/* ==========================================================================
   Osevaro app layer (round 2, mockups/APP-SPEC.md). Load after ds/osevaro.css.
   Under 768px, and whenever Osevaro runs installed, the shop stops being a
   website on a phone: an app bar on top, five docked tabs at the bottom,
   bottom sheets for pickers and forms, rails that swipe and snap, and an
   end cap instead of the big footer.

   Everything for the shell is scoped to html[data-shell="app"] (ds/app.js sets
   it before first paint), so the approved site layouts do not change. The
   install pieces (card, steps sheet, simulations) also work in site mode.
   Motion lives under html.motion-ok and is instant under reduced motion.
   Same tokens, buttons, tags, wash and pets as round 1. No glassy blur.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens and layers (app bar 50, install card 56, tab/action bar 58,
      toasts 90, review controls 1000; sheets, search and sims: top layer)
   -------------------------------------------------------------------------- */
:root {
  --appbar-h: 56px;
  --safe-t: env(safe-area-inset-top, 0px);       /* --safe-b and --safe-x live in osevaro.css */
  --tab-h: 64px;                                  /* docked tab bar content height (bar = 64 + --safe-b) */
  --r-sheet: 24px;
  --sheet-max: 88dvh;
  --t-press: 90ms; --t-tab: 160ms; --t-sheet: 280ms; --t-push: 320ms;
  --ease-out: cubic-bezier(.2, .8, .2, 1);        /* entries */
  --ease-in: cubic-bezier(.4, 0, 1, 1);           /* exits */
  --install-h: 0px;                               /* set by app.js while the install card shows */
  --toast-h: 0px;                                 /* set by app.js while a toast shows (lifts the review chip) */
}
html[data-frame][data-app="standalone"][data-device="iphone"] { --safe-t: 47px; --safe-b: 34px; }   /* simulated status bar + home indicator inside app-preview */
/* a stray ?frame= on a computer screen never stretches the app across 1440px */
html[data-frame] body { max-width: 430px; margin-inline: auto; }
html[data-frame] :is(.tabbar:not(.tabbar--demo), .buybar, .install-card:not(.install-card--demo), .toast-region) { max-width: 430px; margin-inline: auto; }

/* Shell visibility helpers (app fix round): show a thing only in the app, or only on the website.
   [data-when-shell="app|site"] reads like the other data-when-* hooks; [data-app-only] / [data-site-only] are short forms. */
html:not([data-shell="app"]) :is([data-when-shell="app"], [data-app-only]),
html[data-shell="app"] :is([data-when-shell="site"], [data-site-only]) { display: none !important; }

/* --------------------------------------------------------------------------
   2. Which chrome shows where
   -------------------------------------------------------------------------- */
.appbar, .netbar { display: none; }
html[data-shell="app"] .appbar { display: block; }
html[data-shell="app"] :is(.announce, .site-header) { display: none !important; }   /* no marquee, no website header in the app */
html[data-net="offline"] .netbar:not([hidden]), .netbar.netbar--demo { display: flex; }

html[data-shell="app"] {
  scroll-padding-top: calc(var(--appbar-h) + var(--safe-t) + 16px);
  scroll-padding-bottom: calc(var(--tab-h) + var(--safe-b) + 24px + var(--install-h, 0px));
  -webkit-tap-highlight-color: transparent;       /* every app control has its own :active state */
}
html[data-shell="app"][data-app="standalone"] { overscroll-behavior-y: none; }   /* no accidental reloads on Android */
html[data-shell="app"] body { min-height: 100dvh; padding-bottom: calc(var(--tab-h) + var(--safe-b) + 24px + var(--install-h, 0px)); }   /* the end of a page always scrolls clear of the install card */
html[data-shell="app"][data-screen="offline"] body { padding-bottom: calc(24px + var(--safe-b)); }
html[data-shell="app"] :is(a, button, summary, label, [role="button"]) { touch-action: manipulation; }

/* --------------------------------------------------------------------------
   3. Top app bar (section 5): Home shows the logo; other screens a back
      chevron, the title and one or two actions. Sticky, never hides.
   -------------------------------------------------------------------------- */
html[data-shell="app"] .appbar:not(.appbar--demo), .appbar--demo {
  position: sticky; top: 0; z-index: 50;
  padding-top: var(--safe-t);
  background: var(--paper);
  border-bottom: 0;                               /* the hairline is a shadow, so the bar is exactly 56 + safe-t */
}
.appbar.appbar--demo { display: block; position: relative; z-index: 1; padding-top: 0; }
html.motion-ok .appbar { transition: background-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }
.appbar.is-lifted { background: var(--card); box-shadow: 0 1px 0 var(--line); }   /* once the page scrolls */
/* a sticky bar under the app bar (chips, a search field) joins it once stuck: one hairline, under that bar
   (app.js sets html.bar-joined and .is-stuck; .shop-bar-stuck is the shop page's older name for it) */
html[data-shell="app"]:is(.bar-joined, .shop-bar-stuck) .appbar.is-lifted { box-shadow: none; }
/* the start side shrinks to the back arrow, so a screen with two actions (Shop: Search + Filter)
   keeps its title whole at 320-375px; equal sides keep it centred when there is room */
.appbar__row {
  display: grid; grid-template-columns: minmax(44px, 1fr) minmax(0, auto) minmax(92px, 1fr); align-items: center; gap: 8px;
  width: var(--shell); height: var(--appbar-h); margin-inline: auto;
}
.appbar__start, .appbar__end { display: flex; align-items: center; gap: 4px; min-width: 0; }
.appbar__start { margin-left: -10px; }            /* icon glyphs line up with the 16px content edge */
.appbar__end { justify-content: flex-end; margin-right: -10px; }
.appbar .btn-icon { position: relative; border-color: transparent; background: transparent; -webkit-touch-callout: none; }
@media (hover: hover) and (pointer: fine) { .appbar .btn-icon:hover { background: var(--linen); border-color: transparent; } }
.appbar .btn-icon .count { position: absolute; top: 3px; left: 24px; }
.appbar__brand { margin-left: 6px; padding: 4px; gap: 8px; }
.appbar__brand .brand__emblem { width: 32px; height: 32px; }
.appbar__brand .brand__word { width: 92px; height: auto; }
/* a page's own search field and the bar's Search icon are never on screen together (app.js) */
html[data-shell="app"] .appbar.is-search-in-view .appbar__search { opacity: 0; visibility: hidden; }
html.motion-ok[data-shell="app"] .appbar__search { transition: opacity 150ms var(--ease), visibility 150ms, background-color var(--t-fast) var(--ease); }
.appbar__title {
  grid-column: 2; min-width: 0; margin: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: center;
  font-family: var(--font-body); font-size: 17px; font-weight: 650; line-height: 1.25; color: var(--ink);
  -webkit-user-select: none; user-select: none;
  opacity: 0;
}
html.motion-ok .appbar__title { transition: opacity 150ms var(--ease); }
.appbar.has-title .appbar__title, .appbar--demo .appbar__title { opacity: 1; }
/* Shop list: the title is a button that opens the Categories sheet */
.appbar__titlebtn {
  grid-column: 2; display: inline-flex; align-items: center; justify-content: center; gap: 4px; min-width: 0; max-width: 100%;
  min-height: 44px; padding: 0 10px 0 12px; border: 0; border-radius: 12px; background: none; color: var(--ink);
  font-family: var(--font-body); font-size: 17px; font-weight: 650; line-height: 1.2;
}
.appbar__titlebtn > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.appbar__titlebtn .ic { --ic-size: 18px; color: var(--ink-soft); }
@media (hover: hover) and (pointer: fine) { .appbar__titlebtn:hover { background: var(--linen); } }
/* Product: transparent over the gallery with solid round buttons (no text on the
   photo); the normal paper bar once 70% of the gallery has scrolled away */
html[data-shell="app"] .appbar--overlay { margin-bottom: calc(-1 * (var(--appbar-h) + var(--safe-t))); }
:is(html[data-shell="app"] .appbar--overlay, .appbar--overlay.appbar--demo):not(.is-solid) { background: transparent; box-shadow: none; }
:is(html[data-shell="app"] .appbar--overlay, .appbar--overlay.appbar--demo):not(.is-solid) .btn-icon { background: var(--card); box-shadow: var(--shadow); }
:is(html[data-shell="app"] .appbar--overlay, .appbar--overlay.appbar--demo):not(.is-solid) .appbar__title { opacity: 0; }
.appbar--overlay.is-solid { background: var(--card); box-shadow: 0 1px 0 var(--line); }

/* Offline banner: a linen row under the app bar */
.netbar {
  align-items: center; gap: 10px; min-height: 44px; padding: 8px max(var(--gutter), var(--safe-x));
  background: var(--linen); color: var(--ink); font-size: 15px; font-weight: 600; line-height: 1.35;
}
.netbar .ic { --ic-size: 20px; color: var(--ink-soft); }
html[data-shell="app"] .netbar:not(.netbar--demo) { position: sticky; top: calc(var(--appbar-h) + var(--safe-t)); z-index: 49; }

/* --------------------------------------------------------------------------
   4. Bottom tab bar, docked (section 6). Five tabs, always the same.
      Item parts (.tab__icon pill, .tab__label, short labels) are in osevaro.css.
   -------------------------------------------------------------------------- */
html[data-shell="app"] .tabbar:not(.tabbar--demo), .tabbar--demo {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); grid-auto-flow: row; gap: 0;
  width: auto; height: calc(var(--tab-h) + var(--safe-b)); margin: 0;
  padding: 4px max(4px, var(--safe-x)) var(--safe-b);
  background: var(--card); border: 0; border-top: 1px solid var(--line); border-radius: 0; box-shadow: none;
}
html[data-shell="app"] .tabbar:not(.tabbar--demo) { position: fixed; z-index: 58; left: 0; right: 0; bottom: 0; }
.tabbar.tabbar--demo { position: relative; inset: auto; z-index: auto; transform: none; visibility: visible; }
:is(html[data-shell="app"] .tabbar, .tabbar--demo) .tab {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  min-width: 0; min-height: 56px; padding: 0 3px; border: 0; border-radius: 12px; background: none;
  color: var(--ink-soft); text-decoration: none;
  font-size: 13px; font-weight: 600; line-height: 1.15; letter-spacing: 0;
  -webkit-user-select: none; user-select: none;
}
:is(html[data-shell="app"] .tabbar, .tabbar--demo) .tab:is([aria-current="page"], .is-current) { color: var(--ink); background: none; font-weight: 700; }
:is(html[data-shell="app"] .tabbar, .tabbar--demo) .tab .ic { -webkit-touch-callout: none; }
html.motion-ok .tab__icon .ic { transition: transform 120ms var(--ease); }
html.motion-ok .tab__icon.is-nudge .ic { transform: translateY(-2px); }
html.motion-ok[data-shell="app"] .tab:active .tab__icon { background: var(--linen); }
html.motion-ok[data-shell="app"] .tab[aria-current="page"]:active .tab__icon { background: var(--tab-active-bg); }
/* gives way to a product or basket action bar, and to the keyboard */
html.motion-ok[data-shell="app"] .tabbar:not(.tabbar--demo) { transition: transform var(--t) var(--ease), visibility var(--t); }
html[data-shell="app"] body:is(.buybar-on, .kb-open) .tabbar:not(.tabbar--demo) { transform: translateY(100%); visibility: hidden; }

/* Action bar (product: Notify me / Add to basket; basket: Checkout), docked in the tab bar's place */
html[data-shell="app"] .buybar {
  display: flex; position: fixed; z-index: 58; left: 0; right: 0; bottom: 0;
  width: auto; height: calc(var(--tab-h) + var(--safe-b)); margin: 0;
  padding: 7px max(16px, var(--safe-x)) calc(7px + var(--safe-b));
  background: var(--card); border: 0; border-top: 1px solid var(--line); border-radius: 0; box-shadow: none;
  transform: translateY(100%); visibility: hidden;
}
html.motion-ok[data-shell="app"] .buybar { transition: transform var(--t) var(--ease), visibility var(--t); }
html[data-shell="app"] body.buybar-on .buybar { transform: none; visibility: visible; }
html[data-shell="app"] body.kb-open .buybar { transform: translateY(100%); visibility: hidden; }
.buybar__label { font-size: 13px; font-weight: 600; color: var(--ink-soft); line-height: 1.2; }

/* toasts and the review chip sit above whichever bottom bar shows */
html[data-shell="app"] .toast-region { bottom: calc(var(--tab-h) + var(--safe-b) + 12px); }
html[data-shell="app"][data-screen="offline"] .toast-region { bottom: calc(16px + var(--safe-b)); }
html.motion-ok[data-shell="app"] .toast { animation: ov-toast-rise 180ms var(--ease-out) both; }
@keyframes ov-toast-rise { from { opacity: 0; transform: translateY(8px); } }
html[data-shell="app"] .mock { bottom: calc(var(--tab-h) + var(--safe-b) + 12px + var(--install-h, 0px) + var(--toast-h, 0px)); left: 8px; }   /* lifts over a toast, so Undo stays tappable */
@media (max-width: 899.98px) {
  html[data-shell="site"] .mock { bottom: calc(var(--tabbar-h) + 22px + var(--safe-b) + var(--install-h, 0px) + var(--toast-h, 0px)); }
}

/* --------------------------------------------------------------------------
   5. Bottom sheets in the app (section 8; behaviour in osevaro.js)
   -------------------------------------------------------------------------- */
html[data-shell="app"] .sheet {
  --sheet-out: 100%;
  width: min(100%, 640px); max-width: 640px; max-height: var(--sheet-max);
  border-radius: var(--r-sheet) var(--r-sheet) 0 0;
}
/* The keyboard on iPhone: Safari does not resize the page, so a sheet with a field would sit
   behind the keyboard. While a sheet is open osevaro.js sets --kb (the keyboard's height) and
   --vvh (the visible height) from visualViewport on the dialog, so the sheet rides above the
   keyboard like a native one. Both are 0 / unset on Android, where the page itself resizes. */
html[data-shell="app"] dialog.sheet { bottom: var(--kb, 0px); max-height: min(var(--sheet-max), calc(var(--vvh, 100dvh) - 12px)); }
html.motion-ok[data-shell="app"] .sheet[open]:not(.is-settled):not(.is-closing) { animation: ov-sheet-up var(--t-sheet) var(--ease-out) both; }
html.motion-ok[data-shell="app"] .sheet[open]:not(.is-settled):not(.is-closing)::backdrop { animation: ov-fade-in var(--t-sheet) linear both; }
@keyframes ov-sheet-up { from { transform: translateY(100%); } }
@keyframes ov-fade-in { from { opacity: 0; } }
.sheet__head .h3 { font-size: 18px; }
:is(.sheet, .search-sheet, .sim) [tabindex="-1"]:focus { outline: none; }   /* the title takes focus on open; it is not a control */
.sheet__foot--sticky { padding: 12px 20px calc(16px + var(--safe-b)); color: var(--ink-soft); }
.sheet__group { margin: 4px 0 8px; color: var(--ink-soft); }
.sheet__group ~ .sheet__group { margin-top: 20px; }
.sheet--list .sheet__body { padding-bottom: calc(20px + var(--safe-b)); }

/* Category rows (Categories sheet): wash thumb, name, count, chevron; tick when current */
.crows { display: grid; gap: 2px; margin: 0 -8px; }
.crow {
  display: grid; grid-template-columns: 40px minmax(0, 1fr) auto 22px; align-items: center; gap: 12px;
  min-height: 56px; padding: 8px; border-radius: 14px; color: var(--ink); text-decoration: none;
}
@media (hover: hover) and (pointer: fine) { .crow:hover { background: var(--linen); } }
.crow__thumb { position: relative; width: 40px; height: 40px; }
.crow__thumb .wash { position: absolute; inset: 0; width: 100%; height: 100%; }
.crow__thumb .ic { position: absolute; inset: 0; margin: auto; --ic-size: 18px; color: #173a3a; }
.crow__name { font-size: 16px; font-weight: 650; line-height: 1.3; }
.crow__count { font-size: 15px; color: var(--ink-soft); font-variant-numeric: lining-nums tabular-nums; }
.crow__go { --ic-size: 20px; color: var(--ink-soft); }
.crow__tick { --ic-size: 20px; color: var(--ink); }
.crow[aria-current="page"] .crow__name { font-weight: 750; }
/* Single-choice list sheets (Sort): <button class="crow crow--choice" type="button" aria-pressed="true|false">
   <span class="crow__name">..</span><span class="ic ic--check crow__tick" aria-hidden="true"></span></button> */
button.crow { width: 100%; margin: 0; border: 0; background: none; font: inherit; text-align: left; cursor: pointer; }
.crow--choice { grid-template-columns: minmax(0, 1fr) 22px; }
.crow--choice .crow__tick { visibility: hidden; }
.crow--choice:is([aria-pressed="true"], [aria-checked="true"], [aria-current]) .crow__tick { visibility: visible; }
.crow--choice:is([aria-pressed="true"], [aria-checked="true"], [aria-current]) .crow__name { font-weight: 750; }

/* Filters sheet (#filters): fieldsets of chips/checks, Clear all + Show N in the foot.
   Moved here from components.html (the shop uses it too). */
.filterset { display: grid; gap: 12px; min-width: 0; margin: 0; padding: 0; border: 0; }
.filterset__legend { margin-bottom: 12px; padding: 0; color: var(--ink-soft); }
.filters__foot { display: flex; align-items: center; gap: 10px; }
.filters__foot .btn--primary { flex: 1; }

/* Quick add: the product, its price and named colours; coral add in the foot */
.qa-item { display: flex; align-items: center; gap: 14px; margin-bottom: 18px; }
.qa-item__img { flex: none; width: 64px; height: 64px; overflow: hidden; border-radius: 14px; background: var(--well); }
.qa-item__img img { width: 100%; height: 100%; object-fit: cover; mix-blend-mode: multiply; }
.qa-item__name { font-size: 16px; font-weight: 650; line-height: 1.35; }
.qa-item__price { font-family: var(--font-display); font-weight: 600; font-variation-settings: 'SOFT' 50; font-size: 20px; line-height: 1.2; font-variant-numeric: lining-nums tabular-nums; }

/* Notify sheet: the round-1 consent block, with its submit in the foot */
.notify--sheet { gap: 0; }
.notify--sheet .notify__form { gap: 0; padding: 0; border: 0; border-radius: 0; background: none; }

/* --------------------------------------------------------------------------
   6. Search overlay (section 9.2): full screen, paper, its own top row
   -------------------------------------------------------------------------- */
.search-sheet {
  position: fixed; inset: 0; width: 100%; max-width: none; height: 100dvh; max-height: none; margin: 0; padding: 0;
  border: 0; background: var(--paper); color: var(--ink);
  overflow: auto; overscroll-behavior: contain;
}
.search-sheet::backdrop { background: var(--paper); }
html.motion-ok .search-sheet[open]:not(.is-settled):not(.is-closing) { animation: ov-search-in 200ms var(--ease-out) both; }
html.motion-ok .search-sheet[open].is-closing { animation: ov-fade-out 160ms linear forwards; }
@keyframes ov-search-in { from { opacity: 0; transform: translateY(12px); } }
.search-sheet__top {
  position: sticky; top: 0; z-index: 1;
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 8px 6px;
  width: var(--shell); margin-inline: auto; padding: calc(4px + var(--safe-t)) 0 10px;
  background: var(--paper);
}
.search-sheet__top::before { content: ""; position: absolute; inset: 0 calc(-1 * var(--gutter)); z-index: -1; background: var(--paper); border-bottom: 1px solid var(--line); }
.search-sheet__field { position: relative; display: flex; align-items: center; min-width: 0; }
.search-sheet__field > .ic { position: absolute; left: 14px; --ic-size: 20px; color: var(--ink-soft); pointer-events: none; }
.search-sheet__input {
  width: 100%; height: 48px; padding: 0 46px 0 44px;
  border: 1.5px solid var(--field-border); border-radius: 12px; background: var(--card); color: var(--ink);
  font-size: 16px;                                 /* 16px or more: iOS never zooms on focus */
  -webkit-appearance: none; appearance: none;
}
.search-sheet__input::-webkit-search-cancel-button { -webkit-appearance: none; }
.search-sheet__input::placeholder { color: var(--ink-soft); opacity: 1; }
.search-sheet__input:focus-visible { border-color: var(--ink); }
/* in the app a tapped field gets a plain 2px ink edge, not the 3px outer ring */
html[data-shell="app"] .search-sheet__input:focus { outline: none; border-width: 2px; border-color: var(--ink); padding-left: 43.5px; }
.search-sheet__clear { position: absolute; right: 2px; display: grid; place-items: center; width: 44px; height: 44px; border: 0; border-radius: 10px; background: none; color: var(--ink-soft); }
@media (hover: hover) and (pointer: fine) { .search-sheet__clear:hover { background: var(--linen); color: var(--ink); } }
.search-sheet__cancel { min-height: 44px; padding-inline: 10px; margin-right: -10px; text-decoration: none; }
/* The explicit submit sits in the field itself (no extra row pushing the results down): a 36px ink
   disc with an arrow, in a 44px hit area at the field's right end, shown while there is text. Clear
   moves left of it. Cancel stays where it is. */
.search-sheet__go {
  position: absolute; right: 2px; display: grid; place-items: center; width: 44px; height: 44px; padding: 0;
  border: 0; border-radius: 50%; background: none; color: var(--btn-primary-fg); cursor: pointer;
}
.search-sheet__go::before { content: ""; position: absolute; inset: 4px; border-radius: 50%; background: var(--btn-primary-bg); }
.search-sheet__go .ic { position: relative; --ic-size: 20px; }
.search-sheet__field.has-q .search-sheet__input { padding-right: 90px; }
.search-sheet__field.has-q .search-sheet__clear { right: 44px; }
.search-sheet__body { width: var(--shell); margin-inline: auto; padding: 16px 0 calc(40px + var(--safe-b)); }
.ssec + .ssec { margin-top: 28px; }
.ssec__title { margin: 0 0 10px; color: var(--ink-soft); }
.ssec__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 6px; }
.ssec__head .ssec__title { margin: 0; }
.ssec .chips .chip .ic { color: var(--ink-soft); }
.srows { display: grid; gap: 0; background: var(--card); border: 1px solid var(--line); border-radius: 20px; overflow: hidden; }
.srows > li { position: relative; }
.srows > li + li::before { content: ""; position: absolute; top: 0; left: 76px; right: 0; height: 1px; background: var(--line); }
.srow {
  display: grid; grid-template-columns: 48px minmax(0, 1fr) 20px; align-items: center; gap: 14px;
  min-height: 64px; padding: 8px 14px; color: var(--ink); text-decoration: none;
}
@media (hover: hover) and (pointer: fine) { .srow:hover { background: var(--linen); } }
.srow__img { display: grid; place-items: center; width: 48px; height: 48px; overflow: hidden; border-radius: 12px; background: var(--well); color: #173a3a; }
.srow__img img { width: 100%; height: 100%; object-fit: cover; mix-blend-mode: multiply; }
.srow__name { display: block; font-size: 16px; font-weight: 550; line-height: 1.3; }
.srow__name b { font-weight: 800; }
.srow__meta { display: block; margin-top: 2px; font-size: 15px; color: var(--ink-soft); line-height: 1.3; }
.srow__go { --ic-size: 20px; color: var(--ink-soft); }
.srow--all .srow__name { font-weight: 650; }
.srow--all .srow__img { background: var(--linen); color: var(--ink); }
.snone {
  margin-top: 72px; padding: 22px 20px; border: 1px solid var(--line); border-radius: 20px; background: var(--card);
  display: grid; gap: 8px; justify-items: start;
}
.snone p { color: var(--ink-soft); max-width: 34ch; }
.snone a { font-weight: 650; }

/* A search field-button that keeps the query visible on results (Baymard) */
.qbtn {
  display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px; padding: 0 14px;
  border: 1.5px solid var(--field-border); border-radius: 12px; background: var(--card); color: var(--ink);
  font-size: 16px; text-align: left;
}
.qbtn .ic { --ic-size: 20px; color: var(--ink-soft); }
.qbtn__q { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qbtn__q:empty::before { content: "Search the shop"; color: var(--ink-soft); }

/* --------------------------------------------------------------------------
   7. Rails (section 9.1): swipe sideways, snap, bleed to the screen edges.
      The document never scrolls sideways; only rails do.
   -------------------------------------------------------------------------- */
.rail {
  --rail-g: max(var(--gutter), var(--safe-x));
  position: relative;                              /* clips its own absolute children (sr-only counts) */
  display: grid; grid-auto-flow: column; gap: 12px;
  overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
  scroll-snap-type: x mandatory; scroll-padding-inline: var(--rail-g);
  padding-inline: var(--rail-g); margin-inline: calc(-1 * var(--rail-g));
  list-style: none;
}
.rail::-webkit-scrollbar { display: none; }
.rail > * { scroll-snap-align: start; min-width: 0; }
.rail:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; }
.rail--chips { scroll-snap-type: none; grid-auto-columns: max-content; gap: 8px; padding-block: 6px; }
.rail--products { grid-auto-columns: min(72%, 280px); align-items: stretch; padding-block: 4px 14px; }
.rail--products > li { display: flex; flex-direction: column; }
.rail--products > li > :is(.pcard, .door) { flex: 1; }
.rail--cats { grid-auto-columns: 132px; padding-block: 4px 10px; }
html.motion-ok .rail { scroll-behavior: smooth; }
/* sticky chips under the app bar (Shop list). app.js adds .is-stuck once it sits under the bar
   and html.bar-joined, which drops the app bar's own hairline so the two read as one bar. */
html[data-shell="app"] .rail--sticky { position: sticky; top: calc(var(--appbar-h) + var(--safe-t)); z-index: 40; background: var(--paper); }
html[data-shell="app"] .rail--sticky.is-stuck { background: var(--card); box-shadow: 0 1px 0 var(--line); }

/* A website grid that becomes a rail in the app, no page CSS needed:
   <ul class="grid grid--products rail-app">..</ul> (products: 72% / 280px columns, the next card peeks) */
html[data-shell="app"] .rail-app {
  --rail-g: max(var(--gutter), var(--safe-x));
  display: grid; grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: min(72%, 280px); gap: 12px;
  overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none;
  scroll-snap-type: x mandatory; scroll-padding-inline: var(--rail-g);
  padding: 4px var(--rail-g) 14px; margin-inline: calc(-1 * var(--rail-g)); list-style: none;
}
html[data-shell="app"] .rail-app::-webkit-scrollbar { display: none; }
html[data-shell="app"] .rail-app > * { scroll-snap-align: start; min-width: 0; }
html[data-shell="app"] .rail-app > li { display: flex; flex-direction: column; }
html[data-shell="app"] .rail-app > li > :is(.pcard, .door, .skel-card) { flex: 1; }
html.motion-ok[data-shell="app"] .rail-app { scroll-behavior: smooth; }
/* the door tile's resting pet shows inside app rails too (the site hides it under 1180px) */
html[data-shell="app"] :is(.rail, .rail-app) .door__pet { display: block; z-index: 0; right: 14px; bottom: 20px; width: 56%; }

/* Compact category tile (Home rail): paper ground, blob + pet, name below. 132 x 156 */
.ctile--mini { width: 132px; padding: 6px 6px 8px; border-radius: 18px; }
.ctile--mini .ctile__art { aspect-ratio: auto; height: 104px; border-radius: 13px; }
.ctile--mini .ctile__name { display: block; padding: 8px 2px 0; font-size: 17px; line-height: 1.2; text-align: center; }
.ctile--mini.ctile--all { appearance: none; border: 1px solid var(--line); font: inherit; cursor: pointer; text-align: center; }
.ctile__allart { display: grid; place-items: center; height: 104px; border-radius: 13px; background: var(--linen); }
.ctile__allart .ic { --ic-size: 28px; color: var(--ink); }

/* Compact product card in the app (section 10.3): the whole card opens the
   product, title clamped to two lines, price in Fraunces 18, no "View details";
   with ordering open a 44px "+" quick add. */
.pcard__add { display: none; }
/* App fix round: no card-in-card. The linen image well IS the tile (radius 16, full width) and the
   words sit straight on the paper below it, as in native shopping apps. */
html[data-shell="app"] .pcard { padding: 0; background: none; border: 0; border-radius: 16px; box-shadow: none; }
html[data-shell="app"] .pcard__media { border-radius: 16px; }
html[data-shell="app"] .pcard__body { gap: 4px; padding: 10px 2px 0; }
/* the heart: a 36px solid disc drawn inside its 44px hit area, 6px from the photo's corner */
html[data-shell="app"] .pcard__heart { top: 2px; right: 2px; border: 0; background: transparent; box-shadow: none; }
html[data-shell="app"] .pcard__heart::before {
  content: ""; grid-area: 1 / 1; width: 36px; height: 36px; border-radius: 50%;
  background: var(--card); box-shadow: 0 1px 3px rgba(23, 58, 58, .16);
}
html[data-shell="app"] .pcard__heart > .ic { --ic-size: 20px; }
html[data-shell="app"] .pcard__heart[aria-pressed="true"]::before { box-shadow: inset 0 0 0 1.5px var(--coral-text), 0 1px 3px rgba(23, 58, 58, .16); }
html[data-shell="app"] :is(.pcard__eyebrow, .pcard__fit, .pcard__meta, .pcard__actions) { display: none; }
html[data-shell="app"] .pcard__title {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
  font-size: 15px; font-weight: 650; line-height: 1.35;
}
html[data-shell="app"] .pcard__title a::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
html[data-shell="app"] .pcard__title a:focus-visible { outline: none; }
html[data-shell="app"] .pcard:has(.pcard__title a:focus-visible) { outline: 3px solid var(--focus); outline-offset: 2px; }
html[data-shell="app"] :is(.pcard__heart, .pcard__add, .pcard__tag) { z-index: 2; }
html[data-shell="app"] .pcard__row { align-items: center; margin-top: auto; padding-top: 2px; }
html[data-shell="app"] .pcard__price { font-size: 18px; }
html[data-shell="app"][data-order="open"] .pcard__add { display: inline-grid; position: relative; margin: -6px -2px -6px 0; }
@media (hover: hover) and (pointer: fine) { html[data-shell="app"] .pcard:hover { transform: none; } }

/* --------------------------------------------------------------------------
   8. List rows, segmented control, switch (Account, Search, Help)
   -------------------------------------------------------------------------- */
.lgroup-title { margin: 28px 4px 8px; color: var(--ink-soft); }
.lgroup { margin: 0; padding: 0; list-style: none; overflow: hidden; background: var(--card); border: 1px solid var(--line); border-radius: 20px; }
.lgroup > li { position: relative; }
.lgroup > li + li::before { content: ""; position: absolute; z-index: 1; top: 0; left: 52px; right: 0; height: 1px; background: var(--line); }   /* hairlines inset 52px */
.lrow {
  display: grid; grid-template-columns: 22px minmax(0, 1fr) auto 20px; align-items: center; gap: 14px;
  width: 100%; min-height: 56px; padding: 8px 16px; margin: 0;
  border: 0; background: none; color: var(--ink); text-align: left; text-decoration: none; font: inherit;
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) { .lrow:hover { background: var(--linen); } }
.lrow > .ic:first-child { --ic-size: 22px; color: var(--accent-text); }
.lrow > .appicon:first-child { margin: -5px; }
.lrow__label { font-size: 16px; font-weight: 600; line-height: 1.35; }
.lrow__meta { font-size: 15px; color: var(--ink-soft); line-height: 1.35; text-align: right; }
.lrow__sub { display: block; margin-top: 1px; font-size: 15px; font-weight: 400; color: var(--ink-soft); }   /* a second line under the label (long meta on narrow phones) */
.lrow__meta:empty { display: none; }
.lrow__go { --ic-size: 20px; color: var(--ink-soft); grid-column: 4; }
.lrow.is-static, .lrow:disabled { cursor: default; background: none; }
.lrow.is-static .lrow__go, .lrow:disabled .lrow__go { visibility: hidden; }
.lrow:disabled { color: var(--ink); opacity: 1; }
.lrow--control { grid-template-columns: 22px minmax(0, 1fr); cursor: default; padding-block: 12px; }
@media (hover: hover) and (pointer: fine) { .lrow--control:hover { background: none; } }
.lrow--control > .seg, .lrow--control > .lrow__note { grid-column: 1 / -1; }
.lrow__note { font-size: 15px; color: var(--ink-soft); }
.lrow .tbc__mark { margin-left: 0; }

/* Segmented control (a radio group, 44px options) */
.seg { display: flex; gap: 2px; padding: 2px; margin: 0; border: 1.5px solid var(--field-border); border-radius: 13px; background: var(--card); min-width: 0; }
.seg__opt { position: relative; display: flex; flex: 1 1 auto; min-width: 0; }
.seg__opt input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.seg__opt span {
  display: grid; place-items: center; flex: 1; min-height: 44px; padding: 0 8px; border-radius: 10px;
  font-size: 15px; font-weight: 650; line-height: 1.2; color: var(--ink); text-align: center; white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) { .seg__opt:hover span { background: var(--linen); } }
.seg__opt input:checked + span { background: var(--btn-primary-bg); color: var(--btn-primary-fg); }
.seg__opt input:focus-visible + span { outline: 3px solid var(--focus); outline-offset: 2px; }
html.motion-ok .seg__opt span { transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }

/* iOS quick switch: <input type="checkbox" switch> keeps the native control (and its
   haptic tick) on iPhone; elsewhere it is drawn to match. */
.switch { width: 51px; height: 31px; margin: 0; flex: none; accent-color: var(--accent-text); cursor: pointer; }
@supports not (-webkit-touch-callout: none) {
  .switch { -webkit-appearance: none; appearance: none; position: relative; border-radius: 999px; background: var(--field-border); }
  .switch::before { content: ""; position: absolute; top: 2px; left: 2px; width: 27px; height: 27px; border-radius: 50%; background: #ffffff; box-shadow: 0 1px 3px rgba(0, 0, 0, .3); }
  .switch:checked { background: var(--accent-text); }
  .switch:checked::before { transform: translateX(20px); }
  html.motion-ok .switch::before { transition: transform var(--t-fast) var(--ease); }
}

/* Home notice row (closed only): replaces the marquee in the app */
.note--row {
  width: 100%; min-height: 52px; align-items: center; margin: 0;
  border: 0; text-align: left; font: inherit; font-size: 15px; line-height: 1.4; cursor: pointer;
}
.note--row > .ic { margin-top: 0; }
.note--row > .ic:last-child { margin-left: auto; color: var(--ink-soft); }
@media (hover: hover) and (pointer: fine) { .note--row:hover { background: var(--line); } }

/* --------------------------------------------------------------------------
   9. Skeletons (section 11.3): only while something really loads. Same box as
      the real thing; shimmer only under motion-ok, static otherwise.
   -------------------------------------------------------------------------- */
html:not([data-load="skeleton"]) [data-when-load="skeleton"],
html[data-load="skeleton"] [data-when-load="ready"] { display: none !important; }
.skel { display: block; background: var(--linen); border-radius: 8px; }
.skel--img { aspect-ratio: 1; border-radius: 15px; }
.skel--line { height: 14px; border-radius: 7px; }
.skel--title { height: 18px; border-radius: 9px; }
.skel--price { width: 38%; height: 20px; border-radius: 10px; }
.skel--thumb { width: 48px; height: 48px; border-radius: 12px; flex: none; }
.skel-card { display: flex; flex-direction: column; gap: 10px; padding: 6px 6px 12px; border: 1px solid var(--line); border-radius: 20px; background: var(--card); }
html[data-shell="app"] .skel-card { padding: 0 0 4px; border: 0; background: none; }   /* the same shape as the app's card */
html[data-shell="app"] .skel-card .skel--img { border-radius: 16px; }
.skel-row { display: flex; align-items: center; gap: 14px; min-height: 64px; padding: 8px 14px; }
.skel-row > div { display: grid; gap: 8px; flex: 1; }
.skel-stack { display: grid; gap: 8px; padding-inline: 4px; }
html.motion-ok[data-load="skeleton"]:not(.is-automated) .skel {
  background: linear-gradient(100deg, var(--linen) 30%, var(--card) 50%, var(--linen) 70%) 0 0 / 300% 100%;
  animation: ov-shimmer 1.4s linear infinite;
}
@keyframes ov-shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }

/* --------------------------------------------------------------------------
   10. Install card (section 13.1): offered after real interest, never on load
       in the shop, never with a toast or a sheet, and it remembers "Not now".
   -------------------------------------------------------------------------- */
.appicon {
  --appicon: 56px;
  display: inline-grid; place-items: center; flex: none; overflow: hidden;
  width: var(--appicon); height: var(--appicon); border-radius: 22%;
  background: #fbf8f2; border: 1px solid var(--line);      /* stays paper in dark mode: as on the home screen */
}
.appicon img { width: 86%; height: 86%; object-fit: contain; }
.appicon--32 { --appicon: 32px; }
.appicon--40 { --appicon: 40px; }
.appicon--48 { --appicon: 48px; }
.appicon--56 { --appicon: 56px; }
.appicon--android { border-radius: 24%; }
/* App fix round: one compact row (about 72-76px), as app etiquette asks: icon 40, title + one
   line, a small ink Install ("How to" on iPhone) and a 44px close (= "Not now", snoozes 14 days).
   It never shares the screen with a sheet, a toast or a product/checkout action bar. */
.install-card {
  position: fixed; z-index: 56; left: 0; right: 0; margin-inline: auto;
  bottom: calc(var(--tab-h) + var(--safe-b) + 8px);
  width: calc(100% - 16px - 2 * var(--safe-x)); max-width: 560px;
  display: flex; align-items: center; gap: 10px;
  min-height: 72px; padding: 8px 2px 8px 10px; background: var(--card); color: var(--ink);
  border: 1px solid var(--line); border-radius: 20px; box-shadow: var(--shadow-lift);
  container: installcard / inline-size;
  touch-action: none;                              /* a downward swipe dismisses it */
}
.install-card[hidden] { display: none; }
.install-card__text { flex: 1; min-width: 0; }
.install-card__title { font-family: var(--font-body); font-size: 16px; font-weight: 700; line-height: 1.3; letter-spacing: 0; }
.install-card__line { margin-top: 1px; font-size: 15px; line-height: 1.3; color: var(--ink-soft); }
.install-card__short { display: none; }
@container installcard (max-width: 359.98px) {   /* 320px phones: the same promise in fewer words */
  .install-card__long { display: none; }
  .install-card__short { display: inline; }
}
.install-card__actions { display: flex; align-items: center; gap: 0; flex: none; }
.install-card__actions .btn { touch-action: manipulation; }
.install-card__go { padding-inline: 12px; }
.install-card__x { color: var(--ink-soft); }
.install-card__x .ic { --ic-size: 20px; }
.install-card.is-dragging { transition: none; }
html.motion-ok .install-card.is-in { animation: ov-card-up 240ms var(--ease-out) both; }
html.motion-ok .install-card.is-out { animation: ov-card-down 200ms var(--ease-in) forwards; }
@keyframes ov-card-up { from { transform: translateY(calc(100% + 24px)); opacity: 0; } }
@keyframes ov-card-down { to { transform: translateY(calc(100% + 24px)); opacity: 0; } }
body:is(.kb-open, .buybar-on) .install-card:not(.install-card--demo) { display: none; }   /* never with the keyboard or an action bar */
/* site mode: above the floating tab bar (768-899); bottom right on a computer screen */
html[data-shell="site"] .install-card { bottom: calc(20px + var(--safe-b)); }
@media (max-width: 899.98px) { html[data-shell="site"] .install-card { bottom: calc(var(--tabbar-h) + 22px + var(--safe-b)); } }
@media (min-width: 900px) { html[data-shell="site"] .install-card { left: auto; right: max(var(--gutter), var(--safe-x)); width: 420px; } }
/* the sheet's static example */
.install-card.install-card--demo, html[data-shell] .install-card.install-card--demo { position: relative; z-index: auto; inset: auto; width: auto; max-width: 440px; margin: 0; box-shadow: var(--shadow); touch-action: auto; }

/* Desktop header button (13.6): only when the browser's prompt is ready */
@media (min-width: 900px) {
  html[data-shell="site"][data-device="desktop"][data-install-state="native-ready"] .action--install { display: inline-flex; }
}
.action--install .ic { --ic-size: 22px; }

/* --------------------------------------------------------------------------
   11. Install steps sheets (13.5 iPhone/iPad, 13.6 browser menu)
   -------------------------------------------------------------------------- */
.isteps__intro { margin-bottom: 18px; color: var(--ink-soft); }
.isteps { display: grid; gap: 22px; margin: 0; padding: 0 0 8px; list-style: none; }
.istep { display: grid; grid-template-columns: 48px minmax(0, 1fr); gap: 14px; align-items: start; }
.istep__n {
  display: grid; place-items: center; width: 48px; height: 48px; border-radius: 50%;
  background: var(--btn-primary-bg); color: var(--btn-primary-fg);
  font-family: var(--font-display); font-weight: 600; font-variation-settings: 'SOFT' 50; font-size: 22px; line-height: 1;
}
.istep__body { min-width: 0; padding-top: 2px; }
.istep__title { font-family: var(--font-body); font-size: 16px; font-weight: 650; line-height: 1.35; }
.istep__line { margin-top: 2px; font-size: 15px; line-height: 1.45; color: var(--ink-soft); }
.istep__tip { margin-top: 6px; font-size: 14px; line-height: 1.45; color: var(--ink-soft); }
.istep__art { display: grid; place-items: center; margin-top: 10px; padding: 8px 6px; border-radius: 16px; background: var(--linen); color: var(--ink); }
.istep0 { display: grid; justify-items: start; gap: 8px; margin-bottom: 22px; padding: 16px; border: 1px solid var(--line); border-radius: 18px; background: var(--linen); }
.istep0 .btn { margin-block: 4px; }
.isteps__foot p { margin-bottom: 12px; font-size: 15px; line-height: 1.45; color: var(--ink-soft); }
.isteps__foot .isteps__favs { color: var(--ink); }

/* iPhone steps (#ios-steps, app fix round): a short coach card instead of an 88% sheet, so
   Safari's own toolbar stays in view while its menus open. The steps sit in a rail you swipe
   (the next one peeks), and a small tail points at where ••• (Safari 26, bottom right) or Share
   (Safari 18, bottom centre) sits. */
.isteps--rail {
  display: grid; grid-auto-flow: column; grid-auto-columns: min(82%, 300px); gap: 10px;
  margin: 0 -20px; padding: 2px 20px 10px; overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory; scroll-padding-inline: 20px; scrollbar-width: none;
}
.isteps--rail::-webkit-scrollbar { display: none; }
.isteps--rail:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; }
.isteps--rail > .istep {
  scroll-snap-align: start; align-content: start;
  grid-template-columns: 36px minmax(0, 1fr); column-gap: 10px; align-items: center;
  padding: 12px; border: 1px solid var(--line); border-radius: 18px; background: var(--card);
}
.isteps--rail .istep__body { display: contents; }
.isteps--rail .istep__n { grid-row: 1; width: 36px; height: 36px; font-size: 18px; }
.isteps--rail .istep__title { grid-column: 2; grid-row: 1; }
.isteps--rail .istep__line { grid-column: 1 / -1; margin-top: 6px; }
.isteps--rail .istep__tip { grid-column: 1 / -1; margin-top: 4px; }
.isteps--rail .istep__art { grid-column: 1 / -1; margin-top: 10px; padding: 2px 6px; }
.isteps--rail .istep__art .ill { max-height: 64px; width: auto; }
.sheet--coach .isteps__intro { margin-bottom: 12px; }
.sheet--coach .sheet__body { padding-top: 14px; }
.sheet--coach .istep0 { margin-bottom: 14px; padding: 14px; gap: 6px; }
.sheet--coach .isteps__foot { padding-top: 10px; }
.sheet--coach .isteps__foot p { margin-bottom: 10px; }
html[data-shell="app"] .sheet.sheet--coach {
  bottom: calc(var(--kb, 0px) + 14px + var(--safe-b)); width: calc(100% - 16px); max-height: calc(100dvh - 48px - var(--safe-b));
  border-bottom: 1px solid var(--line); border-radius: 24px; overflow: visible;
}
html[data-shell="app"] .sheet.sheet--coach[open] { display: flex; flex-direction: column; }
html[data-shell="app"] .sheet--coach > .sheet__head { flex: none; border-radius: 24px 24px 0 0; }
html[data-shell="app"] .sheet--coach > .sheet__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
html[data-shell="app"] .sheet--coach > .sheet__foot { flex: none; position: static; padding-bottom: 16px; border-radius: 0 0 24px 24px; }
.sheet--coach .coach__tail { display: none; }
html[data-shell="app"] .sheet--coach .coach__tail {
  display: block; position: absolute; bottom: -9px; width: 18px; height: 18px; pointer-events: none;
  background: var(--card); border-right: 1px solid var(--line); border-bottom: 1px solid var(--line);
  transform: rotate(45deg);
}
html[data-shell="app"] .sheet--coach[data-point="right"] .coach__tail { right: 22px; }      /* Safari 26: ••• at the bottom right */
html[data-shell="app"] .sheet--coach[data-point="centre"] .coach__tail { left: calc(50% - 9px); }   /* Safari 18: Share in the middle */
html[data-shell="app"] .sheet--coach:not([data-point]) .coach__tail { display: none; }
/* the little drawings: our own line glyphs, a coral ring on the thing to tap */
.ill { display: block; max-width: 100%; height: auto; overflow: visible; }
.ill__fill { fill: var(--card); }
.ill__icon { fill: #fbf8f2; }
.ill__ring { stroke: var(--coral-text); }
.ill__text { font-family: var(--font-body); font-size: 13px; font-weight: 600; fill: currentColor; }
.ill__text--soft { fill: var(--ink-soft); }
.ill__text--bold { font-weight: 750; }

/* --------------------------------------------------------------------------
   12. Browser simulations (13.7). Clearly labelled, neutral greys, system
       type, no Google or Apple marks: nobody should mistake them for the shop.
   -------------------------------------------------------------------------- */
.sim {
  position: fixed; inset: auto 0 0 0; margin: 0 auto; padding: 0;
  width: min(100%, 412px); max-width: 100%; max-height: 94dvh;
  border: 0; background: transparent; overflow: visible;
  font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; color: #1f1f1f;
}
.sim::backdrop { background: rgba(0, 0, 0, .42); }
.sim__label {
  display: table; max-width: calc(100% - 24px); margin: 0 auto 10px; padding: 4px 10px;
  font: 600 13px/1.35 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; letter-spacing: 0;
  color: #1f1f1f; background: #fffef7; border: 1.5px dashed #555; border-radius: 8px;
}
.sim__sheet { position: relative; padding: 24px 22px calc(18px + var(--safe-b)); background: #ffffff; color: #1f1f1f; border-radius: 28px 28px 0 0; }
.sim__grab { position: absolute; top: 9px; left: 50%; width: 32px; height: 4px; margin-left: -16px; border-radius: 2px; background: #79747e; }
.sim__app { display: flex; align-items: center; gap: 14px; }
.sim__app .appicon { border-color: #dadce0; }
.sim__title { margin: 0 0 14px; font-size: 18px; font-weight: 600; line-height: 1.3; }
.sim__name { margin: 0; font-size: 18px; font-weight: 600; line-height: 1.25; }
.sim__host { margin: 0; font-size: 14px; line-height: 1.35; color: #5f6368; }
.sim__desc { margin-top: 14px; font-size: 14px; line-height: 1.5; color: #3c4043; }
.sim__shots { display: flex; gap: 8px; margin: 14px -22px 0; padding: 0 22px 4px; overflow-x: auto; scrollbar-width: none; }
.sim__shots img { flex: none; width: 96px; height: 208px; object-fit: cover; object-position: top; border-radius: 12px; border: 1px solid #dadce0; background: #f1f3f4; }
.sim__actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }
.sim__btn { min-height: 44px; padding: 0 20px; border: 0; border-radius: 999px; background: transparent; color: #1f1f1f; font: 600 15px/1.2 system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; cursor: pointer; }
@media (hover: hover) and (pointer: fine) { .sim__btn:hover { background: #f1f3f4; } }
.sim__btn--fill { background: #1f1f1f; color: #ffffff; }
@media (hover: hover) and (pointer: fine) { .sim__btn--fill:hover { background: #3c4043; } }
.sim__btn:focus-visible { outline: 3px solid #1f1f1f; outline-offset: 2px; }
[data-theme="dark"] .sim__sheet { background: #2d2e30; color: #e8eaed; }
[data-theme="dark"] .sim__host { color: #bdc1c6; }
[data-theme="dark"] .sim__desc { color: #dadce0; }
[data-theme="dark"] .sim__btn { color: #e8eaed; }
@media (hover: hover) and (pointer: fine) { [data-theme="dark"] .sim__btn:hover { background: #3c4043; } }
[data-theme="dark"] .sim__btn--fill { background: #e8eaed; color: #1f1f1f; }
@media (hover: hover) and (pointer: fine) { [data-theme="dark"] .sim__btn--fill:hover { background: #ffffff; } }
[data-theme="dark"] .sim__btn:focus-visible { outline-color: #e8eaed; }
[data-theme="dark"] .sim__grab { background: #9aa0a6; }
html.motion-ok .sim--android[open]:not(.is-settled):not(.is-closing) { animation: ov-sheet-up var(--t-sheet) var(--ease-out) both; }
html.motion-ok .sim[open].is-closing { animation: ov-fade-out 180ms linear forwards; }
.sim--desktop { inset: 88px 24px auto auto; width: 340px; }
.sim--desktop::backdrop { background: rgba(0, 0, 0, .12); }
.sim--desktop .sim__label { margin: 0 0 8px auto; }
.sim--desktop .sim__sheet { padding: 18px 18px 14px; border-radius: 12px; box-shadow: 0 10px 32px rgba(0, 0, 0, .28); }

/* --------------------------------------------------------------------------
   13. Offline screen (section 10.8)
   -------------------------------------------------------------------------- */
.offline {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  min-height: calc(100dvh - var(--appbar-h) - var(--safe-t)); padding: 24px 0 calc(32px + var(--safe-b));
  text-align: center;
}
.offline__pet { position: relative; width: 160px; margin-bottom: 8px; }
.offline__pet img { width: 100%; height: auto; }
.offline__pet .pet__light { display: var(--light-only); }
.offline__pet .pet__dark { display: var(--dark-only); }
.offline__pet .pet__shadow { bottom: 2px; left: 12%; right: 12%; height: 14px; }
.offline p { max-width: 34ch; color: var(--ink-soft); }
.offline__actions { display: grid; gap: 10px; width: min(100%, 320px); margin-top: 10px; }
.offline__note { margin-top: 6px; font-size: 15px; }

/* --------------------------------------------------------------------------
   14. End cap: the app's footer (section 10.10). The same footer, restyled:
       pets facing left on its edge, brand, one sentence, legal links, © line.
   -------------------------------------------------------------------------- */
.footer__legal { display: none; }
html[data-shell="app"] .site-footer { --footer-pet-h: 84px; margin-top: calc(var(--footer-pet-h) + 24px); padding-bottom: 24px; }
html[data-shell="app"] :is(.footer__notify, .footer__groups, .footer__help) { display: none !important; }
html[data-shell="app"] .footer { padding: 28px 20px 18px; border-radius: 24px; }
html[data-shell="app"] .footer__top { grid-template-columns: minmax(0, 1fr); gap: 0; padding-bottom: 6px; border-bottom: 0; }
html[data-shell="app"] .footer__legal { display: flex; flex-wrap: wrap; gap: 0 2px; margin: 4px -10px 2px; }
html[data-shell="app"] .footer__legal a {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 10px; border-radius: 10px;
  color: var(--footer-fg); font-size: 15px; font-weight: 600; text-underline-offset: .2em;
}
@media (hover: hover) and (pointer: fine) { html[data-shell="app"] .footer__legal a:hover { background: rgba(251, 248, 242, .1); } }
html[data-shell="app"] .footer__base { flex-direction: column; gap: 4px; padding-top: 14px; font-size: 14px; }
html[data-shell="app"][data-endcap="off"] .site-footer { display: none; }
html[data-shell="app"][data-endcap="off"] main > .section:last-child { padding-bottom: 24px; }

/* --------------------------------------------------------------------------
   15. Press feedback, "haptic-like" (section 11.1; all under motion-ok)
   -------------------------------------------------------------------------- */
html.motion-ok[data-shell="app"] :is(.lrow, .crow, .srow, .chip, .note--row):active { background: var(--linen); }
html.motion-ok[data-shell="app"] :is(.ctile, .door):active { transform: scale(.97); transition-duration: var(--t-press); }
html.motion-ok[data-shell="app"] .pcard:active:not(:has(.btn-icon:active)) { transform: scale(.97); transition-duration: var(--t-press); }
html.motion-ok[data-shell="app"] .btn-icon:active { transform: scale(.92); transition-duration: var(--t-press); }
html.motion-ok[data-shell="app"] .btn:active { transform: scale(.98); transition-duration: var(--t-press); }
.btn.is-added .ic { --ic-size: 20px; }

/* --------------------------------------------------------------------------
   16. Screen transitions (section 7): cross-document View Transitions where
       supported (Chrome/Edge 126+, Safari 18.2+); plain navigation elsewhere.
       app.js picks push / pop / tab and skips it under reduced motion, in
       automated captures and in site mode.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
html[data-shell="app"] .appbar:not(.appbar--demo) { view-transition-name: ov-appbar; }
html[data-shell="app"] .tabbar:not(.tabbar--demo) { view-transition-name: ov-tabbar; }
::view-transition-group(ov-appbar), ::view-transition-group(ov-tabbar) { animation: none; }   /* chrome stays still */
::view-transition-old(root), ::view-transition-new(root) { animation-duration: var(--t-push); animation-timing-function: var(--ease-out); }
html:active-view-transition-type(push) ::view-transition-new(root) { animation-name: ov-in-from-right; }
html:active-view-transition-type(push) ::view-transition-old(root) { animation-name: ov-out-to-left; }
html:active-view-transition-type(pop) ::view-transition-new(root) { animation-name: ov-in-from-left; }
html:active-view-transition-type(pop) ::view-transition-old(root) { animation-name: ov-out-to-right; }
html:active-view-transition-type(tab) ::view-transition-old(root),
html:active-view-transition-type(tab) ::view-transition-new(root) { animation-duration: var(--t-tab); }   /* plain crossfade */
@keyframes ov-in-from-right { from { transform: translateX(24%); opacity: 0; } }
@keyframes ov-out-to-left { to { transform: translateX(-10%); opacity: 0; } }
@keyframes ov-in-from-left { from { transform: translateX(-10%); opacity: 0; } }
@keyframes ov-out-to-right { to { transform: translateX(24%); opacity: 0; } }

/* --------------------------------------------------------------------------
   17. Reduced motion and automated captures: things simply appear
   -------------------------------------------------------------------------- */
html:not(.motion-ok) :is(.sheet, .search-sheet, .sim, .install-card, .toast),
html:not(.motion-ok) :is(.sheet, .search-sheet, .sim)::backdrop,
html.is-automated :is(.sheet, .search-sheet, .sim, .install-card),
html.is-automated :is(.sheet, .search-sheet, .sim)::backdrop { animation: none !important; }
