/* ============================================================================
   delEat — the Apple-pattern layer
   Added on top of site.css rather than folded into it: this file owns every
   component the Apple product-page audit asked for (local nav, the
   highlights carousel, the plus-card idiom used in chapters/why-delEat, the
   pricing "keep exploring" trio and the restaurant-type trio). The closer-
   look viewer that used to live here was removed from the home page (the
   "One system" bento plus the delEat cloud diagram already cover that
   ground) — its render stays in img/stage for the module pages, which never
   used this CSS. Nothing here invents a colour, a radius or an easing curve —
   every value comes from css/tokens.css, same rule as the rest of the site.
   Springs live in js/apple.js; this file only ever animates transform and
   opacity, so a spring's written value has something compositor-cheap to
   land on.
   ========================================================================= */

/* ============================================================================
   Local nav — the ONLY sticky bar once the hero has scrolled by. The global
   pill (css/site.css `.nav`) gives up `position: sticky` on any page that
   carries this element (see the `body:has(#localnav) .nav` rule below), so
   it scrolls away with the hero instead of stacking a second bar underneath
   it — scroll back to the very top and the pill is there again, in flow.
   This local nav lives in the document flow right after the hero section, so
   `position: sticky; top: 0` alone makes it appear exactly when Apple's
   does: nothing to show while the hero is still on screen, because the local
   nav has not reached its sticky offset yet; pinned flush to the viewport
   top from the moment it does, so there is never a gap where neither bar is
   visible.
   ========================================================================= */
/* `relative`, not `static` -- it still has to keep its own stacking context
   (`.nav`'s z-index only applies to a positioned element) so it paints above
   the hero it visually overlaps, exactly as it did when it was sticky. The
   only thing that changes is that it no longer re-attaches to the viewport
   on scroll, so it leaves with the hero instead of stacking under the local
   nav below. */
body:has(#localnav) .nav { position: relative; z-index: 60; }

.local-nav {
  position: sticky;
  /* Round 53k: the sticky BOX itself starts below the status bar. 53j only
     padded it, which left the box overlapping the bar; filmed 23 Sep 00:10,
     Safari still treated it as a header there and painted a band from html
     (t=14.75, cream over black). In the same clip, at t=8.25, with this bar
     hidden and nothing sticky under the status bar, the status bar was fully
     transparent -- the page ran straight up behind the clock. That is the
     behaviour wanted, and it exists; it needs nothing sticky in the way. */
  top: env(safe-area-inset-top, 0px);
  z-index: 55;
  display: flex; justify-content: center;
  padding: 0 clamp(10px, 2vw, 20px);
  /* Round 53j: the pill clears the status bar. Nothing on the site offset a
     sticky bar by the top safe-area inset, so on a notched iPhone this glass
     pill sat UNDER the status bar -- and Safari samples whatever sits there.
     Filmed 22 Sep 23:55: over black sections the status bar read warm greys
     ((113,110,109), (89,85,80)), which is white-55% glass blurred over black,
     not the black ground. With the pill pushed below the inset the only thing
     under the status bar is the ground layer, so the bar can take the
     section's colour. The wrapper itself stays transparent: the inset strip
     shows the layer through it. Zero on desktop and on phones without a
     notch, so nothing moves there. */
  pointer-events: none;
}
.local-nav-in {
  position: relative;
  pointer-events: auto;
  width: 100%; max-width: var(--page-wide);
  min-height: 52px;
  display: flex; align-items: center; gap: var(--s-5);
  margin-top: 8px;
  padding: 8px var(--s-5);
  border-radius: var(--r-6);
  background: color-mix(in srgb, var(--n-0) 68%, transparent);
  -webkit-backdrop-filter: blur(20px) saturate(1.7);
  backdrop-filter: blur(20px) saturate(1.7);
  border: 1px solid color-mix(in srgb, var(--n-900) 8%, transparent);
  box-shadow: 0 1px 0 color-mix(in srgb, #FFFFFF 60%, transparent) inset,
              0 18px 40px -22px rgba(0,0,0,.34);
  transition: opacity .38s var(--glide), transform .38s var(--glide), filter .38s var(--glide);
}
/* round 30: hidden over the hero only once js/apple.js is tracking it */
.local-nav.is-armed:not(.is-in) .local-nav-in { opacity: 0; filter: blur(6px); transform: translateY(-10px) scale(.98); }
.local-nav.is-in .local-nav-in { opacity: 1; filter: blur(0); transform: none; }
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .local-nav-in { background: var(--n-0); backdrop-filter: none; -webkit-backdrop-filter: none; }
}
@media (prefers-contrast: more) {
  .local-nav-in { border: 2px solid var(--n-900); }
}

.ln-name {
  flex: none; font-family: var(--font-display); font-weight: 800;
  font-size: var(--t-sm); letter-spacing: var(--tr-head); color: var(--ink);
}
/* Round 52: the local nav carried the name as live text at a single weight, so
   it was the one place on the site that did not show the wordmark's 400/900
   split. It is the real outlined mark now. A new class rather than restyling
   .ln-name, because the old text rules are inlined in the critical blocks and
   would otherwise have to be regenerated to agree. The bar is white glass at
   68 percent whatever is behind it, so the ink cut is always the right one. */
.ln-links { flex: 1; display: flex; align-items: center; justify-content: center; gap: clamp(14px, 2.4vw, 30px); }
.ln-links a {
  font-size: var(--t-sm); font-weight: 600;
  /* Round 53m: the pill is white glass whatever the section, so its links
     take the light-ground inks explicitly. var(--ink-2) resolved to the
     NIGHT value (#A1A1A6) over a black section: light grey on white glass,
     2.52:1. n-700 on this glass over black is 6.4:1, over cream 12:1. */
  color: var(--n-700);
  text-decoration: none; white-space: nowrap;
  transition: color var(--d-2) var(--glide);
}
.ln-links a:hover, .ln-links a.is-current { color: var(--n-900); }
.ln-cta { flex: none; }
/* Every other end of this bar is rounded to the pill radius that
   `.local-nav-in` itself uses (--r-6), so a squared-off `.btn-sm` corner
   here was the one straight edge left in the shape. Full pill, sized off
   the bar's own inner height (52px) minus 12px, same size/weight vocabulary
   as the global nav's own CTA pill (`.nav-cta .btn` in css/site.css). */
.ln-cta.btn {
  border-radius: 999px; height: 40px; padding-inline: 18px;
  font-size: var(--t-sm); font-weight: 600;
  box-shadow: none; transform: none;
}
.ln-cta.btn:hover { box-shadow: none; transform: translateY(-1px); }
.ln-cta.btn:active { box-shadow: none; transform: translateY(0); }
.ln-more { display: none; flex: none; align-items: center; gap: 6px; font: inherit; font-size: var(--t-sm); font-weight: 600;
  color: var(--ink); background: transparent; border: 0; padding: 6px; cursor: pointer; transition: transform .1s ease-out; }
.ln-more svg { width: 11px; height: 11px; transition: transform var(--d-2) var(--snap); }
.ln-more[aria-expanded="true"] svg { transform: rotate(180deg); }
.ln-more:active { transform: scale(.94); }
@media (prefers-reduced-motion: reduce) { .ln-more:active { transform: none; } }

.ln-sheet {
  position: absolute; top: 100%; left: 0; right: 0; margin-top: 6px;
  display: grid; gap: 2px; padding: 10px;
  border-radius: var(--r-5);
  background: color-mix(in srgb, var(--n-0) 92%, transparent);
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  border: 1px solid var(--line-soft); box-shadow: var(--lift-3);
}
.ln-sheet a { padding: 11px 12px; border-radius: var(--r-3); font-size: var(--t-sm); font-weight: 600; color: var(--ink-2); text-decoration: none; }
.ln-sheet a:hover, .ln-sheet a:focus-visible { background: var(--surface-2); color: var(--ink); }
.ln-sheet[hidden] { display: none; }
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .ln-sheet { background: var(--n-0); backdrop-filter: none; -webkit-backdrop-filter: none; }
}
@media (prefers-contrast: more) {
  .ln-sheet { border: 2px solid var(--n-900); }
}

@media (max-width: 900px) {
  .ln-links { display: none; }
  .ln-more { display: inline-flex; position: relative; }
  .local-nav-in { gap: var(--s-4); }
}
@media (max-width: 560px) {
  .ln-cta { display: none; }
  .local-nav-in { min-height: 48px; }
}
/* Round 30, item 4: the local nav's phone sheet, open. The bar goes fixed at
   the top of the stacking order (the same 1000 as the global menu; the two
   are never open together), a scrim covers the pinned page and takes the
   tap that closes the sheet, and the sheet is its own scroller, never
   taller than what is on screen. */
@media (max-width: 900px) {
  .local-nav.is-menu { position: fixed; top: 0; left: 0; right: 0; z-index: 1000; pointer-events: auto; }
  /* ::after, not ::before, which is already the bar's drifting glow; z -1
     inside the bar's own stacking context paints it under the bar and over
     the page. */
  .local-nav.is-menu::after {
    content: ""; position: fixed; inset: 0; z-index: -1; pointer-events: auto;
    background: rgba(0,0,0,.32);
  }
  .local-nav.is-menu .local-nav-in { opacity: 1; filter: none; transform: none; }
  .ln-sheet {
    max-height: calc(100vh - 84px); max-height: calc(100dvh - 84px);
    overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
    padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    /* solid: at 92 percent over a pinned page, the headline under it read
       through the links */
    background: #F7F3EE; -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .ln-sheet a { color: #1C1C1E; }
}
.ln-sheet-sep { height: 1px; margin: 6px 8px; background: var(--line-soft); }
.ln-sheet-label {
  padding: 8px 12px 2px; font-family: var(--font-mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: var(--tr-caps); text-transform: uppercase; color: var(--ink-3);
}
@media (prefers-reduced-motion: reduce) {
  .local-nav-in { transition: opacity .2s linear; filter: none; transform: none; }
}

/* ============================================================================
   Home-page section rhythm — 2026-09: this used to redefine --sec-y to a
   MORE generous budget here (clamp(112px, 11vw, 176px), desktop-only),
   on the theory that twenty-plus chapters in a row needed more breathing
   room than the sitewide default. In practice a `.section`'s bottom
   padding and the next `.section`'s top padding both read this variable,
   so the override didn't add ~64px of room, it added ~128px of it TWICE
   per seam — a chapter's plus-bento cards to the next chapter's kicker
   measured 300px+ of bare ground. Removed: the home page now reads the
   exact same --sec-y as every other page (css/tokens.css), no exception. */

/* ============================================================================
   Hero film → trust band seam — `.local-nav` (above) sits in normal flow
   right between the hero and the trust band and is `position: sticky`, so
   even while its own pill is invisible (opacity: 0, pre-scroll) it still
   reserves its own box: 8px margin-top + `.local-nav-in`'s 52px min-height
   + 8px padding, 66px total. Nothing painted that box, so the page's own
   bone ground showed through it as a flat off-white band between the film
   and the charcoal trust band. Pulling `.trust` up by exactly that height
   removes the band without touching `.local-nav` itself — the film still
   ends where it always did, the (still invisible, still inert) pill now
   sits over the trust band's own charcoal instead of over bare ground, and
   once it fades in on scroll it reads exactly as before. Scoped to pages
   that actually carry a local nav, same as the rhythm rule above. Two
   values because `.local-nav-in`'s own min-height steps down from 52px to
   48px at the same 560px breakpoint it already uses (below), which changes
   the box's own measured height from 66px to 59px -- matched here rather
   than guessed, so trust always butts flush with zero overlap either
   side of that breakpoint. */
body:has(#localnav) .trust { margin-top: -66px; }
@media (max-width: 560px) {
  body:has(#localnav) .trust { margin-top: -59px; }
}

/* ============================================================================
   Get the highlights — a horizontal, native-snap carousel of autoplaying
   clips. Point 4: the segmented tab strip that used to sit above the track
   is gone -- cards, captions, arrows and dots only. Pager is a pill-and-dots
   row underneath, same vocabulary as .ps-pager but its own class so the two
   carousels never fight over state.
   ========================================================================= */
.hl-track {
  display: flex; gap: clamp(12px, 1.6vw, 20px); margin-top: var(--s-6);
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
  padding-bottom: 2px; scroll-padding-inline: var(--gutter);
}
.hl-track::-webkit-scrollbar { display: none; }
.hl-track:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

/* "iOS 26" gallery card: the media fills a tall box and the caption reads
   below it in the page's ordinary ink, not overlaid on the image -- a bold
   lead sentence, then a grey line. */
.hl-card {
  flex: 0 0 auto; width: min(320px, 68vw);
  scroll-snap-align: start; display: block; text-decoration: none; color: var(--ink);
  transition: transform var(--d-3) var(--glide);
}
/* the lift itself (box-shadow only) is CSS; the transform on this element
   is js/apple.js's pointer-tracked tilt (motion(), part e) -- an inline
   style always wins the cascade, so a CSS `transform` here would just be
   dead code once the tilt listener attaches. */
@media (hover: hover) and (pointer: fine) { .hl-card:hover .hl-media-box { box-shadow: var(--lift-4); } }
.hl-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--r-6); }
.hl-media-box {
  position: relative; display: block; aspect-ratio: 520 / 620;
  border-radius: var(--r-6); overflow: hidden; isolation: isolate;
  background: var(--n-800); box-shadow: var(--lift-2);
  transition: transform var(--d-3) var(--glide), box-shadow var(--d-3) var(--glide);
}
.hl-media {
  position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; background: var(--n-800);
}
.hl-cap { display: block; margin-top: var(--s-4); }
.hl-cap b { display: block; font-family: var(--font-display); font-weight: 700; font-size: clamp(17px, 1.3vw, 20px); letter-spacing: -.02em; line-height: 1.28; }
.hl-cap span { display: block; margin-top: 4px; font-size: var(--t-sm); line-height: 1.4; color: var(--ink-2); }

.hl-pager { display: flex; align-items: center; justify-content: center; gap: 7px; margin-top: var(--s-5); }
.hl-pager button {
  width: 7px; height: 7px; border-radius: 999px; border: 0; padding: 0;
  background: var(--n-200); cursor: pointer; flex: none;
  transition: width var(--d-2) var(--snap), background var(--d-2) var(--snap);
}
.hl-pager button[aria-current="true"] { width: 22px; background: var(--ink); }
.hl-pager button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (max-width: 700px) {
  .hl-card { width: 84vw; }
  .hl-media-box { aspect-ratio: 4 / 5; }
  .hl-track { margin-top: 14px; }
}

/* ============================================================================
   Mid-shift details — was a fifteen-chip tablist beside one panel that
   rewrote its own title/body/icon on every click, hover and focus (see
   js/site.js history for the removed wiring). All fifteen items are real
   cards now, so this is the same rail as "Get the highlights" above: native
   snap, a hidden scrollbar, the next card peeking, the site's dot pager.
   No filter tabs here -- every item is its own card, there is nothing to
   filter down to. `initRail()` in js/apple.js drives both rails.
   ========================================================================= */
.ms-track {
  display: flex; gap: clamp(12px, 1.6vw, 20px); margin-top: var(--s-6);
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
  padding-bottom: 2px; scroll-padding-inline: var(--gutter);
}
.ms-track::-webkit-scrollbar { display: none; }
.ms-track:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

.ms-card {
  flex: 0 0 auto; width: min(360px, 78vw);
  scroll-snap-align: start;
  padding: var(--s-5); border-radius: var(--r-5);
  background: var(--surface); border: var(--hair);
  transition: transform var(--d-2) var(--snap), box-shadow var(--d-2) var(--snap);
}
@media (hover: hover) and (pointer: fine) { .ms-card:hover { transform: translateY(-3px); box-shadow: var(--lift-3); } }
.ms-card-ic { display: block; width: 120px; height: 120px; margin-bottom: var(--s-4); }
.ms-card h4 { font-size: var(--t-lg); }
.ms-card p {
  margin-top: var(--s-3); font-size: var(--t-sm); color: var(--ink-2); line-height: 1.5;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.ms-card .go { margin-top: var(--s-4); }

.ms-pager { display: flex; align-items: center; justify-content: center; gap: 7px; margin-top: var(--s-5); }
.ms-pager button {
  width: 7px; height: 7px; border-radius: 999px; border: 0; padding: 0;
  background: var(--n-200); cursor: pointer; flex: none;
  transition: width var(--d-2) var(--snap), background var(--d-2) var(--snap);
}
.ms-pager button[aria-current="true"] { width: 22px; background: var(--ink); }
.ms-pager button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (max-width: 700px) {
  .ms-card { width: 84vw; }
  .ms-track { margin-top: 14px; }
}

/* ============================================================================
   Plus-cards -- compact info cards for the till/kitchen/owner-app chapters
   (and m-till.html's mid-shift panel, src/modules.html). Used to be a
   <details>/<summary> accordion hiding a second sentence behind a "+" --
   each card only ever carried a title and one short line, so the plus and
   its hidden panel were the only reason a card grew taller than its own
   content, and then grew again to match the tallest card in its row. Plain,
   non-interactive cards now: everything the card has to say is already on
   it. 2026-09: `align-items: start` here used to let each card size to
   its own content instead of its row's tallest sibling — the stated goal
   was avoiding the old accordion's growth, but on a genuinely flat card
   the effect is the same bug it was trying to avoid: a two-line title
   (e.g. "VAT backed out, not added") makes ONE card taller, `start` lets
   its siblings stay short, and the row reads uneven. `stretch` (the grid
   default) makes every card in a row match the tallest; the title itself
   is reserved two lines below so a one-line title does not shift its own
   description up relative to a two-line sibling's.
   ========================================================================= */
.plus-bento {
  display: grid; grid-template-columns: repeat(4, minmax(0,1fr));
  align-items: stretch; gap: 14px; margin-top: var(--s-6);
}
@media (max-width: 900px) {
  .plus-bento { grid-template-columns: repeat(2, minmax(0,1fr)); }
  /* a bento of three (every chapter's plus-bento on this page) leaves its
     last card alone in the second row at half width -- :last-child +
     :nth-child(odd) only matches when the total count is odd, so a bento
     of two or four (the offline-tiles idiom, six of them) is untouched. */
  .plus-bento .plus-card:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (max-width: 700px) {
  .plus-bento { margin-top: var(--s-5); grid-template-columns: repeat(2, minmax(0,1fr)); gap: 12px; }
  .plus-card .pc-t b { font-size: 17px; }
  .plus-card .pc-t small { font-size: 15px; }
}
.plus-card {
  /* local token reset: a card is always a white island, even inside an
     `.on-dark` chapter (the owner app) -- resetting `--ink`/`--ink-2`/
     `--surface-2` here means every descendant that reads them (the title,
     the line, the icon plate) resolves to the light-mode values on its own,
     with no on-dark override needed anywhere else. */
  --surface-2: var(--n-50); --ink: var(--n-900); --ink-2: var(--n-600);
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-2);
  background: var(--n-0); border-radius: 20px; padding: 20px;
}
/* Point 1: the drawn Picco object is a 44px icon tile now (css/apple.css's
   shared .ic-tile), so .plus-card just needs to keep it from stretching in
   the flex column -- .on-dark .ic-tile already carries the #1C1C1E fill
   this card used to reset --surface-2 to feed a plain <img> background. */
.plus-card .ic-tile { flex: none; }
.plus-card .pc-t { display: grid; gap: 3px; }
.plus-card .pc-t b {
  font-family: var(--font-display); font-weight: 650; font-size: var(--t-md); color: var(--ink);
  line-height: 1.22; min-height: calc(1.22em * 2);
}
.plus-card .pc-t small { color: var(--ink-2); font-size: var(--t-sm); font-weight: 400; line-height: 1.4; }
@media (max-width: 480px) {
  .plus-card .ic-tile { --ic-tile-s: 24px; }
  .plus-card { padding: var(--s-3); }
}

/* ---- point 6: the phone chapter's cards were near-invisible on black --
   `.plus-card`'s "always a white island" reset (above) reads as a stark,
   out-of-place light rectangle inside a genuinely dark chapter rather than
   a card belonging to it. Inside `.on-dark`, use Apple's own dark-card
   recipe instead: fill #1C1C1E, a 1px #2C2C2E edge, white title, #A1A1A6
   body -- exact values, not the chapter's low-contrast --surface/--ink-3
   pair (#242424 fill on #000000 ground, #6E6E73 body text) that made the
   card read as barely-there. */
.on-dark .plus-card {
  --surface-2: #242426; --ink: #FFFFFF; --ink-2: #A1A1A6;
  background: #1C1C1E; border: 1px solid #2C2C2E;
}
/* ---- point 6: one alignment rule per chapter -- a plus-bento of exactly
   three cards (till/kitchen/pocket/dashboard all ship three) used to fill
   a 4-column grid and sit flush left, next to a headline the chapter
   already centres -- centre the row itself, to match. A bento of four or
   six (offline's tile grid) is untouched: it already spans the full
   container width on purpose. */
/* Round 10: gated to desktop. `:has()` carries its argument's specificity
   (0,4,0 here), so unguarded it beat BOTH the 900px and the 700px
   `repeat(2, ...)` rules below and every three-card bento was still a
   3-column grid on a phone -- two cards in columns 1 and 2, an empty
   column 3, and the third card spanning underneath. */
@media (min-width: 901px) {
  .plus-bento:has(> .plus-card:nth-child(3):last-child) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    max-width: 900px; margin-inline: auto;
  }
}
/* the pill itself defaults to flush-left (width: fit-content with no auto
   margin) -- centre it wherever its chapter is centred. Chapters that stay
   left-aligned (none currently) are unaffected since they never carry
   `.section-head[style*=center]`-style centring in the first place. */
#pocket .chapter-pill, #dashboard .chapter-pill,
.scrub-chapter .chapter-pill, #offline .chapter-pill,
#chapter-cashup .chapter-pill {
  margin-inline: auto;
}

/* ============================================================================
   Chapter lede split — the first sentence reads dark, the rest steps down to
   the secondary ink colour. Split at render time by js/apple.js (a plain
   text split, not a markup change to every paragraph on the page); anything
   not yet split just reads as ordinary --ink-2 body copy, so nothing breaks
   if the splitter has not run.
   ========================================================================= */
.lede-split { color: var(--ink-2); }
.lede-split b { color: var(--ink); font-weight: 600; }

/* ============================================================================
   Why delEat — a plain 3x2 grid of compact cards, no rail. Used to be a
   horizontal snap rail of tall 3:4 cards, eyebrow + headline + a plus that
   revealed a second sentence over the drawn object -- six of those made for
   a lot of card carrying very little text, and a rail to page through on
   top of it. The drawn object, a headline and one line is everything each
   card ever said; height now fits that instead of a fixed 3:4 box.
   ========================================================================= */
.wcards-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0,1fr));
  gap: 14px; margin-top: var(--s-6);
}
@media (max-width: 900px) {
  .wcards-grid { grid-template-columns: repeat(2, minmax(0,1fr)); }
}
@media (max-width: 560px) {
  .wcards-grid { grid-template-columns: 1fr; }
}
.wcard {
  --ink: var(--n-900); --ink-2: var(--n-600);
  display: flex; flex-direction: column; align-items: flex-start;
  background: var(--n-0); border-radius: 20px; padding: 24px;
}
.wcard-obj {
  width: 72px; height: 72px; object-fit: contain;
  filter: drop-shadow(0 8px 14px rgba(0,0,0,.12));
}
.wcard-head {
  margin-top: var(--s-3); font-family: var(--font-display); font-weight: 700;
  font-size: var(--t-lg); letter-spacing: var(--tr-tight); line-height: 1.2;
  color: var(--ink);
  /* Six cards, one two-line title ("Runs every till at The Bhukkad
     Café") among five one-line ones -- reserve two lines always so that
     card's lede does not sit higher than its row's the rest. The grid's
     own default `align-items: stretch` already equalises card height;
     this keeps the text inside each card aligned too. */
  min-height: calc(1.2em * 2);
}
.wcard-lede {
  margin-top: var(--s-2); font-size: var(--t-sm); line-height: 1.4; color: var(--ink-2);
}

@media (prefers-reduced-motion: reduce) {
  .wcard { transition: none; }
}

/* ============================================================================
   Pricing — Apple's "Keep exploring" trio treatment on top of the existing
   .plans grid: a small "Currently viewing" tag on the recommended plan and a
   tighter, spec-list reading for the feature list.
   ========================================================================= */
.plan-current {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 10.5px; font-weight: 700;
  letter-spacing: var(--tr-caps); text-transform: uppercase;
  color: var(--o-800); margin-bottom: var(--s-2);
}
.plan-current::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.plan ul { font-variant-numeric: tabular-nums; }

/* ============================================================================
   Keep exploring — three restaurant types, Apple's closing trio.
   ========================================================================= */
.explore-trio {
  display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: var(--s-4);
  margin-top: var(--s-6);
}
@media (max-width: 860px) {
  .explore-trio { display: flex; flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch; scrollbar-width: none; gap: 12px; padding-bottom: 4px; margin-top: var(--s-5); }
  .explore-trio::-webkit-scrollbar { display: none; }
  .explore-trio > a { flex: 0 0 82%; scroll-snap-align: start; }
}
.explore-card {
  position: relative; display: block; overflow: hidden; isolation: isolate;
  border-radius: var(--r-6); aspect-ratio: 4 / 5; text-decoration: none; color: #FFFFFF;
  background: var(--n-800); box-shadow: var(--lift-2);
  transition: transform var(--d-3) var(--glide), box-shadow var(--d-3) var(--glide);
}
.explore-card:hover { transform: translateY(-4px); box-shadow: var(--lift-4); }
.explore-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.explore-card img {
  position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform var(--d-4) var(--glide);
}
.explore-card:hover img { transform: scale(1.05); }
.explore-card::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 58%; z-index: 1;
  background: linear-gradient(to top, rgba(0,0,0,.68), rgba(0,0,0,0)); pointer-events: none;
}
.explore-card span {
  position: absolute; left: var(--s-5); right: var(--s-5); bottom: var(--s-5); z-index: 2;
}
.explore-card span b { display: block; font-family: var(--font-display); font-weight: 700; font-size: clamp(19px, 1.6vw, 24px); letter-spacing: -.02em; }
.explore-card span small { display: block; margin-top: 5px; font-size: var(--t-sm); opacity: .92; }
.explore-card .room-go { top: var(--s-4); right: var(--s-4); }
.explore-card:hover .room-go, .explore-card:focus-visible .room-go { opacity: 1; transform: none; }
@media (max-width: 700px) {
  .explore-card { aspect-ratio: 4 / 3.2; }
}

/* ============================================================================
   Footer footnotes — small mono markers for the pricing and offline claims.
   ========================================================================= */
/* Round 11, item G: the four notes moved to footnotes.html, so the footer is
   a wordmark, four columns and a base line. The marker stays, as a link. */
sup.fn-ref { font-size: 9px; vertical-align: super; margin-left: 1px; }
sup.fn-ref a { color: var(--o-400); text-decoration: none; }
sup.fn-ref a:hover { text-decoration: underline; }

/* ============================================================================
   Hero: the cinematic film -- Square's daylight-clip idiom (squareup.com)
   crossed with Toast's "built for busy" framing and the apple.com/iphone-duo
   text-over-motion hero. One 24.92s edited film (img/video/film/hero-film,
   a seamless loop) plays behind the copy; a subtitle line cross-fades in
   step with the film's own cues (pos, terrace, latte, tap, bakery,
   openkitchen -- img/video/film/cues.json, inlined into js/apple.js's
   heroFilm() so the artifact build needs no fetch), a scrim so the copy
   reads on any frame. Replaces the old three-device rise/pin (`.hd-slot`,
   `#hero-devices`, `html.hi-pin`) that used to live here -- removed along
   with its intro springs; see js/apple.js's heroFilm() for the cue-mapping
   and playback and heroFilmEntrance() for the on-load rise. This file only
   ever sets layout, colour and the REST state (also what
   `prefers-reduced-motion` and Save-Data get: the film's poster frame,
   static "pos" text, nothing else).
   ========================================================================= */
.hero-film {
  min-height: 100svh;
}
@supports (min-height: 100dvh) {
  .hero-film { min-height: 100dvh; }
}

/* ---- the film layer: full-bleed, behind everything, paused off-screen by
   js/apple.js's IntersectionObserver. `.hf-poster` is a plain <img> that
   sits over the film until it reports `playing`, so the very first paint
   is the film's own still frame (instant, no video fetch needed) and the
   cinematic fade-in is an explicit 600ms cross-dissolve, not a hope that
   the video decodes before anyone notices. */
.hero-film-bg {
  position: absolute; inset: 0; z-index: 0; overflow: hidden;
  background: var(--n-900);
}
.hf-poster, .hf-film {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;
}
.hf-poster {
  z-index: 2; opacity: 1;
  transition: opacity .6s var(--glide);
}
.hf-poster.is-gone { opacity: 0; }
.hf-film { z-index: 1; }
.hero-film-bg .hero-scrim {
  position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: linear-gradient(to bottom, rgba(0,0,0,.55), rgba(0,0,0,.35) 45%, rgba(0,0,0,.7));
}
.hero-film-bg .grain { z-index: 4; }
@media (prefers-reduced-motion: reduce) {
  .hf-poster { transition: opacity .2s linear; }
}

/* ---- the copy: centred over the film, one column, bone type throughout --
   the film + scrim is the hero's media, not a second ground, so this stays
   inside the site's two-ground rule (bone / charcoal) rather than reading
   as a third. */
.hero-film-in {
  position: relative; z-index: 3; width: 100%; flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding-inline: var(--gutter);
}
.hero-film-copy {
  position: static; display: flex; flex-direction: column; align-items: center;
  max-width: 46rem;
}
.hero-film-copy .eyebrow {
  color: var(--bone); opacity: .86;
}
.hero-film-copy h1 {
  margin-top: var(--s-4); max-width: 15ch;
  font-family: var(--font-display); font-weight: 700;
  font-size: clamp(44px, 7vw, 104px); line-height: 1.02; letter-spacing: -0.03em;
  color: var(--bone);
}
.hero-film-copy h1 i[data-glitch] {
  color: var(--o-500); -webkit-text-stroke: 0; text-shadow: 0 3px 18px rgba(0,0,0,.4);
}
.hero-film-copy h1 i[data-glitch]::before { color: var(--n-900); }
.hero-film-copy h1 i[data-glitch]::after  { color: #4B69F0; }

/* ---- the subtitle: six lines stacked on the same grid cell, only one ever
   opaque -- swapped in step with the film by js/apple.js's heroFilm(). */
.hero-film-sub {
  position: relative; display: grid; margin-top: var(--s-4);
  min-height: 1.7em;
}
.hfs-line {
  grid-area: 1 / 1; margin: 0 auto; max-width: 42ch;
  font-family: var(--font-ui); font-weight: 500;
  font-size: clamp(18px, 1.6vw, 24px); line-height: 1.35;
  color: color-mix(in srgb, var(--bone) 85%, transparent);
  opacity: 0; transition: opacity .6s var(--glide);
}
.hfs-line.is-on { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .hfs-line { transition: opacity .2s linear; } }

.hero-film .hero-actions { justify-content: center; margin-top: var(--s-5); }
.hero-film .btn-ghost {
  --btn-fg: var(--bone);
  background: rgba(247,243,238,.12);
  -webkit-backdrop-filter: blur(18px) saturate(1.5);
  backdrop-filter: blur(18px) saturate(1.5);
  box-shadow: inset 0 0 0 1.5px rgba(247,243,238,.4);
}
.hero-film .btn-ghost:hover {
  --btn-bg: rgba(247,243,238,.2);
  box-shadow: inset 0 0 0 1.5px rgba(247,243,238,.6);
}
.hero-film .hero-note { display: none; } /* the mono trust line below carries this once, not twice */
.hero-film .hero-trust {
  margin-top: var(--s-3); text-align: center; opacity: 1;
  color: color-mix(in srgb, var(--bone) 70%, transparent);
}

/* ---- the clip dots: pinned to the bottom edge of the hero, bottom-centre,
   tap to jump. Absolute against `.hero-film-in` (its own positioning
   context) so they read as pagination for the film rather than one more
   line in the copy's own flow. */
.hero-film-dots {
  position: absolute; left: 50%; bottom: clamp(20px, 4vh, 40px); transform: translateX(-50%);
  z-index: 3; display: flex; gap: 8px;
}
.hero-film-dots button {
  width: 7px; height: 7px; border-radius: 999px; border: 0; padding: 0; cursor: pointer;
  background: color-mix(in srgb, var(--bone) 40%, transparent);
  transition: width var(--d-2) var(--snap), background var(--d-2) var(--snap);
}
.hero-film-dots button[aria-selected="true"] { width: 22px; background: var(--bone); }
.hero-film-dots button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (max-width: 700px) {
  .hero-film-copy h1 { max-width: 13ch; }
  .hero-film-dots { bottom: clamp(14px, 3vh, 28px); }
}

@media (prefers-reduced-motion: reduce) {
  .hl-card, .hl-media-box, .explore-card, .nc-media-box, .nc-media { transition: opacity .2s linear !important; transform: none !important; }
}

/* ============================================================================
   Hero: Apple's Duo structure, exact — copy tight to the nav, one film full
   width of the content column directly under it, nothing else. Rebuilt
   2026-09-10 against the founder's own words ("nothing like an Apple
   website"): the earlier Duo pass still boxed the film as a card (n-900
   background, border-radius, box-shadow) on the site's eggshell ground,
   which is exactly the "card, not a Duo" mistake. Apple's Duo hero has no
   card at all -- the film sits directly on the page.

   The one documented exception to the site's two grounds (eggshell/black):
   this section alone runs pure #FFFFFF, because the hero film itself is
   real studio footage (hands + till, composited) shot on a near-white
   backdrop with a natural vignette -- sampled at its corners, ~#E9E9E9,
   center ~#FFFCF9 -- not a flat colour a section background can key to
   exactly. #FFFFFF is the closest a CSS ground gets to that footage without
   re-grading the (read-only) source video, and the fade mask below dissolves
   the vignette's edge into the page rather than showing a rectangle. */
/* The hero-duo block (2026-09-10) was removed in round 10 -- the hero is
   now .hero30 (the apple.com/environment idiom), at the foot of this file. */

/* ============================================================================
   The Offline chapter — Apple's "here's what you get" idiom (apple.com's
   iPhone 18 Pro page): black tiles, one stat or fact each, no icon. Replaces
   "Why delEat" (used to be a light 3x2 grid of icon cards making the same
   six-reasons argument in a softer register) as the chapter that closes the
   claims case, printed on the site's other ground instead of a third tint.
   ========================================================================= */
/* ---- Round 25, item 9: the offline tiles take the modules wall's spans ---
   Six tiles at one size is a list with rounded corners. This is the same
   grammar `#everything` uses and the highlights bento was put on in round
   24: four columns, a 2 by 2 lead, and the rest a mix of wide and square,
   with the DOM in the layout's own order so no cell is ever back-filled.
   Two columns from 1000px down (the lead goes full width and keeps its two
   rows), one column under 700 where every tile is its own row.
   ------------------------------------------------------------------------- */
.offline-tiles {
  display: grid; grid-template-columns: repeat(4, minmax(0,1fr));
  grid-auto-rows: minmax(206px, auto);
  gap: 14px; margin-top: var(--bento-top);
}
.offline-tiles .offline-tile.ot-lead { grid-column: span 2; grid-row: span 2; }
.offline-tiles .offline-tile.ot-wide { grid-column: span 2; }
@media (max-width: 1000px) {
  .offline-tiles { grid-template-columns: repeat(2, minmax(0,1fr)); }
}
/* the same specificity lesson the modules wall recorded in round 10: a plain
   `.ot-wide` rule further down the file would beat an unscoped reset here
   and leave a span-2 tile two tracks wide inside a one-track grid, which is
   what opens a second implicit column. Scoped, so the reset wins. */
@media (max-width: 700px) {
  .offline-tiles { grid-template-columns: 1fr; gap: 12px; grid-auto-rows: minmax(150px, auto); }
  .offline-tiles .offline-tile.ot-lead,
  .offline-tiles .offline-tile.ot-wide { grid-column: span 1; grid-row: span 1; }
}

/* ---- the three slot sizes, each fitted to what it holds ------------------ */
/* the lead is the only tile with room for a tall photograph, so it takes a
   deeper band than the old equal tiles could carry. */
.offline-tile.ot-lead.has-band { --ot-band: 268px; }
.offline-tile.ot-lead b { font-size: 76px; }
/* the squares: a narrower measure, so the value and the caption step down
   with it rather than wrapping into the crop. */
.offline-tile.ot-sq { padding: 22px 20px; }
.offline-tile.ot-sq b { font-size: 40px; }
.offline-tile.ot-sq.has-crop b { font-size: 30px; }
.offline-tile.ot-sq p { font-size: 13.5px; max-width: 21ch; }
.offline-tile.ot-sq.has-crop { padding-right: 34%; }
/* the wides read left to right: the copy in the first half, the fragment
   bleeding off the right corner in the second. */
.offline-tile.ot-wide.has-crop { padding-right: 34%; }
.offline-tile.ot-wide p { max-width: 34ch; }
/* "Any time" is a photograph on a wide tile now, so the image is a right-hand
   block at full height rather than the bottom band it was as a square. */
.offline-tile.ot-wide.ot-shot { padding-bottom: 26px; }
.offline-tile.ot-wide.ot-shot .ot-photo { width: 46%; height: 100%; top: 0; bottom: 0; }
.offline-tile.ot-wide .ot-chip { bottom: 22px; }
/* point 10: rebuilt as Apple's "here's what you get" tiles -- a gradient
   fill (not the flat --surface-2 slab this used to be), a hairline edge, a
   soft top-left highlight, and three of the six carrying a real crop that
   bleeds off the tile's own bottom-right corner. */
.offline-tile {
  position: relative; overflow: hidden; isolation: isolate;
  display: flex; flex-direction: column; justify-content: center; gap: 10px;
  min-height: 190px; padding: 26px 24px;
  border-radius: 24px;
  background: linear-gradient(160deg, var(--nt-surface) 0%, var(--nt-surface-2) 100%);
  border: 1px solid var(--nt-line);
  transition: transform .2s var(--glide);
}
.offline-tile::before {
  content: ""; position: absolute; z-index: 0; inset: 0; pointer-events: none;
  background: radial-gradient(120px 120px at 0% 0%, rgba(255,255,255,.08), transparent 70%);
}
.offline-tile > b, .offline-tile > p { position: relative; z-index: 2; }
@media (hover: hover) and (pointer: fine) {
  .offline-tile:hover { transform: translateY(-4px); }
}
.offline-tile b {
  font-family: var(--font-display); font-weight: 600; font-size: 64px; line-height: 1.05;
  letter-spacing: -0.02em; color: var(--ink);
}
/* the three phrase tiles ("Any browser", "Any time") wrap at 64px inside a
   crop tile's narrowed text column -- one step down keeps them to a tight
   two lines instead of the number tiles' single huge line. */
.offline-tile.has-crop b { font-size: 44px; }
.offline-tile p { font-size: 15px; line-height: 1.45; color: #A1A1A6; max-width: 22ch; }
@media (max-width: 700px) {
  .offline-tile { min-height: 150px; padding: 20px; }
  .offline-tile b { font-size: 38px; }
  .offline-tile.has-crop b { font-size: 30px; }
}
@media (prefers-reduced-motion: reduce) { .offline-tile { transition: none; } }

/* the three cropped tiles: a real render, bottom-right, bleeding off the
   tile's own edge rather than sitting inside a frame. */
.offline-tile .ot-crop {
  position: absolute; z-index: 1; right: -18px; bottom: -14px; pointer-events: none;
  filter: drop-shadow(0 12px 20px rgba(0,0,0,.45));
}
.offline-tile.has-crop { padding-right: 30%; }
.offline-tile .ot-crop.ot-img { width: 54%; max-width: 220px; border-radius: 10px 0 0 0; overflow: hidden; opacity: .92; }
.offline-tile .ot-crop.ot-img img { display: block; width: 100%; height: auto; }
.offline-tile .ot-crop.ot-receipt {
  width: 128px; transform: rotate(4deg); transform-origin: bottom right;
  background: var(--n-0); color: var(--n-800); font-family: var(--font-mono);
  font-size: 8.5px; line-height: 1.6; padding: 10px 10px 14px; border-radius: 4px 4px 0 0;
  box-shadow: 0 12px 20px rgba(0,0,0,.4);
}
.offline-tile .ot-crop.ot-receipt hr { border: 0; border-top: 1px dashed var(--n-300); margin: 5px 0; }
.offline-tile .ot-crop.ot-receipt .r { display: flex; justify-content: space-between; gap: 6px; }
.offline-tile .ot-crop.ot-receipt .r b { font-weight: 700; }
.offline-tile .ot-crop.ot-csv {
  width: 150px; transform: rotate(-3deg); transform-origin: bottom right;
  background: var(--n-0); color: var(--n-800); font-family: var(--font-mono);
  font-size: 8px; line-height: 1.9; padding: 9px 11px; border-radius: 6px 0 0 0;
  box-shadow: 0 12px 20px rgba(0,0,0,.4);
}
.offline-tile .ot-crop.ot-csv div { display: flex; justify-content: space-between; gap: 8px; white-space: nowrap; }
.offline-tile .ot-crop.ot-csv div:first-child { color: var(--n-500); border-bottom: 1px solid var(--n-200); padding-bottom: 3px; margin-bottom: 2px; }
@media (max-width: 700px) {
  .offline-tile.has-crop { padding-right: 24px; }
  .offline-tile .ot-crop.ot-img { width: 46%; }
  .offline-tile .ot-crop.ot-receipt, .offline-tile .ot-crop.ot-csv { transform: scale(.82) rotate(4deg); transform-origin: bottom right; }
}

/* ============================================================================
   Chapter pill + sheet — every narrative chapter (till, floor, kitchen,
   cash-up, pocket, the dashboard chapter) ends with one glass pill: a
   summary line plus a round vermilion + button, the way apple.com/ipad-pro
   closes each section with an "expand" affordance. Tapping it opens
   #ch-sheet — one shared dialog (js/apple.js populates it per chapter from a
   small content map, rather than duplicating a sheet's markup six times) —
   a bottom sheet on phones, a centred modal on desktop, with the pill's own
   screen position as the modal's transform-origin so it visibly springs
   from where it was tapped (spatial consistency: it has to close back along
   the same path).
   ========================================================================= */
/* Round 10, point 6: the pill no longer expands and collapses with scroll
   (the `--pill-w`/`--pill-tw`/`--pill-to`/`--pill-mr` spring, and its
   chapterPills() driver in js/apple.js, are gone). It renders fully
   expanded, always: a white capsule on eggshell, #1C1C1E on black. Hover
   lifts it 1px and deepens the shadow over 200ms, the way Apple's own plus
   buttons behave; the plus itself rotates 45 degrees into a cross while the
   sheet is open (`.is-open`, set by openSheet/closeSheet). */
.chapter-pill {
  display: flex; align-items: center; gap: var(--s-3);
  margin-top: var(--s-6); padding: 8px 8px 8px 20px;
  width: fit-content; max-width: 100%;
  box-sizing: border-box;
  border-radius: var(--r-full);
  background: var(--n-0);
  border: 1px solid color-mix(in srgb, var(--ink) 8%, transparent);
  box-shadow: 0 1px 0 color-mix(in srgb, #FFFFFF 55%, transparent) inset, var(--lift-2);
  transition: transform var(--d-2) var(--glide), box-shadow var(--d-2) var(--glide);
}
.on-dark .chapter-pill {
  background: #1C1C1E;
  border-color: #2C2C2E;
  box-shadow: 0 1px 0 color-mix(in srgb, var(--bone) 8%, transparent) inset, var(--lift-2);
}
@media (hover: hover) and (pointer: fine) {
  .chapter-pill:hover { transform: translateY(-1px); box-shadow: 0 1px 0 color-mix(in srgb, #FFFFFF 55%, transparent) inset, var(--lift-3); }
  .on-dark .chapter-pill:hover { box-shadow: 0 1px 0 color-mix(in srgb, var(--bone) 8%, transparent) inset, var(--lift-3); }
}
.chapter-pill p {
  font-size: var(--t-sm); font-weight: 500; color: var(--ink-2); line-height: 1.4;
  min-width: 0;
}
.chapter-pill-open {
  flex: none; width: 34px; height: 34px; border-radius: 999px; border: 0; padding: 0; cursor: pointer;
  display: grid; place-items: center; align-self: center;
  background: var(--o-500); color: var(--n-900);
  transition: transform var(--d-3) var(--snap), background var(--d-2) var(--snap);
}
.chapter-pill-open:hover { background: var(--o-600); }
.chapter-pill-open:active { transform: scale(.94) rotate(var(--pill-rot, 0deg)); }
.chapter-pill-open.is-open { transform: rotate(45deg); }
.chapter-pill-open svg { width: 15px; height: 15px; pointer-events: none; }
.chapter-pill-open:focus-visible { outline: 2px solid var(--o-500); outline-offset: 3px; }
@media (max-width: 700px) {
  /* the sentence wraps to two lines inside the capsule; the plus stays
     vertically centred against the wrapped block. */
  .chapter-pill { margin-top: var(--s-5); padding: 10px 10px 10px 18px; align-items: center; }
  .chapter-pill p { font-size: 13.5px; }
}
@media (prefers-reduced-motion: reduce) {
  .chapter-pill, .chapter-pill-open { transition: none; }
}

/* Round 22, Apple Design audit sections 2/3/5/6/7/9/12: the sheet is a
   Spring now, not a CSS transition — js/apple.js writes opacity/transform/
   filter every frame from a single 0-1 progress spring, which is what lets
   a re-open mid-close carry on from wherever it actually is (interrupt from
   the presentation value, section 3) instead of restarting a fixed curve.
   The base rules below are only the PRE-JS resting shape (closed) and the
   final `.is-open` numbers JS settles onto; neither carries a `transition`
   any more, or the per-frame inline writes below would fight it. Reduced
   motion is untouched: no spring is ever constructed there (see js/apple.js),
   so the plain opacity cross-fade transition in the @media block at the foot
   of this file still does the whole job, unchanged. */
.ch-sheet-backdrop {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(0,0,0,.5);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  opacity: 0; pointer-events: none;
}
/* opacity:1 stays here, not only written by JS, because the reduced-motion
   branch (js/apple.js) never constructs a spring and only ever toggles this
   class -- it relies on the resting CSS value, exactly as it did before the
   spring existed. The non-reduced path's inline opacity (higher specificity)
   overrides this during the animation and lands on the same number anyway. */
.ch-sheet-backdrop.is-open { opacity: 1; pointer-events: auto; }
.ch-sheet-backdrop[hidden] { display: block; } /* stays mounted through the close transition; JS re-adds [hidden] after it */
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .ch-sheet-backdrop { background: rgba(0,0,0,.8); backdrop-filter: none; -webkit-backdrop-filter: none; }
}

.ch-sheet {
  position: fixed; z-index: 301; background: var(--n-0); color: var(--n-900);
  box-shadow: var(--lift-4); overflow-y: auto; overflow-x: hidden;
}
@media (min-width: 701px) {
  .ch-sheet {
    left: 50%; top: 50%; width: min(680px, 88vw); max-height: 82vh;
    border-radius: var(--r-6);
    opacity: 0; pointer-events: none;
    transform: translate(-50%, -50%) scale(.92);
    transform-origin: var(--sheet-ox, 50%) var(--sheet-oy, 50%);
  }
  /* same reasoning as the backdrop above: the resting values a reduced-
     motion open relies on, harmlessly overridden by inline styles otherwise. */
  .ch-sheet.is-open { opacity: 1; pointer-events: auto; transform: translate(-50%, -50%) scale(1); }
}
@media (max-width: 700px) {
  .ch-sheet {
    left: 0; right: 0; bottom: 0; width: 100%; max-height: 86vh;
    border-radius: 24px 24px 0 0;
    opacity: 0; pointer-events: none;
    transform: translateY(100%);
  }
  .ch-sheet.is-open { opacity: 1; pointer-events: auto; transform: translateY(0); }
}
/* the drag grabber — phones only, a bottom sheet's usual invitation to pull
   it down. touch-action: none on the handle so a vertical drag never also
   scrolls the page under it; the body text below keeps native scroll. */
.ch-sheet-handle { display: none; }
@media (max-width: 700px) {
  .ch-sheet-handle {
    display: block; width: 36px; height: 5px; border-radius: 999px;
    margin: 10px auto 0; background: var(--n-300);
    touch-action: none; cursor: grab;
  }
  .ch-sheet.is-dragging .ch-sheet-handle { cursor: grabbing; }
}
.ch-sheet-more { margin-top: var(--s-5); }
.ch-sheet-close {
  position: absolute; top: 14px; right: 14px; z-index: 5;
  width: 32px; height: 32px; border-radius: 999px; border: 0; cursor: pointer;
  background: color-mix(in srgb, var(--n-0) 88%, transparent);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  color: var(--n-700); display: grid; place-items: center;
}
.ch-sheet-close:hover { background: var(--n-0); }
.ch-sheet-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ch-sheet-media { position: relative; width: 100%; aspect-ratio: 4 / 3; overflow: hidden; background: var(--n-800); }
.ch-sheet-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ch-sheet-body { padding: 28px clamp(20px, 4vw, 32px) 36px; }
.ch-sheet-body h3 { font-family: var(--font-display); font-weight: 700; font-size: var(--t-xl); letter-spacing: var(--tr-tight); }
.ch-sheet-paras p { margin-top: var(--s-3); font-size: var(--t-sm); line-height: 1.6; color: var(--ink-2); }
.ch-sheet-paras p:first-child { margin-top: var(--s-4); }
@media (prefers-reduced-motion: reduce) {
  .ch-sheet-backdrop, .ch-sheet { transition: opacity .2s linear; transform: none !important; }
}

/* ============================================================================
   The Dashboard chapter — apple.com/ae/os/ios's own vocabulary: a version
   tag in mono beside the eyebrow, the device family shown together (one
   large, three smaller, fanned beneath it) rather than one screen, then an
   icon-free list of feature rows, then a small "what's new" trio. Device
   chrome and screen markup are the exact classes css/modules.css already
   ships for the module pages (.dev-rig/.mac-box/.imac-box/.pad-box/
   .dev-ph-box) — this chapter only decides how big each one's own column is;
   js/modules.js's fitBoxes() (now loaded on this page) reads that column
   width the same way it does on every module page.
   ========================================================================= */
.dash-version {
  display: inline-block; margin-top: var(--s-2);
  font-family: var(--font-mono); font-size: 11px; font-weight: 600;
  letter-spacing: var(--tr-caps); color: var(--accent-text);
}
/* point 6: one alignment rule per chapter -- the dashboard's own headline
   used to sit flush left while its device fan below was already centred
   (`.dash-fan`'s `align-items: center`). Apple centres product chapters;
   the headline/lede and the two block-level content groups below (the
   feature rows, the "what's new" trio) now match. Individual rows keep
   their own left-set text -- only the block that holds them is centred,
   the same pattern `.scrub-chapter .moment-copy .points` already uses. */
#dashboard .section-head { text-align: center; margin-inline: auto; }
/* Round 25, item 12: `#onesystem`'s head lost its photograph, so it takes the
   dashboard's own centred treatment rather than sitting in half of a
   two-column grid with an empty column beside it. */
.section-head.is-centred { text-align: center; margin-inline: auto; }
.section-head.is-centred .lede, .section-head.is-centred h2 { margin-inline: auto; }
#dashboard .dash-rows { margin-inline: auto; text-align: left; }
#dashboard .dash-new { text-align: center; }
#dashboard .dash-new-cards { text-align: left; }
/* point 7: the dashboard chapter's four screens show the REAL product --
   a 2x screenshot of the actual delEat dashboard (pos.deleat.io, logged in
   as the seed owner account), cropped per device rather than a hand-built
   mock. Cropped, not redrawn, so the numbers, the calendar grid, the map
   and "The hour" card are all pixel-real. */
.dash-real-shot { display: block; width: 100%; height: 100%; object-fit: cover; object-position: top left; }
.dash-fan { margin-top: var(--s-8); display: flex; flex-direction: column; align-items: center; }
.dash-fan-imac { width: min(640px, 78%); }
.dash-fan-imac .dev-rig { padding-block: 0; }
/* three devices, one baseline (align-items: flex-end), centred, a small
   fixed-feeling gap between them (clamp anchored near 5% of the largest
   device's own width, not 5% of the row's container -- the row does not
   stretch to fill the section, so a container-relative percentage gap
   would grow unboundedly on a wide screen). Column widths are chosen so
   the SCREEN heights land in a 1 : 0.8 : 0.55 ratio (MacBook : iPad :
   iPhone), not the box widths themselves -- each device's own chrome eats
   a different fraction of its box (iPad and iPhone are flat CSS insets:
   90.8% and 97% of box height; the MacBook is the live device3d render,
   measured at ~49% of its own box height at rest), so equal screen
   heights need unequal box widths. Measured/solved once against real
   layout numbers (see the family-row verification pass), not guessed. */
.dash-fan-small {
  margin-top: clamp(-44px, -4vw, -20px); position: relative; z-index: 1;
  display: flex; align-items: flex-end; justify-content: center; gap: clamp(10px, 1.5vw, 20px);
}
.dash-fan-small .dev-rig { padding-block: 0; }
.dfs-mac  { width: min(280px, 30vw); }
.dfs-pad  { width: min(136px, 14.6vw); }
.dfs-phone{ width: min(28px, 3vw); }
@media (max-width: 700px) {
  .dash-fan { margin-top: var(--s-7); }
  .dash-fan-imac { width: 100%; }
  /* phones: the big iMac drops to its still (device3d's own <900px
     fallback) and the three small devices stay, in the same single
     baseline row, scaled down by the same fluid min(px, vw) rules above
     -- at a 390px viewport that is roughly 117/57/12px, comfortably
     inside the wrap-wide gutter with no overlap (verified in the
     dashboard-3d-mobile capture), so there is nothing further to override
     here beyond tightening the gap a little for the narrower row. */
  .dash-fan-small { gap: clamp(6px, 2vw, 14px); }
}

/* Point 8: the six feature rows were one tall single column -- a lot of
   height for six short claims. 3 columns on desktop, 2 on tablet, 1 on
   phone, each cell an icon tile + title + two lines, with a hairline only
   between ROWS (nth-child keyed to how many cells actually sit in a row at
   each breakpoint, since a straight border-top on every cell would draw a
   line between columns too). */
.dash-rows {
  margin-top: var(--s-8); max-width: 900px;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 var(--s-6);
}
.dash-row { padding-block: var(--s-5); }
.dash-row .ic-tile { margin-bottom: var(--s-3); }
.dash-row:nth-child(n+4) { border-top: var(--hair); }
.dash-rows { border-bottom: var(--hair); }
.dash-row b { display: block; font-family: var(--font-display); font-weight: 700; font-size: var(--t-lg); letter-spacing: var(--tr-tight); }
.dash-row p { margin-top: 6px; font-size: var(--t-sm); line-height: 1.55; color: var(--ink-2); }
@media (max-width: 900px) {
  .dash-rows { grid-template-columns: repeat(2, 1fr); }
  .dash-row { border-top: 0 !important; }
  .dash-row:nth-child(n+3) { border-top: var(--hair) !important; }
}
@media (max-width: 560px) {
  .dash-rows { grid-template-columns: 1fr; }
  .dash-row { border-top: 0 !important; }
  .dash-row:nth-child(n+2) { border-top: var(--hair) !important; }
}

.dash-new { margin-top: var(--s-7); }
.dash-new-lab {
  font-family: var(--font-mono); font-size: 11px; font-weight: 700;
  letter-spacing: var(--tr-caps); text-transform: uppercase; color: var(--ink-3);
}
.dash-new-cards { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 12px; margin-top: var(--s-3); }
.dash-new-card { padding: 16px 18px; border-radius: var(--r-4); background: var(--surface-2); }
.dash-new-card b { display: block; font-family: var(--font-display); font-weight: 650; font-size: var(--t-sm); }
.dash-new-card span { display: block; margin-top: 3px; font-size: 12.5px; color: var(--ink-2); line-height: 1.4; }
@media (max-width: 700px) {
  .dash-new-cards { grid-template-columns: repeat(2, minmax(0,1fr)); }
}

/* ============================================================================
   Apple product-page port, round two — 2026-09-10. Everything below this
   line is new: the sticky scroll-scrubbed sequence (till + kitchen chapters,
   built from real captured screen recordings, not stock footage or an
   Apple asset), the play/pause control shared by every autoplaying clip on
   the page, stat callouts, chapter-lede parallax, and the button/link
   micro-interactions. Values below are lifted from this session's audit of
   airpods-pro / macbook-pro / mac-mini / ipad-pro / apple-vision-pro
   (glass blur 20px, play/pause 38px, stat 48px/600/-0.144px number over a
   14px/600 grey caption, mechanical timings under .25s) — the study, not a
   guess. Nothing here invents a colour, radius or curve outside tokens.css.
   ========================================================================= */

/* ---- B2: the sticky scroll-scrubbed sequence -----------------------------
   A tall wrapper (`--scrub-h`, capped at 220vh) holds a `position: sticky;
   top: 0; height: 100vh` stage. Only the SCREEN is video — the iPad frame
   stays the site's own live CSS chrome (`.pad-rig`/`.pad-box`/`.pad`), so
   this reuses every value the rest of the site's device frames already use
   rather than inventing a second frame system. A soft daylight photo drifts
   behind the stage at 15% of scroll (B5), gated by IntersectionObserver in
   js/apple.js and switched off outright under reduced motion. On phones
   (<=900px) the wrapper drops back to its normal, unpinned height and the
   video simply autoplays on enter / pauses on leave, exactly like every
   other looping clip on the page — no pin, no scrub, per the guardrail that
   a sticky sequence must never trap a phone's scroll. */
/* the till/kitchen chapters used to lay `.moment-copy` and `.moment-stage`
   out as a two-column row (css/site.css's default `.moment-in` grid); the
   scrub sequence below replaces `.moment-stage` and lives OUTSIDE
   `.moment-in` as a full-width sibling, so `.moment-in` here now holds only
   the copy -- collapse it to one column everywhere, not just under
   site.css's own 920px breakpoint, or the copy sits in the grid's first
   track with a dead second column beside it. */
.scrub-chapter .moment-in { grid-template-columns: 1fr; max-width: 62rem; margin-inline: auto; text-align: center; }
/* Round 25: 62rem, not 46. The headline and the lede carry their own
   max-widths (16ch and 56ch) and are centred by the rule below, so widening
   the container widens only the card row under them. */

/* ---- Round 25, items 4, 7 and 8: three cards, not a chevron list ---------
   The till, kitchen and cash-up heads each carried three chevron bullets.
   They read as a bullet list rather than as anything else on this page, and
   at 34rem inside a 46rem column they left the section's width empty beside
   them. Same three facts, same words, split into a title and one line, in
   the `.plus-card` idiom one step smaller: a naked 28px glyph, a 17px title,
   a 14px line, white on eggshell at --r-lg with one soft shadow. Three
   across, two at 900px, one at 560.
   ------------------------------------------------------------------------- */
.mini-bento {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px; margin-top: var(--bento-top); text-align: left;
}
.mini-card {
  --ink: var(--n-900); --ink-2: var(--n-600);
  display: grid; gap: 6px; align-content: start;
  background: var(--n-0); border-radius: var(--r-lg);
  padding: 18px 18px 20px;
  box-shadow: 0 4px 14px rgba(0,0,0,.05), inset 0 0 0 1px rgba(0,0,0,.05);
}
.mini-card .ic-tile { --ic-tile-s: 28px; margin-bottom: 4px; }
/* Round 63, item 3: the step's orb (js/orbs.js) stands where the icon tile
   did, same 4px gap above the title. */
.mini-card .mini-orb { display: block; width: 56px; height: 56px; margin: 0 0 4px -6px; }
.mini-card b {
  font-family: var(--font-display); font-weight: 600; font-size: 17px;
  line-height: 1.24; letter-spacing: var(--tr-head); color: var(--ink);
}
.mini-card small { font-size: 14px; font-weight: 400; line-height: 1.45; color: var(--ink-2); }
@media (max-width: 900px) { .mini-bento { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mini-bento .mini-card:last-child:nth-child(odd) { grid-column: 1 / -1; } }
@media (max-width: 560px) { .mini-bento { grid-template-columns: 1fr; gap: 10px; }
  .mini-card { padding: 16px; } }

/* ---- Round 64, item 3: the module page's own How-it-works strip only -----
   Scoped to `#how` (tools/build-modules.py how_cards()'s own id) so the
   landing pages' identical-looking strip (tools/lp62.py how_section(), no
   id, sometimes more than three cards) is untouched. The orb grows from 56
   to 72px -- the host span's box has to grow with it, since the canvas
   js/orbs.js draws is sized off `data-orb-size` directly, not off this box.
   Each card now carries its own `data-reveal` (tools/build-modules.py), so
   they stagger in rather than fading as one block; a hairline connects the
   three orbs, drawn left to right as the strip enters view, desktop only,
   sitting behind the (opaque) cards so it only reads in the gaps between
   them -- like a thread the three steps hang off. */
#how .mini-card .mini-orb { width: 72px; height: 72px; margin: 0 0 4px -8px; }
@media (min-width: 901px) {
  #how .mini-bento { position: relative; }
  #how .mini-card { position: relative; z-index: 1; }
  #how .mini-bento::before {
    content: ""; position: absolute; z-index: 0; left: 0; right: 0;
    /* 18px card padding-top + half the 72px orb */
    top: 54px; height: 1px; background: var(--line);
    transform: scaleX(0); transform-origin: left center;
  }
  @supports (animation-timeline: view()) {
    #how .mini-bento { view-timeline: --how-line block; }
    #how .mini-bento::before {
      animation: how-line-draw linear both;
      animation-timeline: --how-line;
      animation-range: entry 10% entry 70%;
    }
  }
}
@keyframes how-line-draw { to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) {
  #how .mini-bento::before { transform: scaleX(1); animation: none; }
}
/* text-align: center only centres INLINE content inside a box -- it does
   nothing for the box itself. `.moment-copy h2` (site.css, max-width: 16ch)
   and `.lede` (base.css, max-width: 56ch) both carry their own max-width,
   so without an auto margin each one still hugs the container's left edge
   even though its own text centres within that narrow box -- exactly the
   "headline reads centred at a glance but is actually flush left" bug the
   kitchen chapter shipped with. Centre the box, not just the text. */
.scrub-chapter .moment-copy h2, .scrub-chapter .moment-copy .lede,
#chapter-cashup .moment-copy h2, #chapter-cashup .moment-copy .lede {
  margin-inline: auto;
}
/* point 6: cash-up centred to match till/kitchen/dashboard/phone/offline --
   it was still the old two-column [copy][photo] row, the one layout none of
   those five uses any more. Same pattern: one centred column, the point
   list stays left-set inside it, the photo card centred below at its own
   width rather than stretched to the full 46rem text measure. */
/* css/site.css's `.moment { overflow: hidden }` exists to contain the OTHER
   moment chapters' 3D-transformed devices (the receipt, an occasional
   over-rotated tablet corner) -- but ANY ancestor with a non-visible
   overflow becomes `.scrub-sticky`'s scrolling container, and that
   container is exactly as tall as `.moment` itself (not the page), so
   `position: sticky` inside it has nowhere to travel and never engages at
   all -- the pad silently renders off in whatever position it would have
   held with no sticky behaviour, i.e. scrolled straight off top. `.scrub-
   stage`'s own overflow: hidden (below) already contains this chapter's one
   3D object, so the section-level clip is not needed here. */
.scrub-chapter { position: relative; overflow: visible; }
.scrub-wrap {
  /* Round 10: 150vh (was 220vh) -- a 50vh scrub runway still maps the whole
     clip comfortably, and 2 x 70vh comes straight off the page length.
     Round 15: the till's own track is 240vh, because the last 40 percent of
     it is the "Talk about Ctrl." callout stage rather than more clip. That
     is 90vh of new page, 810px at 1440, and it buys a section instead of
     costing one. */
  position: relative; height: var(--scrub-h, 150vh);
  margin-top: var(--s-7);
}
/* Round 23, item 5: 212vh, not 240. Measured at 1440x900: the runway was
   2,160px, of which 900 is the sticky itself, so 1,260px of scroll drove
   the stage; the last callout landed at p 0.84, which left 202px of runway
   where nothing on screen changed and the tablet simply sat there before it
   scrolled away. 212vh is 1,908px, 1,008px of drive, and the callouts are
   respaced to finish at p 0.89 -- 111px of dwell on the finished picture
   instead of 202px of nothing. 252px off the chapter at 1440. */
@media (min-width: 901px) { #scrub-till { --scrub-h: 212vh; } }
/* Round 11, item E: the beats used to be an absolutely positioned layer
   pinned to the bottom of the sticky viewport, which put a 32px headline
   straight over the foot of the frame whenever the frame was tall. They are
   a real row now, below the stage, with their own reserved height (--beat-h,
   the tallest beat), and the frame is capped so stage plus band always fit
   one viewport. Nothing overlaps at any height. */
.scrub-sticky {
  --beat-h: 84px;
  /* Round 25, item 3: the frame's own shadow (0 16px 34px) reached into the
     beat line, so the band under the picture is the shadow's tail plus 40px
     of clear ground rather than the old flat 27. */
  --beat-clear: 40px;
  position: sticky; top: 0; height: 100vh;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: calc(clamp(20px, 3vh, 38px) + var(--beat-clear) + 14px);
  /* Round 25, item 5: `overflow: hidden` cut the tablet's contact shadow
     dead on the sticky's own bottom edge, and in the runway's last position
     that edge is a horizontal line across the chapter: a shadow still one
     level off the ground above it, clean #F7F3EE below. `clip` with a
     140px margin lets the shadow finish decaying outside the box instead,
     and unlike `hidden` it never becomes a scroll container or adds
     scrollable overflow of its own. The ambient wash keeps its own
     `overflow: hidden` on `.egg-amb`, so nothing else changes. */
  overflow: clip; overflow-clip-margin: 140px;
}
.scrub-bg {
  position: absolute; inset: -8% -4%; z-index: 0;
  background-size: cover; background-position: center;
  opacity: .5; filter: saturate(.9);
  will-change: transform;
  /* point 9: the edge fades into the section ground instead of cutting on
     a straight line -- a true alpha mask (not just a colour-tinted overlay)
     so it reads correctly regardless of which ground sits behind it, 12%
     of the layer's own height at top and bottom. */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%);
}
.scrub-bg::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, var(--bone) 0%, color-mix(in srgb, var(--bone) 55%, transparent) 18%, color-mix(in srgb, var(--bone) 55%, transparent) 82%, var(--bone) 100%);
}
.scrub-stage { position: relative; z-index: 1; }
/* the till chapter's pad is sized by its own viewport-width ratio; inside a
   scrub sticky it also has to leave room for the beat band, so take the
   smaller of the two. (item E, same fix as .scrub-frame's width cap.) */
.scrub-sticky .pad-box {
  /* Round 60, item 2: every ratio here is tan(atan2(a, b)), which is a / b as
     a plain number in every engine with CSS trigonometry (Safari 15.4 and up).
     calc(a / b) of two lengths is typed arithmetic, which Safari does not
     evaluate: the whole --s chain was invalid there until a script wrote a
     number, so the tablet painted small and grew. */
  --s: var(--pad-s, clamp(.4, min(tan(atan2(88vw, 740px)), tan(atan2(calc(100vh - var(--beat-h) - 120px), 520px))), 1));
}
.scrub-stage .pad-screen, .scrub-stage .imac-screen { background: #000; }
.scrub-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; background: #000; }
/* the kitchen chapter's scrub-video (js/apple.js's initScrub still owns its
   src/currentTime/play-pause entirely -- see js/device3d.js's own comment
   on `data-screen-video-selector`) is now only a pixel SOURCE for the 3D
   viewer's VideoTexture, not something drawn on its own -- js/device3d.js
   samples its frames straight off the element, so it stays decoding and
   in the DOM but never visibly composited over the WebGL canvas. Scoped to
   `.device3d` (the kitchen's own imac-box) so the till chapter's iPad --
   CSS frame, untouched -- still shows its own `.scrub-video` normally. */
.device3d .scrub-video { display: none; }
.scrub-beats {
  position: relative; z-index: 2; width: 100%;
  min-height: var(--beat-h);
  display: grid; align-content: start;
  padding-inline: var(--gutter); text-align: center; pointer-events: none;
}
.scrub-beat {
  grid-area: 1 / 1; margin: 0 auto; max-width: 26ch;
  font-family: var(--font-display); font-weight: 700; font-size: clamp(22px, 2.6vw, 32px);
  letter-spacing: var(--tr-tight); line-height: 1.15; color: var(--ink);
  transition: opacity .45s var(--glide), transform .45s var(--glide);
}
/* round 30: the beats, the head and the callouts only start hidden once
   js/apple.js -> initScrub() has armed the chapter (`data-scrub-armed`);
   without it the first beat, the head and every callout simply stand in
   their final state. */
[data-scrub-armed] .scrub-beat:not(.is-on),
:not([data-scrub-armed]) > .scrub-sticky > .scrub-beats > .scrub-beat:not(:first-child) { opacity: 0; transform: translateY(8px); }
/* round 36: that second selector read the sticky, not the runway, as the
   thing that is armed, so on a desktop the second and third beats never
   showed at all; it reads the runway now */
.scrub-beat.is-on { opacity: 1; transform: none; }
@media (max-width: 900px) {
  /* Round 25, items 4 and 7: the sticky is static here and carries its own
     32px of padding, so the wrap's own 32 on top of it put the picture 64px
     under the cards against a --sec-y of 52. The padding is the air; the
     margin is 12. (The desktop pull is measured in js/apple.js; this branch
     never reaches it, because initScrub returns before fitLead on a phone.) */
  .scrub-wrap { height: auto; margin-top: var(--s-3); }
  /* flex-direction is `row` on desktop on purpose -- `.scrub-beats` is
     `position: absolute` there, so it never participates in that flex row,
     it just overlays the stage. On mobile it drops to `static` (below) so
     it CAN read as flow content -- which means it now DOES join the flex
     row unless this switches to `column`, and a row of [740px-native pad,
     full-width text] is what was overflowing the viewport before this. */
  .scrub-sticky { position: static; height: auto; flex-direction: column; padding-block: var(--s-6); }
  .scrub-bg { display: none; }
  .scrub-beats { position: static; width: 100%; min-height: 0; margin-top: var(--s-5); padding-inline: 0; }
  .scrub-beat { position: static; display: none; opacity: 1; transform: none; }
  .scrub-beat.is-on { display: block; }
  /* the till's `.pad-box` already sizes off a viewport-relative clamp
     (css/site.css), so it fits on its own -- the kitchen's `.imac-box`
     instead reads its parent's clientWidth (js/modules.js's fitBoxes(),
     `[data-base-w]`), and a flex item with the default `align-items:
     center` shrink-wraps to that box's own 762px content instead of the
     viewport, so fitBoxes had nothing narrower to measure against and the
     iMac bled off both edges of a phone screen. Give the chain a real,
     gutter-bound width to report. */
  .scrub-stage { width: 100%; padding-inline: var(--gutter); box-sizing: border-box; }
  .scrub-stage .dev-rig { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .scrub-beat { transition: opacity .2s linear; transform: none; }
  .scrub-bg { transform: none !important; }
}
/* ============================================================================
   Round 15, item 4: "Talk about Ctrl.", inside the till chapter.

   Ported from apple.com/apple-tv-4k's "Talk about control." (measured in
   r10/apple3-notes.md): the device holds still at a fixed y while a fixed
   column of short callouts fades in beside it, one per scroll stage, no
   transform on the copy, fade only. Ours lives inside `#scrub-till`'s own
   sticky so the page keeps exactly two CSS iPads (hero and till) instead of
   growing a third, which means one runway carries both the scrub (the first
   60 percent) and the callouts (the last 40 percent). js/apple.js ->
   initScrub().

   Apple's version connects copy to device by position alone. Ours draws a
   1px leader line, and it is INK rather than eggshell: this chapter's ground
   is eggshell, and an eggshell line on eggshell is not a line. Same call the
   round 14 cloud section made for its connectors.
   ========================================================================= */
/* Round 19, item 1. The sticky viewport is three reserved bands on desktop,
   not one centred stack: a head band (180px at 1440, 140 at 1024) held whether
   or not the head is showing, a 48px gap, the tablet centred in what is left,
   and the beat band at the foot. Round 15 floated the head and the device in
   one flex column, so the tablet's top edge crossed the headline for the whole
   of the scrub -- the band is what makes "never overlaps" a property of the
   layout rather than of where you happen to have stopped scrolling.

   The head sits at the BOTTOM of its band (`align-self: end`), because the top
   of the band is the top of the viewport and the nav pill is floating over it. */
.tac-head {
  position: static; z-index: 3;
  text-align: center; padding-inline: var(--gutter);
  transition: opacity .5s var(--glide), transform .5s var(--glide);
  pointer-events: none;
}
[data-scrub-armed] .tac-head:not(.is-on) { opacity: 0; transform: translateY(10px); }
.tac-head.is-on { opacity: 1; transform: none; }
.tac-eyebrow {
  margin: 0 0 10px;
  font-family: var(--font-display); font-weight: 600; font-size: 13px;
  letter-spacing: .12em; text-transform: uppercase; color: #FF6B3D;
}
.tac-head h3 {
  margin: 0;
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(30px, 3.6vw, 52px); letter-spacing: -0.04em;
  line-height: 1.04; padding-bottom: .08em;
  background-image: linear-gradient(180deg, #000000 0%, #2C2C2E 55%, #6E6E73 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
.tac-list { position: absolute; inset: 0; z-index: 3; margin: 0; padding: 0; list-style: none; pointer-events: none; }
.tac-c {
  position: absolute; width: clamp(190px, 17vw, 250px);
  display: grid; gap: 6px;
  transition: opacity .5s var(--glide), transform .5s var(--glide);
}
[data-scrub-armed] .tac-c:not(.is-on) { opacity: 0; transform: translateY(12px); }
.tac-c.is-on { opacity: 1; transform: none; }
.tac-c b { font-family: var(--font-display); font-weight: 700; font-size: 18px; line-height: 1.2; color: var(--ink); }
.tac-c span { font-size: 15px; line-height: 1.4; color: var(--ink-2); }
.tac-l { left: clamp(16px, 3vw, 56px); text-align: left; }
.tac-r { right: clamp(16px, 3vw, 56px); text-align: right; }
.tac-c[data-tac="0"], .tac-c[data-tac="2"] { top: 30%; }
.tac-c[data-tac="1"], .tac-c[data-tac="3"] { top: 56%; }
/* the leader: one hairline that draws out of the callout toward the tablet.
   scaleX from the callout's own inner edge, so it reads as being drawn
   rather than sliding in from somewhere. Round 19: it now STOPS at the
   tablet's rendered edge instead of running 29px past it. */
.tac-lead {
  position: absolute; top: 11px; display: block; height: 1px;
  width: var(--tac-lead, clamp(34px, 6vw, 96px)); background: var(--ink);
  opacity: .35; transform: scaleX(0);
  transition: transform .55s var(--glide) .12s;
}
.tac-l .tac-lead { left: 100%; margin-left: 24px; transform-origin: left center; }
.tac-r .tac-lead { right: 100%; margin-right: 24px; transform-origin: right center; }
.tac-c.is-on .tac-lead { transform: scaleX(1); }
/* while the callouts are up, the three scrub beats are not: the band below
   the tablet is the same strip of screen. The tablet itself no longer moves
   when they arrive (round 15 dropped it 7vh and scaled it to .94 to make room
   for the headline) -- the head has its own reserved band now, so there is
   nothing left for the device to get out of the way of. */
.scrub-sticky.is-tac .scrub-beats { opacity: 0; transition: opacity .4s var(--glide); }

/* ---- the banded sticky, desktop only ------------------------------------ */
@media (min-width: 901px) {
  .scrub-sticky:has(.tac-head) {
    --tac-band: clamp(140px, 12.5vw, 180px);
    --tac-gap: 48px;
    --tac-foot: var(--beat-h);
    /* `.pad-box` is 740 x 520 times --s, but what you SEE is `.pad` after
       `data-turn` rotates it: 730.5 x 543.3 per unit of --s, measured, and
       offset sideways by the rotation as well. Width is capped against 730.5
       so that "58 percent of the viewport" is the number a capture measures;
       height is budgeted against 520, because 520 is the room the
       untransformed box asks the grid row for. */
    /* Round 25, item 3: the tablet is budgeted against what it RENDERS and
       against the clearance the beat line is owed, not against the 520px
       its untransformed box asks the row for. `data-turn` leaves the pad
       550.95px tall per unit of --s once the rotation's lower corner is
       counted (measured: 643px at --s 1.1308, 20px of it above the stage
       and 35px below), and `.scrub-stage` is start-aligned in its row, so
       what is left under the pad is exactly --beat-clear. The beat text used
       to sit ON the tablet's contact shadow. */
    --beat-clear: 40px;
    --pad-s: min(tan(atan2(58vw, 730.5px)), 1.2320,
                 tan(atan2(calc(100vh - var(--tac-band) - var(--tac-gap) - var(--tac-foot)
                       - var(--beat-clear)), 551px)));
    /* These four are the tablet's rendered box inside the sticky. The values
       here are the arithmetic fallback; js/apple.js's fitTac() overwrites all
       four with the measured rect, because the rotation's sideways offset
       (17px at 1440) is not something a stylesheet can derive. */
    --pad-l: calc((100vw - 730.5px * var(--pad-s)) / 2);
    --pad-w: calc(730.5px * var(--pad-s));
    --pad-h: calc(543.3px * var(--pad-s));
    --pad-t: calc(var(--tac-band) + var(--tac-gap)
                  + (100vh - var(--tac-band) - var(--tac-gap) - var(--tac-foot) - var(--pad-h)) / 2);
    --tac-lead: 36px;
    --tac-gapx: 24px;
    --tac-rl: calc(var(--pad-l) - var(--tac-lead) - var(--tac-gapx));
    --tac-rr: calc(100vw - var(--pad-l) - var(--pad-w) - var(--tac-lead) - var(--tac-gapx));
    /* one width for both columns, taken from the tighter side, because the
       rotation puts the tablet 17px right of centre and two callout columns
       of visibly different widths read as a mistake rather than as a tilt. */
    --tac-w: min(300px, calc(min(var(--tac-rl), var(--tac-rr)) - 24px));
    display: grid; gap: 0;
    grid-template-columns: 100%;
    grid-template-rows: var(--tac-band) var(--tac-gap) 1fr var(--tac-foot);
    align-items: center; justify-items: center;
  }
  /* every in-flow child names its COLUMN as well as its row: two of them sit
     in row 4 and without the column a second, implicit 760px column opens up
     beside the first and drags the whole stack off centre. */
  .scrub-sticky:has(.tac-head) > .tac-head { grid-area: 1 / 1; align-self: end; width: 100%; }
  .scrub-sticky:has(.tac-head) > .scrub-stage { grid-area: 3 / 1; align-self: start; }
  .scrub-sticky:has(.tac-head) > .scrub-beats { grid-area: 4 / 1; align-self: start; }
  /* both overlays are out of flow, so they span the whole sticky on their own */
  .scrub-sticky:has(.tac-head) > .egg-amb,
  .scrub-sticky:has(.tac-head) > .tac-list { grid-area: 1 / 1 / -1 / 2; }

}
/* ---- 1200 and up: the two callout columns beside the tablet -------------- */
@media (min-width: 1200px) {
  /* 11px is the leader's own offset inside the callout, so what lands on the
     quarter line is the LINE, not the block's top edge. */
  .tac-c[data-tac="0"], .tac-c[data-tac="2"] { top: calc(var(--pad-t) + var(--pad-h) * .25 - 11px); }
  .tac-c[data-tac="1"], .tac-c[data-tac="3"] { top: calc(var(--pad-t) + var(--pad-h) * .75 - 11px); }
  /* placed off the tablet's edge inward, never off the window's edge outward,
     so the leader is always exactly --tac-lead long and always lands on the
     device. Left callouts read right, toward the tablet; right ones read left. */
  .scrub-sticky:has(.tac-head) .tac-l {
    width: var(--tac-w); left: calc(var(--tac-rl) - var(--tac-w)); right: auto; text-align: right;
  }
  .scrub-sticky:has(.tac-head) .tac-r {
    width: var(--tac-w); right: calc(var(--tac-rr) - var(--tac-w)); left: auto; text-align: left;
  }
}
/* ---- 901 to 1199: no side columns -------------------------------------- */
/* Under 1200px, a tablet at 58 percent of the window leaves about 120px a
   side, and a 120px callout is four short lines and a leader nobody can
   follow. The four stack into a 2 x 2 block under the tablet instead, in the
   band the beats vacate when the callouts arrive -- one band, two occupants,
   never both. The tablet gives up the height for it. */
@media (min-width: 901px) and (max-width: 1199px) {
  .scrub-sticky:has(.tac-head) {
    --tac-foot: 170px;
    /* here the tablet has real content directly under it rather than a beat
       line, so it is budgeted against its RENDERED height (543.3 per unit of
       --s) with 12px of clearance, not against `.pad-box`'s 520 -- otherwise
       the rotation's lower corner sits 8px into the first callout row. */
    --pad-s: min(tan(atan2(58vw, 730.5px)), 1.2320,
                 tan(atan2(calc(100vh - var(--tac-band) - var(--tac-gap) - var(--tac-foot)
                       - var(--beat-clear)), 551px)));
  }
  .scrub-sticky:has(.tac-head) > .tac-list {
    position: static; grid-area: 4 / 1; align-self: start; z-index: 3;
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    /* 100vw, not 100%: a percentage width on a grid item is resolved against
       the track, the track here is itself a percentage, and Chrome resolves
       that pair to zero. */
    gap: 16px 32px; width: min(760px, calc(100vw - var(--gutter) * 2));
  }
  .scrub-sticky:has(.tac-head) .tac-c {
    position: static; width: auto; text-align: left; left: auto; right: auto; top: auto;
  }
  .tac-lead { display: none; }
  .scrub-sticky:has(.tac-head) > .scrub-beats { grid-area: 4 / 1; align-self: start; }
}

/* a till bento of two cards (the third duplicated a callout above and went)
   centres on its own, the same way the three-card bentos do. */
@media (min-width: 901px) {
  .plus-bento:has(> .plus-card:nth-child(2):last-child) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    max-width: 640px; margin-inline: auto;
  }
}

/* phones: nothing pins, so the tablet stays in flow and the four callouts
   follow it as a plain 2-column grid, all four visible, no leaders. */
@media (max-width: 900px) {
  .tac-head {
    position: static; opacity: 1; transform: none; padding-inline: 0;
    margin-top: var(--s-5);
  }
  .tac-list {
    position: static; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 20px 16px; margin-top: var(--s-4); width: 100%;
  }
  .tac-c { position: static; width: auto; opacity: 1; transform: none; text-align: left; }
  .tac-lead { display: none; }
}
@media (max-width: 380px) {
  .tac-list { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .tac-head, .tac-c { opacity: 1; transform: none; transition: none; }
  .tac-lead { transform: scaleX(1); transition: none; }
  .scrub-sticky.is-tac .scrub-beats { opacity: 1; }
}


/* ---- B7: play/pause, on every autoplaying clip ----------------------------
   38px circle, bottom-right, 16px inset, a translucent dark fill with the
   site's own glass blur so it reads on any footage. Two inline SVG states
   swapped by opacity, keyed off a state class on the wrapper (never on the
   button itself, so any wrapper — `.hl-media-box`, `.hero-duo-media`,
   `.scrub-stage` — can host it without extra markup nesting). Mechanical
   timings (0.1s opacity, 0.2s transform), not springs — this is a control,
   not an entrance. */
.play-pause {
  position: absolute; right: 16px; bottom: 16px; z-index: 6;
  width: 38px; height: 38px; border-radius: 50%; border: 0; padding: 0; cursor: pointer;
  display: grid; place-items: center;
  background: rgba(0,0,0,.44);
  -webkit-backdrop-filter: blur(14px) saturate(1.6);
  backdrop-filter: blur(14px) saturate(1.6);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.14);
  color: #fff;
  transition: transform .2s var(--snap), background .2s var(--glide);
}
.play-pause svg { position: absolute; width: 15px; height: 15px; opacity: 0; transition: opacity .1s linear; }
.is-paused .play-pause .ic-play, .is-playing .play-pause .ic-pause { opacity: 1; }
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .play-pause { background: rgba(0,0,0,.86); backdrop-filter: none; -webkit-backdrop-filter: none; }
}
@media (prefers-contrast: more) {
  .play-pause { box-shadow: inset 0 0 0 1.5px #fff; }
}
.play-pause:hover { background: rgba(0,0,0,.6); }
.play-pause:active { transform: scale(.9); }
.play-pause:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 480px) { .play-pause { right: 12px; bottom: 12px; width: 34px; height: 34px; } .play-pause svg { width: 13px; height: 13px; } }
/* Round 19, item 3: on the till the bottom RIGHT of the screen is where the
   split lands ("Split evenly", then the two guest cards), so the control sat
   on top of Guest 2 for the whole last third of the clip. The bottom left of
   that screen is the menu rail below its last category and is empty in every
   frame, so the button goes there -- still in the frame's own corner, still a
   16px inset, never over a guest card. */
.scrub-stage .pad-screen > .play-pause { left: 16px; right: auto; }

/* ---- B11: stat callouts ----------------------------------------------------
   Apple's exact two-tier spec from the ipad-pro/macbook-pro audit: a 48px/
   600-weight number, a 14px/600-weight grey caption below it. Ported onto
   the dashboard chapter (the 12-second refresh, the 19 reports, the 02:00
   close — all real, already-stated numbers) and the offline tiles, which
   used to run a looser clamp(26px,...,38px) figure — tightened to the exact
   Apple size now that both live under one shared class. */
.stat-callouts { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 14px; margin-top: var(--s-7); }
.stat-callout { display: grid; gap: 4px; }
.stat-value {
  font-family: var(--font-display); font-weight: 600; font-size: 48px;
  letter-spacing: -0.144px; line-height: 1.08; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stat-caption { font-size: 14px; font-weight: 600; letter-spacing: -0.224px; color: var(--ink-2); }
@media (max-width: 700px) {
  /* Point 9: this component carries exactly 3 stats -- a 2-column wrap
     always orphans the third on its own row with empty space beside it.
     Apple's own mobile stat callouts stack to one column (verified against
     the ipad-pro capture in scratchpad/apple-study), so this does too. */
  .stat-callouts { grid-template-columns: 1fr; gap: var(--s-4); margin-top: var(--s-6); }
  .stat-value { font-size: 34px; }
}
/* point 10 superseded this: the offline tiles now carry their own larger
   64px/600/-0.02em value (css/apple.css's .offline-tile b rule, above),
   deliberately bigger than the 48px stat-callout pair since these are the
   chapter's own hero numbers, not an inline stat. Rule kept removed here on
   purpose so there is exactly one declaration to read, not two competing
   ones. */

/* ---- B6/B16: button and link micro-interactions ---------------------------
   Apple's own primary-CTA values, translated: a pill presses to .98 scale in
   0.12s (mechanical, not a spring — springs are reserved for entrances, per
   the apple-design skill's own rule), and a chevron-link's arrow slides 3px
   on hover. `.btn` already has its own hover lift in css/site.css; this only
   adds the press state and a focus ring where either was missing. */
.btn:active { transform: scale(.98); transition-duration: .12s; }
.btn-link, a.btn-link { display: inline-flex; align-items: center; gap: 6px; }
.btn-link .arw, .bx .arw, a .arw { display: inline-block; transition: transform .18s var(--snap); }
.btn-link:hover .arw, .bx:hover .arw, a:hover .arw { transform: translateX(3px); }
.btn:focus-visible, .btn-link:focus-visible, a.btn-link:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}

/* ---- B9: paddle arrows on the highlights rail, desktop only ---------------
   Apple's `.paddlenav`: 36px glass circles, rgba(210,210,215,.64) — ported
   to delEat's own neutral ramp at the same alpha. Dots stay the only
   pagination on phones (already the case, `.hl-pager`); these arrows are an
   addition for the pointer/keyboard-precise desktop case, not a replacement. */
.hl-rail-wrap { position: relative; }
.hl-arrow {
  position: absolute; top: 50%; z-index: 4; margin-top: -18px;
  width: 36px; height: 36px; border-radius: 50%; border: 0; cursor: pointer;
  display: grid; place-items: center; color: var(--ink);
  background: color-mix(in srgb, var(--n-300) 64%, transparent);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  transition: background-color .1s linear, opacity .1s linear, transform .2s var(--snap);
}
.hl-arrow svg { width: 15px; height: 15px; }
.hl-arrow:hover { background: color-mix(in srgb, var(--n-400) 70%, transparent); }
.hl-arrow:active { transform: translateY(-50%) scale(.92); margin-top: 0; top: 50%; }
.hl-arrow.prev { left: -18px; } .hl-arrow.next { right: -18px; }
.hl-arrow[disabled] { opacity: 0; pointer-events: none; }
.hl-arrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 900px) { .hl-arrow { display: none; } }

/* ---- B14: "Compare plans" — a link out, not an inline mega-table ---------
   Apple's comparison tables live off the product page, reached by one local
   -nav-style link; delEat's full comparison already lives on pricing.html,
   this just names the door on the home page trio too. */
.plans-compare { margin-top: var(--s-5); text-align: center; }

/* ---- icon sprite ------------------------------------------------------- */
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.ic { display: inline-block; width: 1em; height: 1em; stroke: currentColor; fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; vertical-align: -0.125em; }
.ic.filled { fill: currentColor; stroke: none; }

/* ---- Round 14, item 3: the icon has no tile ------------------------------
   Every glyph on the site is now naked: no ground, no border, no shadow,
   and bigger. The class name stays `.ic-tile` because it is written into
   index.html, tools/build-nav.py, tools/build-modules.py and a dozen
   context classes (.sv-ic, .pic-ic, .bx-obj, .mm2-ic, .rel-ic, .pg-ic)
   that only ever set `--ic-tile-s`; renaming it would have touched every
   one of those for no drawn difference.

   So `--ic-tile-s` changes meaning instead: it is the GLYPH's size, and the
   box is the glyph. 28px on cards and bento tiles, 22px in the mega menu
   and the other tight rows (`.sm`), 32px where a card used to take the 56px
   plate (`.lg`). Stroke 1.75 with round caps at every size, which is the
   sprite's 1.5 stepped up to hold its weight now that nothing sits behind
   it. Two inks: `#000` on eggshell and white, eggshell `#F7F3EE` on black.
   The one orange glyph per group is `.ic-key` (the cloud at the centre of
   the system bento, the selected mega-menu row, the Ask delEat sparkle). */
.ic-tile {
  --ic-tile-s: 28px;
  width: var(--ic-tile-s); height: var(--ic-tile-s); flex: none;
  border-radius: 0; display: grid; place-items: center;
  background: none; border: 0; box-shadow: none; color: #000000;
}
.ic-tile .ic {
  width: var(--ic-tile-s); height: var(--ic-tile-s);
  stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round;
}
.on-dark .ic-tile, .ic-tile.on-dark { background: none; color: var(--bone); }
/* the Product/Solutions menu popovers hang off header.nav.on-dark
   structurally but are always light glass cards -- undo the rule above
   inside them (source order breaks the tie since both are 2-class
   selectors in this same file), the same "local token reset" .plus-card
   uses above for an identical reason. */
.nav-menu .ic-tile, .mm-card .ic-tile { background: none; color: #000000; }
.ic-tile.sm { --ic-tile-s: 22px; }
.ic-tile.lg { --ic-tile-s: 32px; }
/* the one primary glyph in a group: the cloud at the centre of the system
   bento (.ic-key in the markup), the mega-menu row you are on (nav-menu.css),
   and every Ask delEat sparkle, which `:has()` finds without a class having
   to be written at twenty call sites. The glyphs are aria-hidden and always
   sit beside their own label, so the orange is decoration, not text. */
.ic-key, .ic-tile.ic-key, .on-dark .ic-tile.ic-key { color: #FF6B3D; }
.ic-tile:has(use[href="#ic-ask"]) { color: #FF6B3D; }
/* Round 25, item 13: not inside the mega menus. Twenty-seven ink glyphs and
   one orange one in the same column is what made the Product and Solutions
   panels read as two themes; the accent belongs where the glyph stands
   alone, not in a list. The selected row keeps its own orange (nav-menu.css),
   which is a state rather than a glyph. */
.nav-menu .ic-tile:has(use[href="#ic-ask"]),
.mm-card .ic-tile:has(use[href="#ic-ask"]) { color: #000000; }

/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  ROUND 10 (2026-09-11)                                                   ║
   ║  The hero, the bento, the card fragments and the app-icon tiles.         ║
   ╚══════════════════════════════════════════════════════════════════════════╝ */

/* ============================================================================
   Round 13 — the hero, rebuilt from Parth's own mockup.

   The round 12 scene is gone: no film, no wordmark ring, no glass card, no
   scroll cue, no 190vh sticky runway and no white statement over the footage.
   What is left is one in-flow section exactly one viewport tall, black, with
   the type stack centred in the free space above a product frame that is
   pinned to the bottom edge and clipped by the fold. That single change takes
   about 90vh off the page.

   Nothing here is driven by JavaScript. The intro is five CSS animations on a
   shared easing, fired once with `animation-fill-mode: forwards`; the ambient
   motion is two very slow glow blobs, the LIVE dot and one table breathing.
   Reduced motion drops all of it into the settled state.
   ========================================================================= */
.hero13 {
  position: relative;
  min-height: 100vh; height: 100vh;
  overflow: hidden;
  /* edge to edge UNDER the nav, as the round 12 scene was: the nav is sticky
     with its own height, so the section starts at the top of the page and the
     pill floats over it. The nav keeps its normal dark glass here, which is
     why there is no `is-over-hero` state any more. */
  margin-top: calc(-1 * var(--nav-h));
  background: #000000; color: var(--bone);
  display: flex; flex-direction: column; align-items: center;
  justify-content: flex-start;
  /* Round 18: the type stack starts 8vh under the nav and every step below
     it is tighter, because the device group needs the rest of the fold. */
  padding: calc(var(--nav-h) + 8vh) var(--gutter) 0;
  --h13-ease: cubic-bezier(.16, 1, .3, 1);
}
/* Round 25, item 10: the hero is 112vh on a desktop and the type sits 4vh
   under the nav rather than 8. Both exist for one reason: the device group
   was 1,131px wide inside a 1,440px window, which is what "too small, too
   squeezed" was. The extra 12vh and the 36px off the top go straight into
   the height k is solved against, and k is what the group's width is. The
   composition runs past the fold exactly as apple.com/os/macos does; the
   hero's own overflow is still the crop. */
@media (min-width: 901px) {
  .hero13 { min-height: 112vh; height: 112vh; padding-top: calc(var(--nav-h) + 4vh); }
}

/* ---- the brand ground. A wide, very faint radial behind the type, plus two
   600px blobs that drift 40px over 18s. This is the whole of the hero's
   background: no photograph, no film, no illustration. ------------------- */
.h13-air { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.h13-glow {
  position: absolute; left: 0; right: 0; top: 0; height: 600px;
  background: radial-gradient(circle at center, rgba(255,107,61,.07) 0%, transparent 65%);
}
.h13-blob {
  position: absolute; width: 600px; height: 600px; border-radius: 50%;
  filter: blur(120px); opacity: .12;
  background: radial-gradient(circle at center, rgba(255,107,61,1) 0%, rgba(255,107,61,0) 70%);
}
.h13-blob-a { left: calc(50% - 460px); top: -120px; }
.h13-blob-b { left: calc(50% - 140px); top: 40px; }
@media (prefers-reduced-motion: no-preference) {
  .h13-blob-a { animation: h13driftA 18s var(--glide) infinite alternate; }
  .h13-blob-b { animation: h13driftB 18s var(--glide) infinite alternate; }
}
@keyframes h13driftA { from { transform: none; } to { transform: translate3d(40px, -28px, 0); } }
@keyframes h13driftB { from { transform: none; } to { transform: translate3d(-34px, 22px, 0); } }

/* ---- the type stack. `flex: 1 0 auto` is deliberate: the stack never
   shrinks, so the frame below it is the thing the fold eats into. ------- */
.h13-stack {
  /* Round 57: 3, above the trio (2), whose film box reaches up under the
     CTA row */
  position: relative; z-index: 3;
  /* Round 17, item 3: the stack no longer grows. It takes its own height and
     everything below the CTAs belongs to the trio, which is the only way the
     three devices can be whole AND end 40px above the fold. */
  flex: 0 1 auto; width: 100%; max-width: 900px;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  text-align: center; padding-bottom: 0;
}
.h13-eyebrow {
  margin: 0 0 10px;
  font-family: var(--font-display); font-weight: 600; font-size: 13px;
  line-height: 1.2; letter-spacing: .12em; text-transform: uppercase;
  color: #FF6B3D;
}
.h13-head {
  margin: 0;
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(40px, 6vw, 84px);
  letter-spacing: -0.04em;
  /* Round 14, item 1: the "g" of "night." was being cut. With
     `background-clip: text` the paint stops at the element's own padding box,
     and at line-height .95 that box is shorter than the glyphs, so every
     descender lost its fill. 1.04 gives the line box room and .08em of
     padding gives the LAST line's descender somewhere to land. Nothing on
     this page may clip it: .hero13's own `overflow: hidden` is a viewport
     away from the type. */
  line-height: 1.04; padding-bottom: .08em;
  /* Round 53: the same cut, sideways. `letter-spacing` is applied AFTER the
     last character too, so a negative track pulls the element's right edge
     0.045em INSIDE the last glyph's ink -- and `background-clip: text` paints
     nothing outside that edge, so the "s" of "is" lost a vertical slice of
     its right side (measured at 1728: box right 1364, the s's ink carrying
     on past it). Padding gives the paint box room on both sides; the equal
     negative margin gives the room back to the layout, so the margin box is
     the width it always was. That matters twice over: `.h13-stack` centres
     this with `align-items: center`, and the line breaks are the markup's
     own <br>, so neither the centring nor the wrap may move. Longhands, not
     the shorthand: `padding-bottom` above is the descender fix and stands. */
  padding-left: .07em; padding-right: .07em;
  margin-left: -.07em; margin-right: -.07em;
  /* the vertical gradient fill from the mockup: white into the two greys the
     rest of this page already uses for dark-ground type. */
  background-image: linear-gradient(180deg, #FFFFFF 0%, var(--hl-1) 52%, var(--hl-2) 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
.h13-sub {
  margin: clamp(12px, 1.8vh, 20px) auto 0; max-width: 520px;
  font-size: 16px; font-weight: 400; line-height: 1.5;
  color: #A1A1A6;
}
.h13-ctas {
  margin-top: 10px;
  display: flex; align-items: center; gap: clamp(16px, 2vw, 30px);
}
.h13-text {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-display); font-weight: 600; font-size: 16px;
  color: var(--bone); text-decoration: none;
}
.h13-chev { width: 15px; height: 15px; transition: transform .3s var(--h13-ease); }
.h13-text:hover .h13-chev { transform: translate3d(4px, 0, 0); }
/* Round 54, item 3: the price, in the hero's fine print, with the site's
   text link and chevron. */
.h13-fine { margin: 14px auto 0; max-width: 520px; font-size: 13px; line-height: 1.5; color: var(--hl-2); text-wrap: pretty; }
.h13-fine-link { display: inline-flex; align-items: center; gap: 3px; font-weight: 600; color: var(--bone); white-space: nowrap; }
.h13-fine-link .h13-chev { width: 12px; height: 12px; }
.h13-key {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 46px; padding: 0 24px; border-radius: 999px;
  background: #FF6B3D; color: #FFFFFF; text-decoration: none;
  font-family: var(--font-display); font-weight: 600; font-size: 16px;
  box-shadow: 0 10px 30px rgba(255,107,61,.32);
  transition: transform .3s var(--h13-ease), box-shadow .3s var(--h13-ease);
}
.h13-key:hover { transform: translate3d(0, -1px, 0); box-shadow: 0 14px 38px rgba(255,107,61,.42); }

/* Round 14, item 2: the particle field. One canvas at the hero's own size, no
   fixed layer, nothing outside this section, and no layer opacity any more --
   the alpha lives in the paint (dots .55, links up to .16) so the field is
   actually visible on black. z-index 1 puts it between the glow blobs (0) and
   the type (2). js/apple.js -> heroWeb(). */
.h13-web {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%; pointer-events: none;
}

/* ---- Round 15, item 2: the device trio. Measured off apple.com/os/macos
   (r10/apple3-notes.md): MacBook left and cut by the left edge, iPhone small
   and dead centre in front, iPad right and cut by the right edge, all three
   running past the fold. `.hero13`'s own overflow: hidden is the crop, which
   is why none of these boxes has a height of its own.

   `--k` is a unitless ratio (100vw divided by a px length), so the whole
   composition scales with the window instead of stepping at a breakpoint and
   the offsets keep their relationship to one another at every width. ---- */
.h13-trio {
  /* Round 16, item 4: the trio was cut too hard -- at 1440 only 29 percent
     of the phone's screen and half the tablet's survived the fold. The band
     is taller now, so the group sits higher in the hero, and the two inner
     devices drop their downward offsets. The MacBook's own keyboard is still
     the thing the bottom edge eats, like the macOS reference. */
  /* Round 18: the group fills the hero's width -- 94vw, 3 percent of clear
     margin a side, capped at 1,600px so it stops growing past 1,702px of
     viewport and centres. What made room for that is a different bottom
     rule: round 17 kept all three devices WHOLE 40px above the fold, which
     at 900px of viewport left the group at 70 percent of the width. Now only
     the three SCREENS have to clear the fold; the MacBook's keyboard and
     base run past it and are cut by the hero's own overflow, exactly as the
     macOS reference is cut.

     The group's natural box in --k units, the MacBook's top-left as origin:
       MacBook   x    0     -> 760      y   0    -> 634.6  (screen ends 316)
       iPhone    x  593.6   -> 766.5    y  10.1  -> 385
       iPad      x  715     -> 1255.2   y   5.4  -> 385
     so --gw 1255.2, --gh 634.6, and --gs 385 -- the lowest edge that MUST
     stay above the fold (the iPad's and iPhone's own bottoms, level with one
     another so the two read as standing on one surface; the MacBook's screen
     ends higher, at 316). --gc is the clearance that edge keeps.

     The iPad now overlaps the MacBook's right edge by 45 units instead of
     sitting 165 units clear of it, and the iPhone straddles the join --
     593.6 to 766.5 covers the last 166 units of the MacBook and the first
     51.5 of the iPad -- so the silhouette is continuous and there is no hole
     left in the middle for the eye to fall through. Everything is drawn
     against the group's own centre, 627.6, rather than the 50% anchor.

     fitTrio() in js/apple.js solves k = min(availW / --gw, (box height -
     --gc) / --gs) and then writes --gb, which is where the group's BOTTOM
     falls relative to this box's bottom and is normally negative. The clamp
     and the --gb below are the no-script answer to the same sum. */
  position: relative; z-index: 2; flex: 1 1 auto; min-height: 0;
  width: 100%; height: auto;
  pointer-events: none;
  /* Round 23, item 3: --gtop is the clear air between the CTA row and the
     top of the device group, and it is a FLOOR rather than an exact figure:
     where the hero has more room than the group needs, the spare still
     splits evenly above and below, as it has since round 17. At 1440 the
     floor is what binds, so k is solved against the height the group has
     left once the gap is taken, and the group comes down accordingly. */
  --gtop: 72px;
  --gw: 1255.2; --gh: 634.6; --gs: 385; --gc: 8px;
  /* Round 25, item 10: the group asks for 114 percent of the window instead
     of 94 percent of it capped at 1,600px, so the MacBook runs off the left
     edge and the iPad off the right by up to 7 percent a side -- inside the
     brief's 8, and measured against the screens rather than the bodies: at
     the full 7 the MacBook keeps 91 percent of its screen and the iPad 88.5,
     both past the 85 the brief asks for. Where the height binds first (most
     900px-tall windows) the bleed comes out smaller and the group simply
     reaches the window's own edges, which is still the point. */
  /* Round 30: `calc(length / length)` is typed arithmetic, which an engine
     without it treats as invalid at computed-value time, and every width
     below would then fall back to auto. A plain number is the default and
     the typed solve replaces it only where @supports says it parses;
     js/apple.js -> fitTrio() overwrites both with a measured figure anyway. */
  --k: 1;
  --gb: calc(112vh - 478px - 72px - 634.6px * var(--k));
}
@supports (width: calc(100vw / 1px * 1px)) {
  .h13-trio { --k: clamp(.40, min(calc(114vw / 1255.2px), calc((112vh - 478px - 72px - 8px) / 385px)), 1.9); }
}
.h13-dev { position: absolute; left: 50%; top: auto; bottom: var(--gb); }
/* the entry animation lives on `.h13-dev` and the pointer parallax on the
   child, so the two transforms never fight for the same property. */
.h13-devin { transform: translate3d(var(--pxx, 0px), var(--pxy, 0px), 0); }
.h13-dev-mac { z-index: 1; margin-left: calc(-627.6px * var(--k)); }
.h13-dev-mac img { display: block; width: calc(760px * var(--k)); height: auto; }
.h13-dev-pad { z-index: 2; margin-left: calc(87.4px * var(--k)); bottom: calc(var(--gb) + 249.6px * var(--k)); }
.h13-dev-ph  { z-index: 3; margin-left: calc(-34px * var(--k)); bottom: calc(var(--gb) + 249.6px * var(--k)); }
.h13-trio .pad-box { --s: calc(.73 * var(--k)); }
.h13-trio .ph-box  { --s: calc(.44 * var(--k)); }
/* the real captures, filling each screen from the top: what the fold keeps is
   the head of the dashboard, which is the part worth reading. */
.h13-trio .pad-screen img, .h13-trio .ph-screen img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
}
.h13-trio .pad-screen, .h13-trio .ph-screen { background: #000; }

/* Round 30, item 1, still the rule: the hero FAILS OPEN. Nothing in it is
   hidden unless an inline script at the top of the hero has checked that the
   document is visible, that reduced motion is off and that the APIs exist,
   and that script also fails open on a timer. */
/* ---- Round 57: the opening film's states live in index.html's own head
   (<style id="r57-hero">), because they have to hold from the very first
   paint, before this sheet has arrived. ------------------------------------ */
@media (prefers-reduced-motion: no-preference) {
  /* the pointer parallax (js/apple.js heroTrio) glides */
  .h13-devin { transition: transform .9s var(--h13-ease); }
}
/* ---- Round 17, item 2: the headline failsafe. The round 16 shimmer set
   `animation` on `.h13-head.is-shimmer`, which REPLACED the h13pop shorthand
   and with it h13pop's `forwards` fill, so the base rule's own `opacity: 0`
   came back and the headline vanished about a second after it arrived. Two
   guards now, and either one alone is enough: `is-shimmer` declares its own
   opacity (below, at the shimmer), and `is-lit` is written by script at
   4.4s on every path, so whatever the intro did the headline is at full
   opacity by 4.5s and stays. This rule sits BEFORE the shimmer on purpose:
   equal specificity, so with both classes the shimmer's animation still
   runs and only its opacity is inherited from here. ---------------------- */
.h13-head.is-lit { animation: none; opacity: 1; transform: none; }
@keyframes h13rise { from { opacity: 0; transform: translate3d(0,15px,0); } to { opacity: 1; transform: none; } }
@keyframes h13pop  { from { opacity: 0; transform: translate3d(0,20px,0) scale(.97); } to { opacity: 1; transform: none; } }


/* ---- phones. The same stack, a smaller headline, the CTAs stacked, and the
   three devices composed into one group a phone wide: MacBook behind left,
   iPad behind right, iPhone in front of both, the group cropped by the fold
   and by both side edges. 40px offsets on the way in instead of 140. ---- */
@media (max-width: 900px) {
  .hero13 { min-height: 100svh; height: 100svh; padding-inline: 12px; }
  /* the brief's 12vw puts "Closes the night." one line over the measure at
     every phone width (measured: 360px needed against 350px of room at 390),
     which orphans "night." on a third line. 11.6vw clears it at 320, 360,
     390 and 430 with the stack's own side padding dropped. */
  .h13-head { font-size: clamp(37px, 11.6vw, 64px); }
  .h13-sub { max-width: 42ch; }
  .h13-ctas { flex-direction: column; gap: 14px; width: 100%; }
  .h13-text { order: 2; }
  .h13-key { order: 1; width: 100%; max-width: 320px; }
  .h13-stack { padding-inline: 0; }
  /* the same three devices, composed as one group a phone wide (round 15's
     arrangement), whole now rather than cut by both side edges. Natural box in
     --k units: x -300 to 309.7 (609.7 wide), y 24 to 385.5 (361.5 tall), the
     iPhone's own bottom being the group's. */
  /* Round 18: the same whole-device group, at 100 percent of the width less
     16px a side. --gs is the group's own height here, because on a phone
     every device stays whole above the fold and --gc is that 24px gap. */
  .h13-trio {
    height: auto;
    --gtop: 40px;
    --gw: 609.7; --gh: 361.5; --gs: 361.5; --gc: 24px; --gb: 24px;
    --k: .55;
  }
  @supports (width: calc(100vw / 1px * 1px)) {
    .h13-trio { --k: clamp(.30, min(calc((100vw - 32px) / 609.7px), calc((100vh - 470px) / 361.5px)), 1.2); }
  }
  .h13-dev-mac { margin-left: calc(-304.9px * var(--k)); bottom: calc(var(--gb) + 111px * var(--k)); }
  .h13-dev-mac img { width: calc(300px * var(--k)); }
  .h13-dev-pad { margin-left: calc(5.2px * var(--k)); bottom: calc(var(--gb) + 140.9px * var(--k)); }
  .h13-dev-ph  { margin-left: calc(-79.9px * var(--k)); bottom: var(--gb); }
  /* the phone composition keeps its own scales, unchanged from round 17. */
  .h13-trio .pad-box { --s: calc(.405 * var(--k)); }
  .h13-trio .ph-box  { --s: calc(.382 * var(--k)); }
  /* the phones keep whole devices and get the same assembly with smaller
     offsets (Round 54, item 3). */
  .h13-dev-mac { --dev-y: 26px; }
  .h13-dev-pad { --dev-x: -28px; }
  .h13-dev-ph  { --dev-x: 28px; }
}
/* ---- Round 57b: the whole opening inside the first screen (desktop).
   Apple keeps the product inside the fold, so from 901px up the film stage,
   and the settled trio it hands to, end at least 24px above the fold, with
   the headline, the sub, both buttons and the price line above them. Every
   step of the copy block is sized off the window's height as well as its
   width, so a short window gives up type before it gives up the product:
     --h13-pt   air between the nav and the eyebrow
     --h13-f    the headline (two lines of 1.0 plus .1em for the descenders)
     --h13-m1   headline to sub, --h13-m2 sub to buttons, --h13-m3 buttons
                to the price line
     --h13-gap  the price line to the top of the devices
   The trio is then solved against what is left above the fold: --gs is the
   film's own foot (the group's 634.6 units plus the 40 the stage keeps under
   it), --gf the 24px it keeps clear of the fold, and fitTrio() (js/apple.js
   and the inline copy in index.html) measures the copy block and writes the
   k that fits. The stage is 16:9 in trio units, so its height sets k and its
   width follows; the DOM trio and the film share k, so the seam holds.
   The headline stays the hero's largest element: it is the page's largest
   contentful paint (about 13.1 F squared of text), and once the whole
   MacBook is inside the fold its picture (760 x 634.6 units, k squared)
   would take that over the moment the film hands to it, at 4.6s. So k is
   also capped at F / --gl: at 204 the headline keeps 13 percent more area
   than the MacBook at every size. The headline's curve (16.9vh - 46px) is
   set so that cap and the fold agree within a few pixels from 700 to 1440px
   of height on landscape windows, so neither the product nor the type is
   short-changed.
   --h13-cb is the no-script estimate of where the copy block ends (eyebrow
   25.6, sub 48, buttons 46, price line 19.5 = 139.1px of fixed lines). The
   hero stays 112vh: the 12vh under the fold is the room the desktop
   handover (js/scroll.js) scales the trio into. The Round 23 tablet-range
   rule and the Round 17 short-window headline rule are folded into this. */
@media (min-width: 901px) {
  .hero13 {
    --h13-pt: clamp(8px, 2.2vh, 40px);
    --h13-f: clamp(48px, min(10vw, 16.9vh - 46px), 200px);
    --h13-m1: clamp(10px, 1.5vh, 20px);
    --h13-m2: clamp(14px, 2.2vh, 28px);
    --h13-m3: clamp(8px, 1.2vh, 16px);
    --h13-gap: clamp(20px, 2.8vh, 44px);
    --h13-cb: calc(var(--nav-h) + var(--h13-pt) + 2.1 * var(--h13-f) + var(--h13-m1) + var(--h13-m2) + var(--h13-m3) + var(--h13-gap) + 139.1px);
    padding-top: calc(var(--nav-h) + var(--h13-pt));
  }
  .h13-stack { padding-bottom: var(--h13-gap); }
  .h13-sub { margin-top: var(--h13-m1); }
  .h13-ctas { margin-top: var(--h13-m2); }
  .h13-fine { margin-top: var(--h13-m3); }
  .h13-trio {
    --gtop: 0px; --gs: 674.6; --gf: 24px; --gl: 204;
    --k: .5;
    --gb: calc(112vh - var(--h13-cb) - 634.6px * var(--k));
  }
  @supports (width: calc(100vw / 1px * 1px)) {
    .h13-trio { --k: clamp(.30, min(calc((100vw - 48px) / 1255.2px), calc((100vh - 24px - var(--h13-cb)) / 674.6px), calc(var(--h13-f) / 204px)), 1.9); }
  }
}
/* (Round 58's one-laptop hero, and its film, gave way to the phone hero: see
   the Round 58 hero block at the end of this file.) */
@media (prefers-reduced-motion: reduce) {
  .h13-eyebrow, .h13-head, .h13-sub, .h13-ctas, .h13-fine, .h13-dev,
  .h13-blob-a, .h13-blob-b {
    animation: none; transform: none;
  }
  .h13-eyebrow, .h13-head, .h13-sub, .h13-ctas, .h13-fine, .h13-dev { opacity: 1; }
  .h13-devin { transition: none; transform: none; }
  .h13-web { display: none; }
  .h13-blob { opacity: .12; }
}

/* ============================================================================
   Points 1 and 10 — the dashboard pair photograph, and the bento under it.
   ========================================================================= */
.dash-pair { margin: var(--s-7) auto 0; max-width: 1180px; }
.dash-pair img { display: block; width: 100%; height: auto; }

.dbento {
  margin-top: var(--s-7);
  display: grid; gap: 12px;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  grid-auto-rows: minmax(178px, auto);
}
/* explicit placement, so document order stays readable and the grid still
   tiles with no holes: 4 rows of 6. */
.db-1 { grid-column: 1 / 4; grid-row: 1 / 3; }
.db-2 { grid-column: 4 / 7; grid-row: 1 / 2; }
.db-3 { grid-column: 4 / 7; grid-row: 2 / 3; }
.db-7 { grid-column: 1 / 3; grid-row: 3 / 5; }
.db-4 { grid-column: 3 / 5; grid-row: 3 / 4; }
.db-5 { grid-column: 5 / 7; grid-row: 3 / 4; }
.db-6 { grid-column: 3 / 5; grid-row: 4 / 5; }
.db-8 { grid-column: 5 / 7; grid-row: 4 / 5; }

.db {
  position: relative; overflow: hidden; isolation: isolate;
  display: flex; flex-direction: column; justify-content: flex-end; gap: 8px;
  padding: 22px 22px 20px; min-width: 0;
  border-radius: var(--r-lg);
  background: #1C1C1E;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06);
}
/* the one type ramp: a big value and a 15px caption, nothing else. */
.db-v {
  font-family: var(--font-display); font-weight: 700; font-size: 40px;
  line-height: 1.1; letter-spacing: -0.03em; padding-bottom: .08em;
  background: var(--grad-text); -webkit-background-clip: text; background-clip: text;
  color: transparent; width: fit-content;
}
.db-tall .db-v { font-size: 56px; }
.db-c { font-size: 15px; font-weight: 400; line-height: 1.42; color: #A1A1A6; max-width: 26ch; }
.db-line { font-size: 15px; font-weight: 400; line-height: 1.45; color: var(--bone); max-width: 30ch; }
.db-3 { justify-content: center; gap: 14px; }

/* ---- Round 11, item C: the tiles are filled ------------------------------
   Every tile's element is a real block that owns the tile, not a decorative
   crop in the corner, and every one animates once on entry (js/apple.js ->
   tileMotion adds .is-in, then .is-done). The trade bars keep an ambient
   nudge after that; nothing else repeats.
   ------------------------------------------------------------------------ */
.db-frag { position: absolute; z-index: 0; pointer-events: none; }
.db-note {
  font-family: var(--font-mono); font-size: 12px; color: #A1A1A6;
  margin: 0; letter-spacing: .01em;
}
.db-lab { color: var(--bone); font-weight: 600; font-size: 15px; margin: 0; }

/* 1 — trade by hour. The plot owns the tile's lower two thirds. */
.db-1 { justify-content: flex-start; }
.db-bars { display: flex; flex-direction: column; gap: 8px; flex: 1 1 auto; min-height: 132px; margin-top: 6px; }
.db-bars-hd { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.db-bars-hd b { font-size: 13px; font-weight: 600; color: var(--bone); }
.db-bars-hd i {
  font-style: normal; font-size: 11px; color: #A1A1A6;
  border: 1px solid #3A3A3C; border-radius: 999px; padding: 2px 9px;
}
.db-bars-plot { display: flex; align-items: flex-end; gap: 4px; flex: 1 1 auto; min-height: 96px; }
.dbar { position: relative; flex: 1 1 0; min-width: 0; height: 100%; border-radius: 5px; background: rgba(255,255,255,.07); }
.dbar i {
  position: absolute; left: 0; right: 0; bottom: 0; height: 100%; border-radius: 5px;
  background: linear-gradient(180deg, #FF8A5B 0%, #FF5A1F 100%);
  transform: scaleY(0); transform-origin: bottom;
  transition: transform .75s var(--glide);
  transition-delay: calc(var(--i, 0) * 40ms);
}
.db.is-in .dbar i { transform: scaleY(var(--v, 0)); }
.db-bars-ax { display: flex; justify-content: space-between; font-family: var(--font-mono); font-size: 10px; color: #A1A1A6; }
.db-bars-ax i { font-style: normal; }

/* 2 — this week over last, three ranges, labelled. */
.db-2 { justify-content: flex-start; }
.db-range { display: flex; align-items: flex-end; gap: clamp(10px, 2vw, 26px); flex: 1 1 auto; min-height: 104px; margin-top: 8px; }
.dr-col {
  flex: 1 1 0; min-width: 0; display: grid; grid-template-columns: 1fr 1fr; align-items: end;
  column-gap: 6px; height: 100%;
}
.dr-bar {
  height: calc(var(--v, 0) * 100%); min-height: 6px; border-radius: 5px 5px 0 0;
  transform: scaleY(0); transform-origin: bottom;
  transition: transform .7s var(--glide); transition-delay: calc(var(--i, 0) * 60ms);
}
.db.is-in .dr-bar { transform: scaleY(1); }
.dr-last { background: rgba(255,255,255,.16); }
.dr-now  { background: linear-gradient(180deg, #FF8A5B 0%, #FF5A1F 100%); }
.dr-col em {
  grid-column: 1 / -1; font-style: normal; font-size: 11px; color: #A1A1A6;
  margin-top: 8px; text-align: center; white-space: nowrap;
}

/* 3 — drill down: a small card that opens into a page. */
.db-3 { justify-content: flex-start; gap: 10px; }
.db-drill { position: relative; flex: 1 1 auto; min-height: 112px; margin-top: 4px; }
.dd-card, .dd-sheet {
  position: absolute; left: 0; top: 0;
  border-radius: 14px; background: #2C2C2E; box-shadow: inset 0 0 0 1px rgba(255,255,255,.08);
}
.dd-card {
  width: 132px; padding: 12px 14px; display: grid; gap: 2px;
  transition: opacity .4s var(--glide), transform .55s var(--glide);
}
.dd-card b { font-size: 13px; font-weight: 600; color: var(--bone); }
.dd-card i { font-style: normal; font-size: 11px; color: #A1A1A6; }
.dd-sheet {
  right: 0; bottom: 0; padding: 12px 14px 10px; display: grid; gap: 8px; align-content: start;
  transform: scale(.42); transform-origin: top left; opacity: 0;
  transition: opacity .45s var(--glide) .28s, transform .62s var(--glide) .28s;
}
.db.is-in .dd-card { opacity: 0; transform: scale(.86); }
.db.is-in .dd-sheet { opacity: 1; transform: scale(1); }
.dd-sheet-hd { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.dd-sheet-hd b { font-size: 13px; font-weight: 600; color: var(--bone); }
.dd-sheet-hd i { font-style: normal; font-size: 11px; color: #A1A1A6; }
.dd-line { width: 100%; height: 56px; display: block; }
.dd-path { stroke-dasharray: 1; stroke-dashoffset: 1; }
.db.is-in .dd-path { stroke-dashoffset: 0; transition: stroke-dashoffset 1s var(--glide) .55s; }

/* 4 — menu engineering: twelve dishes, the orange one last. */
.db-4 { justify-content: flex-start; gap: 8px; }
.db-scatter { position: relative; flex: 1 1 auto; min-height: 138px; padding: 6px 4px 18px 34px; }
.dsc-plot {
  position: relative; display: block; width: 100%; height: 100%;
  border-left: 1px solid rgba(255,255,255,.14); border-bottom: 1px solid rgba(255,255,255,.14);
}
.dsc-dot {
  position: absolute; left: var(--x); bottom: var(--y);
  width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; border-radius: 999px;
  background: rgba(255,255,255,.42);
  opacity: 0; transform: scale(.3);
  transition: opacity .3s var(--glide), transform .42s var(--glide);
  transition-delay: calc(var(--i, 0) * 60ms);
}
.dsc-dot.is-hero { background: #FF6B3D; width: 12px; height: 12px; margin: -6px 0 0 -6px; transition-delay: 780ms; }
.db.is-in .dsc-dot { opacity: 1; transform: none; }
.db.is-in .dsc-dot.is-hero { animation: dscPulse 2.4s var(--glide) 1.1s 2; }
@keyframes dscPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,107,61,.45); }
  45%      { box-shadow: 0 0 0 7px rgba(255,107,61,0); }
}
.dsc-ax-y, .dsc-ax-x { position: absolute; font-style: normal; font-size: 10px; color: #A1A1A6; letter-spacing: .02em; }
.dsc-ax-y { left: 0; top: 50%; transform: translateY(-50%) rotate(-90deg); transform-origin: center; }
.dsc-ax-x { left: 34px; right: 0; bottom: 0; text-align: center; }

/* 5 — Ask delEat: the question, the orb searching (Round 60), then the answer. */
.db-frag-chat { position: static; display: grid; gap: 7px; justify-items: start; margin-bottom: 4px; flex: 1 1 auto; align-content: end; }
.db-5 { justify-content: flex-start; }
.dbq, .dba {
  font-size: 13px; line-height: 1.38; border-radius: 14px; padding: 9px 12px; max-width: 96%;
}
.dbq { background: #2C2C2E; color: var(--bone); border-bottom-left-radius: 5px;
       opacity: 0; transform: translateY(6px); transition: opacity .4s var(--glide), transform .4s var(--glide); }
.db.is-in .dbq { opacity: 1; transform: none; }
/* the answer has no bubble until it starts to stream */
.dba:empty { display: none; }
.dba { background: var(--o-500); color: var(--n-900); font-weight: 500; justify-self: end; border-bottom-right-radius: 5px; max-width: 88%; }
.dbsrc {
  font-size: 11px; font-weight: 600; color: #A1A1A6; letter-spacing: .01em;
  border: 1px solid #3A3A3C; border-radius: 999px; padding: 3px 9px;
  opacity: 0; transition: opacity .4s var(--glide);
}
.db.is-done .dbsrc { opacity: 1; }

/* 6 — all outlets, ranked, relative bars only. */
.db-6 { justify-content: flex-start; }
.db-rank { display: grid; gap: 7px; flex: 1 1 auto; align-content: end; margin-top: 8px; }
.drk { display: grid; grid-template-columns: minmax(0, 1fr); gap: 4px; }
.drk b { font-size: 12px; font-weight: 500; color: #A1A1A6; }
.drk i {
  display: block; height: 6px; border-radius: 999px;
  background: linear-gradient(90deg, #FF5A1F 0%, #FF8A5B 100%);
  width: calc(var(--v, 0) * 100%);
  transform: scaleX(0); transform-origin: left;
  transition: transform .7s var(--glide); transition-delay: calc(var(--i, 0) * 70ms);
}
.db.is-in .drk i { transform: scaleX(1); }

@media (prefers-reduced-motion: reduce) {
  .dbar i, .dr-bar, .drk i { transition: none; transform: scaleY(var(--v, 1)); }
  .drk i { transform: scaleX(1); }
  .dbar i { transform: scaleY(var(--v, 1)); }
  .dsc-dot { opacity: 1; transform: none; transition: none; animation: none; }
  .dd-card { opacity: 0; }
  .dd-sheet { opacity: 1; transform: scale(1); transition: none; }
  .dd-path { stroke-dashoffset: 0; }
  .dbq, .dbsrc { opacity: 1; transform: none; transition: none; }
}

.db-photo { padding: 0; justify-content: flex-end; }
.db-photo .db-media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.db-photo::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to top, rgba(0,0,0,.72) 0%, rgba(0,0,0,.28) 38%, rgba(0,0,0,0) 66%);
}
.db-over {
  position: relative; z-index: 2; margin: 0; padding: 22px;
  font-family: var(--font-display); font-weight: 600; font-size: 21px; line-height: 1.22;
  letter-spacing: var(--tr-head); color: #FFFFFF; max-width: 18ch;
}
.db-over-sub {
  display: block; margin-top: 6px;
  font-family: var(--font-ui); font-weight: 400; font-size: 13px; line-height: 1.4;
  letter-spacing: 0; color: rgba(255,255,255,.72);
}

@media (max-width: 1024px) {
  .dbento { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .dr-col em { font-size: 10px; }
  .db-1 { grid-column: 1 / 3; grid-row: 1 / 3; }
  .db-2 { grid-column: 3 / 5; grid-row: 1 / 2; }
  .db-3 { grid-column: 3 / 5; grid-row: 2 / 3; }
  .db-4 { grid-column: 1 / 3; grid-row: 3 / 4; }
  .db-5 { grid-column: 3 / 5; grid-row: 3 / 4; }
  .db-6 { grid-column: 1 / 3; grid-row: 4 / 5; }
  .db-7 { grid-column: 3 / 5; grid-row: 4 / 6; }
  .db-8 { grid-column: 1 / 3; grid-row: 5 / 6; }
}
@media (max-width: 700px) {
  .dbento { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: minmax(132px, auto);
            grid-auto-flow: row dense; }
  .db { padding: 18px; border-radius: 20px; }
  .db-v { font-size: 34px; }
  .db-tall .db-v { font-size: 40px; }
  .db-over { padding: 18px; font-size: 18px; }
  .db-1, .db-5, .db-7, .db-8 { grid-column: 1 / 3; grid-row: auto; }
  .db-2, .db-3, .db-4, .db-6 { grid-column: span 1; grid-row: auto; }
  .db-7 { min-height: 210px; }
  .db-8 { min-height: 176px; }
  /* Round 11: every element is in flow now, so the only thing a phone needs
     is a floor under each tile tall enough for its element plus its copy. */
  .db-1 { min-height: 300px; }
  .db-2 { min-height: 262px; }
  .db-3 { min-height: 238px; }
  .db-4 { min-height: 222px; }
  .db-5 { min-height: 226px; }
  .db-6 { min-height: 230px; }
  .db-bars-plot { min-height: 84px; }
  .db-range { min-height: 88px; gap: 8px; }
  .dr-col em { font-size: 10px; white-space: normal; line-height: 1.25; }
  .db-scatter { min-height: 92px; }
  .db-drill { min-height: 104px; }
  .dd-card { width: 116px; }
  .db-over-sub { font-size: 12px; }
}

/* ============================================================================
   Point 2 — the three till cards each carry the piece of the till they are
   about, drawn in markup and cropped by the card's own radius.
   ========================================================================= */
.plus-bento.has-frag .plus-card {
  position: relative; overflow: hidden; isolation: isolate;
  padding-bottom: 92px;
}
.plus-bento.has-frag .plus-card > *:not(.pcf) { position: relative; z-index: 1; }
.pcf {
  position: absolute; z-index: 0; right: -14%; bottom: -15%; width: 74%; min-width: 190px;
  display: grid; gap: 5px; padding: 10px 11px;
  border-radius: 12px; background: var(--n-0);
  border: 1px solid var(--n-200);
  box-shadow: 0 10px 26px rgba(0,0,0,.14);
  font-size: 11px; line-height: 1.3; color: var(--n-700);
}
.pcf-hd { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.pcf-hd b { font-size: 11.5px; font-weight: 650; color: var(--n-900); }
.pcf-hd i { font-style: normal; font-size: 10px; color: var(--n-500); }
.pcf-row { display: flex; align-items: center; gap: 6px; }
.pcf-tick {
  flex: none; width: 12px; height: 12px; border-radius: 4px;
  border: 1.4px solid var(--n-300); background: var(--n-0);
}
.pcf-row.is-on .pcf-tick {
  border-color: var(--o-500); background: var(--o-500);
  background-image: linear-gradient(transparent, transparent);
  box-shadow: inset 0 0 0 1.5px var(--o-500);
  position: relative;
}
.pcf-row.is-on .pcf-tick::after {
  content: ""; position: absolute; left: 3px; top: .5px; width: 3.5px; height: 6.5px;
  border: solid var(--n-900); border-width: 0 1.6px 1.6px 0; transform: rotate(42deg);
}
.pcf-seg {
  display: grid; grid-auto-flow: column; gap: 2px; margin-top: 2px;
  padding: 2px; border-radius: 8px; background: var(--n-100);
}
.pcf-seg b {
  font-size: 10px; font-weight: 600; text-align: center; padding: 4px 2px;
  border-radius: 6px; color: var(--n-600);
}
.pcf-seg b.on { background: var(--n-0); color: var(--n-900); box-shadow: var(--lift-1); }
.pcf-line { display: flex; justify-content: space-between; gap: 10px; }
.pcf-line em { font-style: normal; font-family: var(--font-mono); font-size: 10.5px; color: var(--n-900); }
.pcf-tot { border-top: 1px solid var(--n-200); padding-top: 4px; margin-top: 1px; font-weight: 650; }
.pcf-tot span, .pcf-tot em { color: var(--n-900); font-weight: 650; }
.pcf-tog { font-style: normal; font-size: 10px; color: var(--n-600); display: inline-flex; align-items: center; gap: 5px; }
.pcf-tog s { text-decoration: none; width: 22px; height: 13px; border-radius: 999px; background: var(--o-500); position: relative; }
.pcf-tog s::after { content: ""; position: absolute; top: 1.5px; right: 1.5px; width: 10px; height: 10px; border-radius: 999px; background: var(--n-0); }
@media (max-width: 700px) {
  /* a fragment needs a card wider than a 2-up column at 390px: the bento
     that carries one goes single-column on phones. The plain three-card
     bentos (kitchen, pocket) are untouched and stay 2-up. */
  .plus-bento.has-frag { grid-template-columns: 1fr; }
  .plus-bento.has-frag .plus-card { padding-bottom: 96px; }
  .pcf { min-width: 0; width: 58%; right: -10px; bottom: -10px; font-size: 10.5px; }
}

/* ============================================================================
   Point 3 — the offline tiles: one ramp (40/700 gradient value, 15/400
   caption) and one element each, cropped at the tile's bottom right.
   ========================================================================= */
.offline-tiles { gap: 12px; }
.offline-tile {
  border-radius: var(--r-lg);
  background: #1C1C1E; border: 0;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06);
  justify-content: flex-start; min-height: 196px;
}
.offline-tile::before { display: none; }
.offline-tile b {
  font-family: var(--font-display); font-weight: 700; font-size: 40px; line-height: 1.1;
  letter-spacing: -0.03em; padding-bottom: .08em;
  background: var(--grad-text); -webkit-background-clip: text; background-clip: text;
  color: transparent; width: fit-content;
}
.offline-tile.has-crop b { font-size: 40px; }
.offline-tile b .fn-ref, .offline-tile b .fn-ref a { -webkit-text-fill-color: #A1A1A6; color: #A1A1A6; }
.offline-tile p { font-size: 15px; font-weight: 400; line-height: 1.42; color: #A1A1A6; max-width: 24ch; }
/* the crop sits under the copy, bleeding off the bottom right, rather than
   beside it -- at 40px the two-word values ("Any browser", "Replay-safe")
   need the tile's full width to stay on one line. */
.offline-tile.has-crop { padding-right: 24px; padding-bottom: 124px; min-height: 272px; }
.offline-tile .ot-crop {
  right: -10px; bottom: -10px; display: grid; gap: 4px;
  filter: drop-shadow(0 12px 22px rgba(0,0,0,.5));
}
@media (max-width: 700px) {
  .offline-tile { min-height: 168px; padding: 20px; }
  /* Round 10 fix: two columns at 320px leaves 96px of text width, and a flat
     32px ran "browser" straight off the tile edge. The value tracks the
     viewport below about 421px and holds 32px above it. */
  .offline-tile b, .offline-tile.has-crop b { font-size: clamp(23px, 7.6vw, 32px); }
  .offline-tile.has-crop { padding-right: 18px; padding-bottom: 118px; min-height: 216px; }
}
/* "0 orders lost" — the queue chip */
.offline-tile .ot-crop.ot-queue {
  width: 190px; right: -10px; bottom: -10px; padding: 10px 12px; border-radius: 10px 0 0 0;
  background: #2C2C2E; box-shadow: inset 0 0 0 1px rgba(255,255,255,.08);
  font-size: 11px; line-height: 1.45; color: #A1A1A6;
}
.ot-queue .otq-hd { display: flex; align-items: center; gap: 6px; color: var(--bone); font-weight: 600; }
.otq-dot { width: 7px; height: 7px; border-radius: 999px; background: #D9A400; flex: none; }
.ot-queue .otq-row { display: block; }
.ot-queue .otq-row.dim { color: #A1A1A6; }
/* "02:00" — a slip, its business day above and where it counts below */
.offline-tile .ot-crop.ot-slip { width: 168px; text-align: center; bottom: 6px; right: 16px; }
.ot-slip .ots-day { font-family: var(--font-mono); font-size: 11px; color: #A1A1A6; }
.ot-slip .ots-paper {
  display: grid; gap: 3px; background: var(--n-0); color: var(--n-800);
  font-family: var(--font-mono); font-size: 12px; line-height: 1.5;
  padding: 9px 11px 11px; border-radius: 4px 4px 0 0; text-align: left;
}
.ot-slip .ots-paper .r { display: flex; justify-content: space-between; gap: 8px; }
.ot-slip .ots-paper .r.tot { font-weight: 700; border-top: 1px dashed var(--n-300); padding-top: 4px; margin-top: 2px; }
.ot-slip .ots-note { font-size: 11px; color: #A1A1A6; }
/* "Replay-safe" — one order card, ticked once */
.offline-tile .ot-crop.ot-order {
  width: 176px; right: -10px; bottom: -10px; padding: 11px 12px; border-radius: 10px 0 0 0;
  background: #2C2C2E; box-shadow: inset 0 0 0 1px rgba(255,255,255,.08);
  font-size: 11px; color: #A1A1A6;
}
.ot-order .oto-hd { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.ot-order .oto-hd b { font-size: 12px; font-weight: 650; color: var(--bone);
  background: none; -webkit-text-fill-color: currentColor; letter-spacing: 0; }
.oto-tick { width: 18px; height: 18px; border-radius: 999px; background: var(--o-500); color: var(--n-900); display: grid; place-items: center; flex: none; }
.oto-tick svg { width: 12px; height: 12px; }
.ot-order .oto-row { display: block; margin-top: 4px; }
/* "Any browser" — a generic browser window, the till inside it */
.ot-win {
  width: 62%; min-width: 200px; max-width: 280px; height: 152px;
  bottom: -24px; border-radius: 10px 0 0 0; overflow: hidden;
  background: #2C2C2E; box-shadow: inset 0 0 0 1px rgba(255,255,255,.1);
  display: block; padding: 0;
}
.ot-win .otw-bar { display: flex; align-items: center; gap: 5px; padding: 7px 9px 0; }
.ot-win .otw-bar i { width: 7px; height: 7px; border-radius: 999px; background: #6E6E73; flex: none; }
.ot-win .otw-tab {
  margin-left: 6px; font-size: 9.5px; color: #A1A1A6; background: #1C1C1E;
  border-radius: 5px 5px 0 0; padding: 3px 10px;
}
.ot-win .otw-url {
  display: block; margin: 5px 9px 7px; padding: 3px 9px; border-radius: 999px;
  background: #1C1C1E; color: #A1A1A6; font-family: var(--font-mono); font-size: 9.5px;
}
.ot-win img { display: block; width: 100%; height: auto; }
/* "UAE VAT" — the receipt, retyped to the ramp */
.offline-tile .ot-crop.ot-receipt {
  width: 168px; right: 16px; bottom: -14px; transform: rotate(3deg); transform-origin: bottom right;
  background: var(--n-0); color: var(--n-800); font-family: var(--font-mono);
  font-size: 12px; line-height: 1.5; padding: 10px 11px 14px; border-radius: 4px 4px 0 0;
  display: grid; gap: 2px;
}
.ot-receipt .r { display: flex; justify-content: space-between; gap: 8px; }
.ot-receipt .r.tot { font-weight: 700; }
.ot-receipt .r.mid { justify-content: center; font-size: 11px; }
.ot-receipt hr { border: 0; border-top: 1px dashed var(--n-300); margin: 4px 0 2px; width: 100%; }
/* Round 11, item F: two of the six are photographs now, one is a clock.
   ------------------------------------------------------------------------ */
/* the photograph tiles: the image fills the lower right two thirds and is
   masked out toward the copy, so the tile keeps one ground and no seam. */
.offline-tile.ot-shot { position: relative; overflow: hidden; }
.offline-tile .ot-photo {
  position: absolute; right: 0; bottom: 0; width: 80%; height: 72%;
  z-index: 0; pointer-events: none;
  -webkit-mask-image: linear-gradient(105deg, transparent 0%, #000 34%, #000 100%),
                      linear-gradient(to bottom, transparent 0%, #000 30%, #000 100%);
  mask-image: linear-gradient(105deg, transparent 0%, #000 34%, #000 100%),
              linear-gradient(to bottom, transparent 0%, #000 30%, #000 100%);
  -webkit-mask-composite: source-in; mask-composite: intersect;
}
.offline-tile .ot-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.offline-tile.ot-shot > b, .offline-tile.ot-shot > p { position: relative; z-index: 2; }
.offline-tile .ot-chip {
  position: absolute; left: 24px; bottom: 24px; z-index: 3;
  display: inline-flex; align-items: center; gap: 7px; flex-wrap: wrap;
  padding: 8px 12px; border-radius: 10px;
  background: rgba(20,20,22,.78); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.10);
  font-size: 11.5px; line-height: 1.3; color: #A1A1A6;
}
.offline-tile .ot-chip b {
  font-family: var(--font-ui); font-size: 11.5px; font-weight: 600; letter-spacing: 0;
  background: none; -webkit-text-fill-color: currentColor; color: var(--bone);
}
.offline-tile .ot-chip-btn {
  font-family: var(--font-ui); font-size: 11.5px; font-weight: 600;
  background: var(--o-500); color: var(--n-900); box-shadow: none; border-radius: 999px;
  padding: 7px 14px; -webkit-backdrop-filter: none; backdrop-filter: none;
}
.offline-tile.ot-shot { padding-bottom: 84px; }

/* the clock tile: the value IS the clock, in tabular numerals, and the note
   under it fades in once the minute has turned. */
.offline-tile.ot-clockt { justify-content: center; gap: 12px; }
.offline-tile.has-crop b.ot-clock, .offline-tile b.ot-clock {
  font-size: clamp(62px, 7.6vw, 110px); line-height: .92;
  font-variant-numeric: tabular-nums; letter-spacing: -0.04em;
}
.offline-tile .ot-when {
  margin-top: auto; font-size: 13px; color: #A1A1A6;
  opacity: 0; transform: translateY(6px);
  transition: opacity .5s var(--glide), transform .5s var(--glide);
}
.offline-tile.is-done .ot-when { opacity: 1; transform: none; }
.offline-tile.ot-clockt { padding-bottom: 28px; }
/* Round 25, item 9: the clock sits in a one-column square now, not a third
   of the row, so 110px of tabular numerals no longer fits the measure. */
.offline-tile.ot-sq.has-crop b.ot-clock, .offline-tile.ot-sq b.ot-clock { font-size: clamp(46px, 4.4vw, 64px); }
.offline-tile.ot-sq.ot-clockt { padding-right: 20px; }

/* "Replay-safe" — bigger card, and the tick draws itself in. */
.offline-tile .ot-crop.ot-order { width: 212px; font-size: 12px; padding: 13px 14px; }
.ot-order .oto-row.dim { color: #A1A1A6; }
.oto-tick { width: 22px; height: 22px; }
.oto-tick svg { width: 14px; height: 14px; }
.oto-tick path { stroke-dasharray: 1; stroke-dashoffset: 1; }
.offline-tile.is-done .oto-tick path { stroke-dashoffset: 0; transition: stroke-dashoffset .5s var(--glide) .12s; }

/* "Any browser" — the same window, larger. */
.ot-win { width: 70%; min-width: 230px; max-width: 320px; height: 178px; }

@media (prefers-reduced-motion: reduce) {
  .offline-tile .ot-when { opacity: 1; transform: none; transition: none; }
  .oto-tick path { stroke-dashoffset: 0; }
}

@media (max-width: 700px) {
  .offline-tile .ot-crop { transform: scale(.78); transform-origin: bottom right; }
  .offline-tile .ot-crop.ot-receipt { transform: scale(.78) rotate(3deg); }
  .ot-win { min-width: 0; width: 80%; height: 150px; }
  .offline-tile.has-crop b.ot-clock, .offline-tile b.ot-clock { font-size: clamp(40px, 12vw, 58px); }
  .offline-tile.ot-shot { padding-bottom: 74px; }
  .offline-tile .ot-chip { left: 18px; bottom: 18px; font-size: 10.5px; padding: 6px 10px; }
  .offline-tile .ot-chip b { font-size: 10.5px; }
  .offline-tile .ot-photo { width: 74%; height: 60%; }
}

/* ============================================================================
   Point 1 — the kitchen scrub, and the floor plan, in a plain 28px frame
   with no device at all.
   ========================================================================= */
.scrub-stage:has(> .scrub-frame) {
  width: 100%; padding-inline: var(--gutter); box-sizing: border-box;
  display: flex; justify-content: center;
}
.scrub-frame, .ui-frame {
  position: relative; width: 100%; overflow: hidden;
  border-radius: 28px; background: var(--n-900);
  box-shadow: var(--lift-4), inset 0 0 0 1px rgba(255,255,255,.08);
}
/* Round 19, item 6: the frame is LIGHT now and holds a dark screen, rather
   than being a dark box with a recording of a light screen inside it. --r-lg
   and the card shadow, a 16px surround, and a ratio the four-column ticket
   grid actually fills (1200 x 620, where the recording's own was 1200 x 749
   and left a quarter of the screen empty). */
.scrub-frame {
  width: min(1120px, 100%, calc((100vh - var(--beat-h) - 140px) * 1200 / 749));
  aspect-ratio: 1200 / 749;
  border-radius: var(--r-lg);
  background: var(--n-0);
  box-shadow: var(--lift-3), inset 0 0 0 1px rgba(0,0,0,.07);
  padding: 16px; box-sizing: border-box;
}
.scrub-frame .scrub-video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* a frame holding the live display is not a window onto a recording of a
   fixed size: it is as tall as four columns of tickets make it, so the ratio
   and the viewport-height cap above both come off. */
.scrub-frame:has(.kds2) { width: min(1120px, 100%); aspect-ratio: auto; }

/* ============================================================================
   Round 19, item 6: the kitchen display, one component, three places.

   `.kds2` is the whole screen: the dark surface, its header row and the
   ticket grid. `.kt-dark` is just the ticket styling, for a container that
   already owns its own chrome (the pocket phone). Both draw the same card, so
   the KDS reads the same in the kitchen chapter, on the `#screens` tab and in
   the phone. Ageing is the 4px left stripe and nothing else: green under five
   minutes, amber five to twelve, red over twelve, taken from the elapsed time
   printed on the ticket (`.age-2` / `.age-3`, the classes the markup already
   carried for the light version's border colour).
   ========================================================================= */
.kds2 {
  --k-surface: #1C1C1E;
  --k-card:    #262629;
  --k-line:    rgba(255,255,255,.09);
  --k-ink:     #F5F5F7;
  --k-ink-2:   #9C9CA1;
  --k-green:   #34C38F;
  --k-amber:   #E8A317;
  --k-red:     #E8503A;
  width: 100%; box-sizing: border-box;
  background: var(--k-surface); color: var(--k-ink);
  border-radius: 12px; padding: 18px 20px 16px;
  display: flex; flex-direction: column; gap: 16px;
  font-family: var(--font-ui); letter-spacing: -0.004em;
  container-type: inline-size;
}
.kds2-hd { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex: 0 0 auto; }
.kds2-hd b { display: block; font-size: 19px; font-weight: 700; letter-spacing: -.02em; line-height: 1.2; }
.kds2-sub { display: flex; align-items: center; gap: 7px; margin-top: 4px; font-size: 14px; color: var(--k-ink-2); }
.kds2-live { width: 6px; height: 6px; border-radius: 50%; background: var(--k-green); flex: 0 0 auto; }
.kds2-seg { display: inline-flex; gap: 2px; padding: 3px; border-radius: 999px; background: rgba(255,255,255,.06); }
.kds2-seg b { font-size: 13px; font-weight: 600; line-height: 1; color: var(--k-ink-2); padding: 7px 14px; border-radius: 999px; }
.kds2-seg b.on { background: rgba(255,255,255,.13); color: var(--k-ink); }
.kds2 > .kds { flex: 0 0 auto; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; align-items: stretch; }
.kds2-foot { flex: 0 0 auto; margin: 0; font-size: 13px; line-height: 1.45; color: var(--k-ink-2); }

.kds2 .tkt, .kt-dark .tkt {
  background: var(--k-card);
  border: 1px solid var(--k-line); border-left: 4px solid var(--k-green);
  border-radius: 10px; overflow: hidden;
  display: flex; flex-direction: column; padding: 13px 14px 14px;
}
.kds2 .tkt.age-2, .kt-dark .tkt.age-2 { border-left-color: var(--k-amber); }
.kds2 .tkt.age-3, .kt-dark .tkt.age-3 { border-left-color: var(--k-red); }
.kds2 .tkt .th, .kt-dark .tkt .th { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; padding: 0; }
.kds2 .tkt .th b, .kt-dark .tkt .th b { font-size: 15px; font-weight: 700; text-transform: lowercase; letter-spacing: -.01em; color: var(--k-ink); }
.kds2 .tkt .th .ag, .kt-dark .tkt .th .ag { font-family: var(--font-mono); font-size: 13px; font-weight: 700; color: var(--k-green); }
.kds2 .tkt.age-2 .th .ag, .kt-dark .tkt.age-2 .th .ag { color: var(--k-amber); }
.kds2 .tkt.age-3 .th .ag, .kt-dark .tkt.age-3 .th .ag { color: var(--k-red); }
.kds2 .tkt .tm, .kt-dark .tkt .tm { padding: 4px 0 0; font-family: var(--font-mono); font-size: 12px; color: var(--k-ink-2); }
/* the station, as a pill */
.kds2 .tkt .st, .kt-dark .tkt .st {
  align-self: flex-start; margin-top: 9px;
  font-size: 12px; font-weight: 600; line-height: 1; letter-spacing: .02em;
  padding: 6px 11px; border-radius: 999px;
  background: rgba(255,255,255,.07); color: var(--k-ink-2);
}
.kds2 .tkt ul, .kt-dark .tkt ul {
  list-style: none; margin: 11px 0 0; padding: 0; display: grid; gap: 7px; align-content: start;
}
.kds2 .tkt li, .kt-dark .tkt li { font-size: 15px; line-height: 1.3; display: grid; grid-template-columns: 22px 1fr; gap: 8px; color: var(--k-ink); }
.kds2 .tkt li b, .kt-dark .tkt li b { font-family: var(--font-mono); font-weight: 700; color: var(--k-ink-2); }
.kds2 .tkt li em, .kt-dark .tkt li em { display: block; font-style: normal; font-size: 13px; line-height: 1.35; color: var(--k-ink-2); margin-top: 3px; }
.kds2 .tkt .ta, .kt-dark .tkt .ta {
  margin-top: auto; padding: 12px 0 0; display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
/* "All ready" is a tick and a word, not a button: it is a state, and the one
   thing on the card you press is Bump. */
.kds2 .tkt .ta b:not(.go), .kt-dark .tkt .ta b:not(.go) {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 600; color: var(--k-ink-2);
  background: none; border: 0; padding: 0; border-radius: 0;
}
.kds2 .tkt .ta b:not(.go)::before, .kt-dark .tkt .ta b:not(.go)::before {
  content: ""; width: 9px; height: 5px; flex: 0 0 auto;
  border-left: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
  transform: rotate(-45deg) translate(1px, -1px);
}
.kds2 .tkt .ta b.go, .kt-dark .tkt .ta b.go {
  font-size: 13px; font-weight: 700; color: #fff;
  background: var(--accent); border: 0; border-radius: 999px; padding: 7px 16px; text-align: center;
}
/* the beat the scrub is on: 2 lights the ready state on the oldest ticket,
   3 bumps it off the pass and the three that are left take the room. */
[data-beat="1"] .kds2 .tkt.age-3 .ta b:not(.go) { color: var(--k-green); }
[data-beat="1"] .kds2 .tkt.age-3 {
  border-color: rgba(52,195,143,.5); border-left-color: var(--k-red);
  background: #2C2C2F; box-shadow: 0 0 0 1px rgba(52,195,143,.28), 0 10px 26px rgba(0,0,0,.4);
}
[data-beat="1"] .kds2 .tkt.age-3 .ta b.go { box-shadow: 0 0 0 4px rgba(255,107,61,.24); }
[data-beat="2"] .kds2 .tkt.age-3 { opacity: 0; transform: translateX(28px) scale(.97); }
/* the column count does NOT change when a ticket is bumped. Reflowing four
   columns into three re-measures every card and grew the frame by 223px
   mid-scrub; the three that are left hold their places and the fourth leaves
   the slot it was in, which is what the pass actually looks like. */
.kds2 .tkt { transition: opacity .45s var(--glide), transform .45s var(--glide), border-color .3s linear; }
/* two columns below 820, which is where four cards stop holding a dish name
   on one line -- and two, not one, all the way down to a 390px phone. */
@container (max-width: 820px) { .kds2 > .kds { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* the threshold is the container's CONTENT box, and a 390px phone leaves the
   component 298px of it, so 300 was one pixel too generous and phones were
   getting a single column. */
@container (max-width: 260px) { .kds2 > .kds { grid-template-columns: minmax(0, 1fr); } }
@container (max-width: 420px) {
  .kds2 { padding: 14px 14px 12px; gap: 12px; }
  .kds2-hd b { font-size: 16px; }
  .kds2-sub { font-size: 12.5px; }
  .kds2-seg b { font-size: 11.5px; padding: 6px 10px; }
  .kds2 > .kds { gap: 8px; }
  .kds2 .tkt { padding: 11px 11px 12px; }
  .kds2 .tkt .th b { font-size: 13px; }
  .kds2 .tkt .th .ag { font-size: 11.5px; }
  .kds2 .tkt .tm { font-size: 10.5px; }
  .kds2 .tkt .st { font-size: 10.5px; padding: 5px 8px; margin-top: 7px; }
  .kds2 .tkt ul { margin-top: 9px; gap: 6px; }
  .kds2 .tkt li { font-size: 13px; grid-template-columns: 16px 1fr; gap: 6px; }
  .kds2 .tkt li em { font-size: 11.5px; }
  .kds2 .tkt .ta { padding-top: 10px; flex-direction: column; align-items: flex-start; gap: 8px; }
  .kds2 .tkt .ta b.go { font-size: 12px; padding: 7px 14px; width: 100%; }
  .kds2 .tkt .ta b:not(.go) { font-size: 12px; }
  .kds2-foot { font-size: 12px; }
}
/* nothing pins on a phone, so the frame stops being a fixed-ratio window and
   is simply as tall as the tickets make it. */
@media (max-width: 900px) {
  .scrub-frame:has(.kds2) { width: 100%; padding: 12px; }
  .scrub-frame > .kds2 { padding: 14px 14px 12px; }
  .kds2-hd { flex-wrap: wrap; gap: 10px; }
  .kds2-seg b { padding: 6px 10px; }
}
@media (prefers-reduced-motion: reduce) {
  .kds2 .tkt, .kds2 > .kds { transition: none; }
}
/* the `#screens` tab: the panel IS the screen, so the component takes the
   panel's own radius rather than drawing a second one inside it. */
.sc-panel > .kds2 { border-radius: inherit; padding: 20px 22px 18px; }
/* the panel is 900px inside a wider `.sc-fit-wrap`, and the bone showing in
   that gap was invisible only while every panel was itself bone. */
.sc-panel:has(> .kds2) { background: #1C1C1E; }
.sc-fit-wrap:has(.sc-panel.is-on > .kds2) { background: #1C1C1E; }
/* the pocket phone's kitchen view: same tickets, same colours, so the KDS
   reads as one product on a 390px screen and on a 1120px one. */
.ph-view.v-kitchen { background: #1C1C1E; }
.v-kitchen .ph-hd h3 { color: #F5F5F7; }
.v-kitchen .ph-hd .sub { color: #9C9CA1; }
.v-kitchen .ph-hd .live { background: #34C38F; }
.v-kitchen .ph-hd .ui-btn {
  background: rgba(255,255,255,.09); border-color: rgba(255,255,255,.14); color: #F5F5F7;
}
.ph-kds.kt-dark { --accent-kds: var(--accent); }
.kt-dark .tkt { --k-card: #262629; --k-line: rgba(255,255,255,.09); --k-ink: #F5F5F7; --k-ink-2: #9C9CA1;
  --k-green: #34C38F; --k-amber: #E8A317; --k-red: #E8503A; }
/* three tickets have to fit one phone screen, and the station pill is 30px of
   new card, so the phone runs the same component one notch tighter. */
.ph-kds.kt-dark .tkt { padding: 11px 12px 12px; }
.ph-kds.kt-dark .tkt .st { margin-top: 7px; padding: 5px 9px; font-size: 11px; }
.ph-kds.kt-dark .tkt ul { margin-top: 9px; }
.ph-kds.kt-dark .tkt .ta { padding-top: 10px; }
.ui-frame { background: var(--n-0); box-shadow: var(--lift-3), inset 0 0 0 1px rgba(0,0,0,.07); }
.ui-frame > .inner { display: block; width: 100%; }

/* ============================================================================
   Round 14, item 3 — the app-icon tiles are gone. Round 10's point 5 put a
   two-stop gradient plate, a top highlight and a hairline edge under every
   glyph on this page, and round 12 cycled six grounds around the system
   bento. Parth wants the glyph on its own, larger, everywhere: no ground,
   no border, no shadow. `main.app-icons` keeps its class (the card ramp
   below still hangs off it) but carries no plate rules any more; the base
   `.ic-tile` above is the whole of it now.
   ========================================================================= */

/* ---- the one card ramp: title 21px, body 15px, everywhere on this page. */
.app-icons .plus-card .pc-t b { font-size: 21px; font-weight: 600; line-height: 1.2; min-height: 0; }
.app-icons .plus-card .pc-t small { font-size: 15px; line-height: 1.4; }
.app-icons .dash-new-card b { font-size: 21px; }
@media (max-width: 700px) {
  .app-icons .plus-card .pc-t b { font-size: 18px; }
  .app-icons .plus-card .pc-t small { font-size: 14px; }
}

/* ============================================================================
   Round 11, item H — the cash-up chapter. One white card on eggshell holding
   the cash-up screen, the three points beside it. The counts type in and the
   total counts up once, on entry (js/apple.js -> tileMotion).
   ========================================================================= */
/* Round 25, item 8: one column. The three points that used to stand beside
   the card are three cards under the lede now, so a second track here would
   only be the empty half of the section Parth was looking at. */
#chapter-cashup .section-head { max-width: 62rem; }
.cashup .cu-in {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: clamp(24px, 3.4vw, 56px); align-items: start;
  margin-top: var(--s-7); max-width: 62rem;
}
.cu-card {
  background: var(--n-0); border-radius: var(--r-lg);
  padding: clamp(20px, 2.2vw, 30px);
  box-shadow: var(--lift-3), inset 0 0 0 1px rgba(0,0,0,.055);
}
.cu-hd {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding-bottom: var(--s-4); border-bottom: 1px solid var(--n-200);
}
.cu-hd b { font-family: var(--font-display); font-weight: 700; font-size: 21px; letter-spacing: var(--tr-tight); }
.cu-hd span { font-size: 13px; color: var(--ink-3); }
.cu-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px;
  margin-top: var(--s-5);
}
.cu-den {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  background: var(--surface); border-radius: 12px; padding: 11px 13px;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.045);
}
.cu-den i {
  font-style: normal; font-family: var(--font-mono); font-size: 12px; color: var(--ink-3);
}
.cu-den em {
  font-style: normal; font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 17px; font-weight: 600; color: var(--ink);
}
.cu-coins i { font-family: var(--font-ui); }
.cu-sums { margin-top: var(--s-5); border-top: 1px solid var(--n-200); padding-top: var(--s-4); display: grid; gap: 8px; }
.cu-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 15px; color: var(--ink-2); }
.cu-row b {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-size: 19px; font-weight: 650; color: var(--ink);
}
.cu-total { font-size: 30px !important; letter-spacing: -0.02em; }
.cu-var { padding-top: 8px; border-top: 1px dashed var(--n-300); }
.cu-var b { color: var(--ink); transition: color .45s var(--glide); }
.cu-card.is-done .cu-var b { color: var(--ok-ink); }
.cu-card.is-done .cu-var span { color: var(--ok-ink); }

@media (max-width: 900px) {
  .cashup .cu-in { grid-template-columns: 1fr; }
}
@media (max-width: 520px) {
  .cu-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .cu-den { padding: 9px 11px; }
  .cu-den em { font-size: 15px; }
  .cu-total { font-size: 26px !important; }
}

/* ============================================================================
   Round 12, item 4 — the word reveal, ported from oryzo.ai.

   Words are lit one at a time as the block crosses the viewport: the leading
   words at full strength, the trailing ones at a quarter, the boundary
   walking through the sentence with scroll. No mask, no blur, no motion,
   nothing pins. js/apple.js -> wordReveal() writes one number per word.
   ========================================================================= */
.wr .wr-w {
  display: inline-block;
  will-change: opacity;
}
/* reduced motion, and any block the observer never reaches: fully visible. */
/* round 34: gsap writes the lede words' opacity on a scrub, so no transition here */
.wr-all .wr-w { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .wr .wr-w { opacity: 1; transition: none; }
}
/* the scrub beats: the same vocabulary, stepped from .is-on instead of from
   a scroll window, because they sit inside a 100vh sticky whose rect never
   travels. Off-beats stay hidden by their own existing rule. */
.wr-beat .wr-w { opacity: .25; transition: opacity .34s var(--glide); }
.scrub-beat.is-on.wr-beat .wr-w {
  opacity: 1; transition-delay: calc(var(--i, 0) * 55ms);
}
@media (prefers-reduced-motion: reduce) {
  .wr-beat .wr-w { opacity: 1; transition: none; }
}

/* ============================================================================
   Round 12, item 3 — the Siri edge glow, ported from oryzo.ai.

   A fixed, pointer-events-none layer at the viewport edges. The colour is a
   conic sweep of the four brand hues; the mask is a band at the frame, 3% of
   the width and 5% of the height (the proportions measured on the
   reference), and a 40px blur takes every edge off it. Opacity ramps in over
   600ms, holds, and leaves over 900ms. The hue rotates once every 20s while
   it is up. js/site.js -> siriGlow().
   ========================================================================= */
.siri-glow {
  position: fixed; inset: 0; z-index: 50; pointer-events: none;
  opacity: 0; transition: opacity .9s var(--glide);
  filter: blur(40px);
  background: conic-gradient(from 0deg at 50% 50%,
    #FF6B3D 0deg, #C2F222 90deg, #6FA0FF 180deg, #A67CE8 270deg, #FF6B3D 360deg);
  /* the band: opaque at the frame, gone 3% in horizontally and 5% in
     vertically, which is what the reference measures at 1440 x 900. */
  -webkit-mask-image:
    linear-gradient(to right,  #000 0, transparent 3%, transparent 97%, #000 100%),
    linear-gradient(to bottom, #000 0, transparent 5%, transparent 95%, #000 100%);
  mask-image:
    linear-gradient(to right,  #000 0, transparent 3%, transparent 97%, #000 100%),
    linear-gradient(to bottom, #000 0, transparent 5%, transparent 95%, #000 100%);
  -webkit-mask-composite: source-over; mask-composite: add;
}
.siri-glow.is-on {
  opacity: 1; transition: opacity .6s var(--glide);
  animation: siri-hue 20s linear infinite;
}
.siri-glow.is-static { opacity: .6; transition: none; animation: none; }
@keyframes siri-hue { to { filter: blur(40px) hue-rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .siri-glow { animation: none; transition: none; }
}

/* ============================================================================
   Round 12, item 7 — the offline tiles reserve their caption.

   At 1440 the "Any browser" window was landing on the second line of its
   caption and the "Any time" photograph was running under its own. The tiles
   centred their copy and hung the element off the bottom right, so as soon
   as a caption wrapped to two lines the two met. The copy sits at the TOP of
   the tile now and the element gets its own band underneath it, reserved as
   a number, `--ot-band`, that the padding and the element height both read.
   Checked at 1440, 1024, 768 and 390.
   ========================================================================= */
.offline-tile { justify-content: flex-start; }
.offline-tile.ot-clockt { justify-content: center; }
.offline-tile.has-band {
  --ot-band: 150px;
  padding-bottom: calc(var(--ot-band) + 24px);
}
/* the window: it overhangs the tile by 24px, so its own height is the band
   plus that overhang and the reservation stays exactly the band. */
.offline-tile.has-band .ot-win { height: calc(var(--ot-band) + 24px); }
.offline-tile.has-band .ot-photo { height: var(--ot-band); top: auto; bottom: 0; }
@media (max-width: 1100px) { .offline-tile.has-band { --ot-band: 138px; } }
@media (max-width: 700px)  {
  .offline-tile.has-band { --ot-band: 128px; }
  /* the lead's deeper band is a desktop figure: on one column it would make
     the first tile twice the height of the five under it. */
  .offline-tile.ot-lead.has-band { --ot-band: 150px; }
  .offline-tile.ot-shot.has-band { padding-bottom: calc(var(--ot-band) + 18px); }
  .offline-tile.has-band .ot-photo { width: 82%; }
}

/* ============================================================================
   Round 12, item 6 — the "Fourteen modules" bento gets the dashboard bento's
   treatment.

   Same contract as the round 11 dashboard tiles: every tile carries one
   element, the element plays once on entering the viewport with the round 11
   timing (a 40 to 70ms stagger on the site's own --glide) and then breathes,
   and `prefers-reduced-motion` lands everything in its settled state with no
   motion at all. js/apple.js -> tileMotion() adds `.is-in` and then
   `.is-done`; every rule below keys off those two classes and nothing else.

   Every number and every phrase in here is already on the page or on the
   module page the tile links to: 15.1%, 33, 9, the four stock reasons, the
   four transports, the four outlet names, the report titles.
   ========================================================================= */
 /* position only: `display` belongs to each modifier below, and a
    `.bx .bxa` shorthand carrying one would outrank every single-class
    `.bxa-*` rule on specificity regardless of source order. */
.bx .bxa { position: relative; z-index: 2; }
.bx .bxa i { font-style: normal; }

/* ---- "Trades with no network": the bars drop to none, the queue counts up,
   then the bars come back and the tile reads "synced". */
.bxa-signal {
  margin-top: auto; padding-top: var(--s-3);
  display: grid; grid-template-columns: auto 1fr; align-items: end; gap: 4px 14px;
  border-top: 1px solid rgba(255,255,255,.10);
}
.bxs-bars { grid-row: span 2; display: flex; align-items: flex-end; gap: 4px; height: 46px; }
.bxs-bars i {
  width: 8px; border-radius: 3px; background: currentColor; opacity: .28;
  height: calc(14px + var(--i) * 11px);
  transform-origin: 50% 100%; transform: scaleY(1);
  transition: transform .34s var(--glide), opacity .34s var(--glide);
}
/* dropping: each bar falls, the outermost first. */
.bx.is-in .bxs-bars i {
  transform: scaleY(.08); opacity: .12;
  transition-delay: calc((3 - var(--i)) * 90ms);
}
.bx.is-done .bxs-bars i {
  transform: scaleY(1); opacity: .62;
  transition-delay: calc(var(--i) * 90ms);
}
.bxs-q {
  grid-column: 2; align-self: center;
  font-family: var(--font-mono); font-size: 13px; opacity: 0;
  transition: opacity .3s var(--glide) .36s;
}
.bx.is-in .bxs-q { opacity: .78; }
.bx.is-done .bxs-q { opacity: 0; transition-delay: 0s; }
.bxs-ok {
  grid-column: 2; grid-row: 1 / span 2; align-self: center;
  font-family: var(--font-mono); font-size: 13px; color: #FF8A5B;
  opacity: 0; transition: opacity .34s var(--glide) .30s;
}
.bx.is-done .bxs-ok { opacity: 1; }

/* ---- "Nineteen, all exporting": the CSV chips light one after another,
   then the export tick draws. */
.bx-rows-lit div .csv {
  border-radius: 999px; padding: 1px 7px;
  background: transparent; color: inherit; opacity: .5;
  transition: background .28s var(--glide), color .28s var(--glide), opacity .28s var(--glide);
}
.bx.is-in .bx-rows-lit div .csv {
  background: var(--o-500); color: var(--n-900); opacity: 1;
  transition-delay: calc(var(--i) * 110ms);
}
.bxa-dl {
  display: inline-flex; align-items: center; gap: 6px; margin-top: var(--s-2);
  font-family: var(--font-mono); font-size: 12px; opacity: 0;
  transition: opacity .3s var(--glide);
}
.bxa-dl svg { width: 14px; height: 14px; }
.bxa-dl path { stroke-dasharray: 1; stroke-dashoffset: 1; }
.bx.is-done .bxa-dl { opacity: .8; }
.bx.is-done .bxa-dl path { stroke-dashoffset: 0; transition: stroke-dashoffset .5s var(--glide) .1s; }

/* ---- "Costed from the ingredient": four ingredient bars fill to their
   share of the plate cost, then the blended figure counts up. */
.bxa-stack {
  display: flex; height: 10px; border-radius: 999px; overflow: hidden;
  margin: var(--s-3) 0 0; background: rgba(0,0,0,.07);
}
.bxa-stack i {
  display: block; height: 100%; width: calc(var(--v) * 100%);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .5s var(--glide);
}
.bxa-stack i:nth-child(1) { background: #FF5A1F; }
.bxa-stack i:nth-child(2) { background: #FF8A5B; }
.bxa-stack i:nth-child(3) { background: #D97A00; }
.bxa-stack i:nth-child(4) { background: #FFB454; }
.bx.is-in .bxa-stack i { transform: scaleX(1); transition-delay: calc(var(--i) * 90ms); }

/* ---- "Stock moves for four reasons": the four chips appear in order and
   the stock line draws itself underneath them. */
.bxa-chips { display: flex; flex-wrap: wrap; gap: 5px; margin-top: var(--s-3); }
.bxa-chips i {
  font-size: 11.5px; line-height: 1; padding: 5px 9px; border-radius: 999px;
  background: rgba(0,0,0,.06); color: inherit;
  opacity: 0; transform: translateY(6px);
  transition: opacity .32s var(--glide), transform .32s var(--glide);
}
.bx.is-in .bxa-chips i { opacity: .9; transform: none; transition-delay: calc(var(--i) * 110ms); }
.bxa-line { display: block; margin-top: var(--s-2); height: 34px; color: var(--o-500); }
.bxa-line svg { width: 100%; height: 100%; display: block; }
.bxa-line path { stroke-dasharray: 1; stroke-dashoffset: 1; }
.bx.is-in .bxa-line path { stroke-dashoffset: 0; transition: stroke-dashoffset 1.1s var(--glide) .44s; }

/* ---- "One brand standard, five sets of books": five outlet cards come out
   of one position, each stamping a tick as it lands. The first version fanned
   them by rotation out of a shared origin and, at the real name lengths on
   this page ("Sharjah Al Majaz" is sixteen characters), they simply landed on
   each other. They step out along a row instead, which is the same idea and
   is actually readable. */
.bxa-fan {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--s-3);
}
.bxa-fan i {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 11px; border-radius: 10px;
  background: rgba(255,255,255,.10); box-shadow: inset 0 0 0 1px rgba(255,255,255,.16);
  font-size: 12px; white-space: nowrap;
  opacity: 0; transform: translate3d(-16px, 0, 0) scale(.94);
  transition: transform .5s var(--glide), opacity .34s var(--glide);
}
.bxa-fan i b { font-weight: 600; }
.bxa-fan i em {
  width: 14px; height: 14px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: var(--o-500);
  transform: scale(0); transition: transform .3s var(--glide);
}
.bxa-fan i em::after {
  content: ""; width: 6px; height: 3px; border: 1.6px solid var(--n-900);
  border-top: 0; border-right: 0; transform: rotate(-45deg) translate(.5px, -1px);
}
.bx.is-in .bxa-fan i {
  opacity: 1; transform: none;
  transition-delay: calc(var(--i) * 90ms);
}
.bx.is-done .bxa-fan i em { transform: scale(1); transition-delay: calc(var(--i) * 90ms + 120ms); }

/* ---- "ESC/POS over four transports": the four transports light in order
   and a ticket slides out of the printer glyph. */
.bxa-tr {
  display: flex; align-items: center; gap: var(--s-4); margin-top: var(--s-3);
  flex-wrap: nowrap;
}
.bxt-chips { display: flex; flex-wrap: wrap; gap: 5px; flex: 1 1 auto; min-width: 0; }
.bxt-chips i {
  font-size: 11.5px; line-height: 1; padding: 5px 9px; border-radius: 999px;
  background: rgba(0,0,0,.06);
  opacity: .35; transition: opacity .3s var(--glide), background .3s var(--glide);
}
.bx.is-in .bxt-chips i {
  opacity: 1; background: rgba(255,90,31,.14);
  transition-delay: calc(var(--i) * 130ms);
}
/* the printer with a ticket coming out of it: the glyph is drawn at 38px and
   the ticket is a paper strip that grows out of its own slot, clipped by the
   block so it never becomes a floating white rectangle. */
.bxt-print {
  position: relative; display: block; width: 44px; height: 58px; flex: none;
  color: var(--ink-2); overflow: hidden;
}
.bxt-print .ic { width: 38px; height: 38px; margin-left: 3px; stroke: currentColor; fill: none; stroke-width: 1.6; display: block; }
.bxt-print em {
  position: absolute; left: 12px; top: 27px; width: 20px; height: 24px;
  border-radius: 0 0 3px 3px;
  /* a ruled slip, not a blank rectangle: on a white tile a white box with a
     hairline reads as nothing at all. */
  background:
    repeating-linear-gradient(to bottom, rgba(0,0,0,.28) 0 1.5px, transparent 1.5px 6px) 0 5px / 13px 100% no-repeat,
    #F2EFEA;
  box-shadow: 0 0 0 1px rgba(0,0,0,.16);
  background-position-x: 4px;
  transform: scaleY(0); transform-origin: 50% 0;
  transition: transform .55s var(--glide);
}
.bx.is-in .bxt-print em { transform: scaleY(1); transition-delay: .6s; }

/* ---- the ambient breath. Once a tile is settled its element keeps a very
   small life of its own, which is the only thing the round 11 dashboard
   bento does after it lands. Never under reduced motion. */
@media (prefers-reduced-motion: no-preference) {
  .bx.is-done .bxs-bars i:nth-child(4) { animation: bx-breath 5.5s var(--glide) 1.2s infinite; }
  .bx.is-done .bxa-line { animation: bx-drift 7s var(--glide) 1.4s infinite; }
  .bx.is-done .bxt-print em { animation: bx-breath 6.5s var(--glide) 1.6s infinite; }
}
@keyframes bx-breath { 0%,88%,100% { opacity: 1; } 94% { opacity: .45; } }
@keyframes bx-drift { 0%,100% { transform: none; } 50% { transform: translateY(-2px); } }

/* ---- reduced motion: every element lands settled, nothing moves. */
@media (prefers-reduced-motion: reduce) {
  .bxs-bars i { transform: none; opacity: .62; transition: none; }
  .bxs-q { display: none; }
  .bxs-ok { opacity: 1; transition: none; }
  .bx-rows-lit div .csv { background: var(--o-500); color: var(--n-900); opacity: 1; transition: none; }
  .bxa-dl { opacity: .8; transition: none; }
  .bxa-dl path { stroke-dashoffset: 0; transition: none; }
  .bxa-stack i { transform: none; transition: none; }
  .bxa-chips i { opacity: .9; transform: none; transition: none; }
  .bxa-line path { stroke-dashoffset: 0; transition: none; }
  .bxa-fan i { opacity: 1; transform: none; transition: none; }
  .bxa-fan i em { transform: scale(1); transition: none; }
  .bxt-chips i { opacity: 1; background: rgba(255,90,31,.14); transition: none; }
  .bxt-print em { transform: scaleY(1); transition: none; }
}

/* ---- phones: the fan folds to a stack and the transports wrap under the
   printer rather than beside it, so nothing runs off a 320px tile. */
@media (max-width: 700px) {
  .bxa-fan { gap: 5px; }
  .bxa-fan i { font-size: 11px; padding: 5px 9px; }
  .bxa-tr { gap: var(--s-3); flex-wrap: wrap; }
  .bxa-line { height: 28px; }
}

/* ============================================================================
   Round 13 — one hover treatment for every bento tile, and the eyebrow chip.

   Taken from the same mockup as the hero. On hover the tile's 1px edge
   lightens over 300ms and a 260px blurred orange blob at its bottom right
   corner goes from .05 to .10. Both live on ONE pseudo-element per tile, so
   nothing has to touch the box-shadows, borders and `::after` markers these
   tiles already carry: the ring is an inset box-shadow on the pseudo, the
   blob is its background at .10, and the pseudo's own opacity carries the
   pair from .5 (blob at an effective .05, ring invisible) to 1.

   The pseudo sits ABOVE the tile content on purpose. A corner glow is the one
   thing that should read as light falling on the tile rather than as a layer
   underneath it, and at 10 percent of an orange radial it tints nothing
   legibly. It also means no child of any tile needed a z-index, which is what
   would have broken the photo tiles' own caption scrims.
   ========================================================================= */
.bx, .sb, .plus-card { position: relative; }
.bx::before, .sb::before, .plus-card::before {
  content: ""; position: absolute; inset: 0; z-index: 5; pointer-events: none;
  border-radius: inherit;
  background: radial-gradient(260px 260px at 100% 100%, rgba(255,107,61,.10) 0%, rgba(255,107,61,0) 70%);
  opacity: .5;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0);
  transition: opacity .3s var(--glide), box-shadow .3s var(--glide);
}
/* eggshell tiles darken their edge instead of lightening it. */
.sb::before, .plus-card::before,
.bx.paper::before, .bx.plate::before, .bx.wash::before, .bx.ember::before {
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0);
}
@media (hover: hover) and (pointer: fine) {
  .bx:hover::before, .sb:hover::before, .plus-card:hover::before {
    opacity: 1; box-shadow: inset 0 0 0 1px rgba(255,255,255,.12);
  }
  .sb:hover::before, .plus-card:hover::before,
  .bx.paper:hover::before, .bx.plate:hover::before,
  .bx.wash:hover::before, .bx.ember:hover::before {
    box-shadow: inset 0 0 0 1px rgba(0,0,0,.10);
  }
}
@media (prefers-reduced-motion: reduce) {
  .bx::before, .sb::before, .plus-card::before { transition: none; }
}

/* ---- Round 20b, item 4: the black tiles get a definitive edge -----------
   Parth at 1440 on #dashboard: the tiles' edges were barely visible against
   the section's black, so the bento did not read as boxes at all. Round 13b
   had given them liquid glass -- `rgba(18,18,18,.4)` over a 20px backdrop
   blur with a 5 percent edge -- and on a pure black ground a translucent
   near-black tile IS the ground. Nothing was wrong with the blur; there was
   simply nothing behind it to blur.

   So the tile is opaque one step above the ground, and it is lifted rather
   than merely outlined: `#161618` against `#000000`, a 1px edge at 14
   percent white, a 1px inner top highlight at 6 percent for the light
   catching the top face, and a wide soft shadow beneath. Hover takes the
   edge to 22 percent. Radius and gaps are untouched.

   Contrast checked on the new ground rather than assumed: the caption grey
   `#A1A1A6` on `#161618` is 7.2:1, so `--ink-2` on dark needed no change.
   ------------------------------------------------------------------------ */
.db, .offline-tile {
  position: relative;
  background: #161618;
  -webkit-backdrop-filter: none; backdrop-filter: none;
  border: 1px solid rgba(255,255,255,.14);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06),
              0 12px 40px rgba(0,0,0,.45);
  transition: background .3s var(--glide), border-color .3s var(--glide),
              box-shadow .3s var(--glide), transform .2s var(--glide);
}
@media (hover: hover) and (pointer: fine) {
  .db:hover, .offline-tile:hover {
    background: #19191C; border-color: rgba(255,255,255,.22);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.08),
                0 16px 48px rgba(0,0,0,.55);
  }
}
@media (prefers-reduced-motion: reduce) {
  .db, .offline-tile { transition: none; }
}

/* ---- the eyebrow chip. Mono, 11px, uppercase, in an orange pill. On the
   eggshell bentos the label is --o-800, not the brand fill: #FF6B3D at 11px
   on a near-white tile is 3.0:1 and fails, which is the same reason the round
   11 note gives for lime text living at #4D7007. The pill itself is the brand
   fill at 10 percent in both places, so the chip reads identically. */
.tchip {
  display: inline-flex; align-items: center; align-self: flex-start;
  font-family: var(--font-mono); font-weight: 600; font-size: 11px;
  line-height: 1; letter-spacing: .08em; text-transform: uppercase;
  padding: 6px 10px; border-radius: 999px;
  background: rgba(255,107,61,.10); color: var(--o-800);
  width: fit-content; white-space: nowrap;
}
.db > .tchip, .offline-tile > .tchip, .bx.ink .tchip, .bx.masala .tchip {
  color: #FF6B3D; position: relative; z-index: 3;
}
.db > .tchip { margin-bottom: auto; }
.offline-tile > .tchip { margin-bottom: 12px; }
.bx .kicker.tchip { margin-bottom: 2px; }
.bx:hover .kicker.tchip { color: var(--o-800); }
.bx.ink:hover .kicker.tchip, .bx.masala:hover .kicker.tchip { color: #FF6B3D; }
/* the centre tile of the system bento is the orange one: white on the same
   translucent white plate its cloud icon already uses. */
.sb-core .tchip { background: rgba(255,255,255,.20); color: #FFFFFF; }

/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  Round 14, item 5 — the hero's type treatment on every section heading   ║
   ╚══════════════════════════════════════════════════════════════════════════╝
   The hero headline's vertical gradient is the page's one heading idiom now.
   Two ramps only, one per ground: white into the two greys on black, ink into
   the two greys on eggshell. Weight and tracking are the hero's (Inter 800,
   -0.04em); the size is whatever the section already had.

   Three things this rule has to carry with it, all of them item 1's lesson:
   `background-clip: text` paints only inside the padding box, so the line
   height has to leave room for the glyphs and the last line needs .08em of
   padding under it or every descender loses its fill. `text-wrap: balance`
   is inherited from base.css and keeps working: the gradient is vertical, so
   the line break position does not change a pixel of it.

   Module pages have no `.section-head` of their own -- their heads are the
   bare `<h2>` inside `.mod-related`, `.mod-faq` and `.cta-band` -- so those
   three are named here as well, which is what puts the treatment on all 27. */
.section-head h2,
.mod-related > .wrap > h2,
.mod-faq > .wrap > h2,
.cta-band .cta-in h2 {
  font-family: var(--font-display); font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 1.06; padding-bottom: .08em;
  background-image: linear-gradient(180deg, #000000 0%, #2C2C2E 55%, #6E6E73 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
.on-dark .section-head h2,
.on-dark .cta-in h2,
.section-head.is-dark h2 {
  background-image: linear-gradient(180deg, #FFFFFF 0%, var(--hl-1) 55%, var(--hl-2) 100%);
}
/* the scrub chapters and the phone section set their own heading colour on a
   photographic ground; leave those alone. */
.moment-copy h2, .ph-step h2 {
  background-image: none; color: inherit; -webkit-text-fill-color: currentColor;
  padding-bottom: 0;
}

/* ============================================================================
   Round 16 (2026-09-12)
   ========================================================================= */

/* ---- item 1: motion behind the dashboard pair ---------------------------
   The pair image used to sit on flat black. Three decorative layers now move
   behind and over it: a breathing radial glow, a second instance of the
   hero's particle web (same module, quieter), and a single diagonal light
   sweep across both screens when the stage first enters the viewport. The
   sweep is clipped to the two screen quads read off the composite's own
   green key, expressed as percentages of the image box, so the band only
   crosses glass and never the aluminium. */
.dash-stage { position: relative; isolation: isolate; margin-top: var(--bento-top); }
.dash-amb { position: absolute; inset: -12% 0; z-index: 0; pointer-events: none; overflow: hidden; }
.dash-glow {
  position: absolute; left: 50%; top: 50%; width: 600px; height: 600px;
  margin: -300px 0 0 -300px; border-radius: 50%;
  background: radial-gradient(circle, rgba(255,107,61,1) 0%, rgba(255,107,61,.42) 44%, transparent 72%);
  opacity: .10; filter: blur(40px);
  /* Round 23, item 6: it drifts as well as breathes. A blob that only
     scales in place reads as a static wash the moment you stop watching
     it; 9s of breath against 23s of a slow figure across the stage means
     the two never line up and the ground is visibly alive. */
  animation: dashBreathe 9s ease-in-out infinite alternate,
             dashDrift 23s ease-in-out infinite alternate;
}
@keyframes dashBreathe { from { opacity: .10; } to { opacity: .18; } }
@keyframes dashDrift {
  from { transform: translate3d(-9%, -5%, 0) scale(1); }
  50%  { transform: translate3d(6%, 4%, 0) scale(1.06); }
  to   { transform: translate3d(10%, -3%, 0) scale(1.08); }
}

/* ---- Round 17, item 4: the same field on every black section -------------
   The canvas is written into the section by blackFields() in js/apple.js as
   its first child; these two rules are all it needs. `z-index: 0` on the
   canvas plus `position: relative` on every sibling puts the field over the
   ground and under the content in tree order, with no child having to carry
   a z-index of its own. .14 is a third of the hero's field: enough that the
   ground is clearly moving, little enough that body copy over it does not
   change.

   Round 19: the layer is no longer dimmed at all. Round 17 landed the dots at
   an effective .143 (.55 paint x .26 layer) and Parth could not see them, so
   the strength moved into the paint instead -- .45 in js/apple.js against the
   hero's .55 -- and this layer is opaque. Same dots, same 130px link reach,
   same .16 line alpha as the hero; one step quieter, and actually there. */
.has-web { position: relative; }
.sec-web {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; display: block;
  opacity: 1; pointer-events: none;
}
.has-web > :not(.sec-web) { position: relative; }
/* Round 66: fields on every ground. The canvas sits under the section's own content by stacking,
   so no child's position is overridden. */
.has-web2 { isolation: isolate; }
.has-web2 > .sec-web2 { z-index: -1; }
@media (prefers-reduced-motion: reduce) { .sec-web { display: none; } }
/* Round 63: phones draw the section fields too (js/apple.js blackFields). */
/* the composite's own ground is pure black, so anything drawn behind it is
   simply hidden. The image is screened over the stage instead: black keys
   itself out, the devices stay as they are, and the glow reads as light
   spilling onto the aluminium rather than a halo stuck behind a rectangle.
   `.dash-pair` keeps `position` but never `z-index`, because a stacking
   context on the figure would give the blend nothing to blend against. */
.dash-pair { position: relative; }
.dash-pair img { mix-blend-mode: screen; }
/* the two screens, as clip paths. Laptop: a plain rectangle. Tablet: the
   propped quad, so the band follows its tilt. */
.dash-sweep {
  position: absolute; inset: 0; display: block; overflow: hidden; pointer-events: none;
}
.dash-sweep.sw-lap { clip-path: polygon(23.11% 18.88%, 66.02% 18.82%, 66.02% 69.27%, 23.11% 69.34%); }
.dash-sweep.sw-pad { clip-path: polygon(57.92% 47.20%, 84.01% 47.33%, 79.40% 84.31%, 52.91% 81.32%); }
.dash-sweep::before {
  content: ""; position: absolute; top: -30%; bottom: -30%; left: 0; width: 40%;
  background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,.08) 50%, rgba(255,255,255,0) 100%);
  transform: translateX(-160%) skewX(-14deg); opacity: 0;
}
.dash-stage.is-swept .dash-sweep::before { animation: dashSweep 1.4s cubic-bezier(.32,.06,.4,1) both; }
@keyframes dashSweep {
  0%   { transform: translateX(-160%) skewX(-14deg); opacity: 0; }
  12%  { opacity: 1; }
  88%  { opacity: 1; }
  100% { transform: translateX(320%) skewX(-14deg); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .dash-glow { animation: none; opacity: .14; }
  .dash-sweep { display: none; }
}

/* ---- item 2: no device sits on a photograph any more ---------------------
   The till and kitchen scrub chapters carried a photograph behind the device
   (`img/photo/casual.webp` and `img/photo/cloud.webp`). Both grounds are
   eggshell, so both get the same replacement: a soft radial orange wash and
   a faint ink dot grid that parallaxes 10px against the scroll. The files
   stay on disk; photographs inside bento tiles and galleries are untouched. */
.egg-amb { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
/* Round 19, item 6. This used to be a 140vmax circle centred on the sticky,
   which at any viewport is far wider than the box that clips it -- so the wash
   was still at a fifth of its strength when `.egg-amb`'s `overflow: hidden`
   cut it, and what you saw at the top of the runway was a hard horizontal
   band between plain eggshell above and a pinker eggshell below. It is an
   ellipse inside its own box now, centred on the frame, at full transparency
   34 percent of the sticky's height from the middle: 144px clear of the top
   and bottom edges at 900, 123px at 768, so there is no edge left to see. */
.egg-wash {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse 58% 34% at 50% 50%,
    rgba(255,107,61,.10) 0%, rgba(255,107,61,.055) 42%, rgba(255,107,61,0) 100%);
}
.egg-dots {
  position: absolute; inset: -40px 0 -40px 0;
  background-image: radial-gradient(rgba(0,0,0,.04) 1px, transparent 1px);
  background-size: 24px 24px;
  transform: translateY(var(--dotY, 0px));
  will-change: transform;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 14%, #000 86%, transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, #000 14%, #000 86%, transparent 100%);
}
@media (max-width: 900px) { .egg-dots { display: none; } }
@media (prefers-reduced-motion: reduce) { .egg-dots { transform: none !important; } }

/* ---- Round 20: the nine systems, as one 3D scene ------------------------
   The round 16 orbit SVG is gone. The centre is a WebGL point cloud
   (js/cloud20.js) that rotates, disperses under the pointer and springs
   home; the eight systems are DOM text on a `perspective: 1200px` stage,
   each at its own translateZ and its own height, and the connectors and
   their packets are drawn in the same canvas off the nodes' real screen
   rectangles, so nothing here can fall out of alignment with anything
   else. Below 900px the whole thing flattens to a cloud over a 2 by 4
   grid and the canvas keeps only its rotation. */
.cld { position: relative; }
.cld-stage {
  position: relative; max-width: 1100px; margin-inline: auto;
  aspect-ratio: 1100 / 780;
  perspective: 1200px; perspective-origin: 50% 50%;
}
.cld-cv {
  position: absolute; inset: 0; width: 100%; height: 100%;
  display: block; pointer-events: none;
}

/* The no-WebGL fallback, and the ground the cloud sits in under reduced
   motion: the round 16 disc, drawn in CSS rather than as a second SVG. */
.cld-disc {
  position: absolute; left: 50%; top: 50%; width: 380px; height: 380px;
  margin: -190px 0 0 -190px; border-radius: 50%; display: none;
  background:
    radial-gradient(circle at 50% 50%, #FF6B3D 0%, #FF8A5B 62%, rgba(255,138,91,0) 100%);
}
.cld.no-gl .cld-disc { display: block; }

/* Round 20b, item 3: the white cloud mark is OFF the middle of the point
   cloud. Parth saw it as a second, contradictory cloud sitting inside the
   one the section is about. It survives only as the fallback for a browser
   with no WebGL at all, where there is no point cloud for it to contradict;
   the reduced-motion path still paints the real cloud, so it stays hidden
   there too. */
.cld-centre {
  position: absolute; left: 50%; top: 50%; margin: 0;
  transform: translate(-50%, -50%); pointer-events: none; z-index: 2;
  display: none;
}
.cld.no-gl .cld-centre { display: block; }
.cld-glyph { display: block; width: 54px; height: 54px; color: #FFFFFF; }
.cld-glyph use {
  fill: none; stroke: currentColor; stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
}

.cld-nodes {
  position: absolute; inset: 0; margin: 0; padding: 0; list-style: none;
  transform-style: preserve-3d; z-index: 3;
  transform: rotateX(var(--tx, 0deg)) rotateY(var(--ty, 0deg));
  transition: transform 120ms linear;
  pointer-events: none;
}
.cld-node {
  pointer-events: auto;
  position: absolute; left: 50%; top: 50%; width: 196px;
  margin: 0; transform-style: preserve-3d;
  /* js writes --nx/--ny once per layout and the tilt shift every frame */
  transform: translate(-50%, -50%)
             translate3d(calc(var(--nx, 0px) + var(--px, 0px)),
                         calc(var(--ny, 0px) + var(--py, 0px)), var(--z, 0px))
             scale(var(--nk, 1));
  opacity: 0;
}
/* Round 60: under an 1100px stage the plates scale with it (--nk, written
   by js/cloud20.js with the ring), so the ring is the 1100 layout drawn
   smaller rather than the same plates crowding a tighter ring: at 1024 two
   pairs overlapped by 7px, at 900 six pairs by up to 25. */
.cld.is-in .cld-node { animation: cldNode .6s var(--glide) both; animation-delay: calc(220ms + var(--i, 0) * 60ms); }
@keyframes cldNode { from { opacity: 0; } to { opacity: var(--o, 1); } }

.cld-plate {
  display: block; text-align: center; padding: 13px 12px 15px;
  border-radius: var(--r-4);
  background: rgba(28,28,30,.90); border: 1px solid rgba(247,243,238,.12);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  transition: transform 260ms var(--glide), border-color 260ms var(--glide),
              background-color 260ms var(--glide);
}
.cld-ic {
  display: block; width: 44px; height: 44px; margin: 0 auto 10px;
  color: #F7F3EE; transition: color 260ms var(--glide);
}
.cld-ic use {
  fill: none; stroke: currentColor; stroke-width: 1.75;
  stroke-linecap: round; stroke-linejoin: round;
}
.cld-node b {
  display: block; font-family: var(--font-ui); font-size: 20px; font-weight: 600;
  line-height: 1.2; letter-spacing: -.01em; color: #F7F3EE;
}
.cld-node i {
  display: block; margin-top: 5px; font-style: normal;
  font-family: var(--font-ui); font-size: 14px; font-weight: 400;
  line-height: 1.35; color: #A1A1A6;
}

/* hover lifts the plate 24px toward the viewer and fills the glyph; the
   cloud answers in the canvas (js/cloud20.js brightens the points on that
   node's bearing and sends one extra packet down its wire). */
.cld-node.is-hot .cld-plate {
  transform: translateZ(24px);
  border-color: rgba(255,107,61,.42);
  background: rgba(28,28,30,.94);
}
.cld-node.is-hot .cld-ic { color: #FF6B3D; }
.cld-node:focus-within .cld-plate { transform: translateZ(24px); border-color: rgba(255,107,61,.42); }

.cld-vwires { display: none; }

/* Round 60, item 3: the closing line sat 5px under the lowest plate at a
   desktop width. The plates stand in perspective at their own depths, so the
   nearest ones are drawn up to about 24px past the stage's box at rest;
   js/cloud20.js works that reach out from the layout and writes it as
   --cld-drop, and the line keeps --s-7 clear of it. The section's lede
   style, centred. */
.cld-line { margin: calc(var(--cld-drop, 24px) + var(--s-7)) auto 0; max-width: 56ch; text-align: center; }

/* ---- flat, below 900px --------------------------------------------------
   Eight plates on two rings need about 880px of stage before the labels
   start colliding, so under 900 the ring comes apart: the cloud keeps the
   top of the stage on its own, and the eight sit under it in a 2 by 4
   grid with two straight wires running up into the columns. No
   perspective, no tilt, and the canvas draws the cloud alone. */
@media (max-width: 899px) {
  /* Round 24, item 2: the canvas covers the WHOLE stage on a phone, not
     just the cloud's own band, because the connectors are curves drawn in
     the GL scene now and they have to reach the plates in the grid below.
     The band the cloud is centred in is still --cvh; the stage reserves it
     as padding, so the grid flows underneath exactly where it did. */
  /* Round 56, item 4: a finger on the stage pushes the points while the page
     still scrolls (pan-y), and the plates tilt with scroll velocity, the
     desktop's --tx written by js/cloud20.js each frame */
  .cld-stage { aspect-ratio: auto; perspective: none; --cvh: min(58vw, 300px);
               padding-top: var(--cvh); touch-action: pan-y; }
  .cld-cv { position: absolute; inset: 0; height: 100%; }
  .cld-disc { top: calc(var(--cvh) / 2); width: 180px; height: 180px; margin: 0; transform: translate(-50%, -50%); }
  .cld.no-gl .cld-centre { left: 50%; top: calc(var(--cvh) / 2); }
  .cld-glyph { width: 40px; height: 40px; }
  .cld-nodes {
    position: relative; inset: auto; transform-style: flat;
    transform: perspective(900px) rotateX(var(--tx, 0deg)); transform-origin: 50% 50%; transition: none;
    display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
    /* round 40, item 1: every row is the same height, so a card never grows
       because its own title or line wraps a step further than its neighbour's */
    grid-auto-rows: 1fr;
    margin-top: 22px;
  }
  .cld-node {
    position: relative; left: auto; top: auto; width: auto;
    transform: none !important; opacity: 1;
  }
  /* the plate fills its row and the three parts sit on the same baselines in
     every card: the icon at the top, the title in two lines of room and the
     line in two, whether this card's text uses them or not */
  .cld-plate { padding: 12px 10px 14px; height: 100%; }
  .cld-ic { width: 28px; height: 28px; margin-bottom: 8px; }
  .cld-node b { font-size: 15px; min-height: calc(2 * 1.2em); }
  .cld-node i { font-size: 12.5px; min-height: calc(2 * 1.35em); }
  .cld-node.is-hot .cld-plate, .cld-node:focus-within .cld-plate { transform: none; }
  /* the two CSS hairlines are gone: the real curves run to every plate on
     a phone now, so a pair of straight gradient rules under the cloud was
     a second, contradictory answer to the same question. */
  .cld-vwires { display: none; }
}
@media (max-width: 899px) { .cld-line { margin-top: var(--s-7); } }
@media (max-width: 359px) { .cld-nodes { grid-template-columns: 1fr; } }

@media (prefers-reduced-motion: reduce) {
  .cld-nodes { transform: none !important; transition: none; }
  .cld-node { opacity: 1 !important; animation: none !important; }
  .cld-plate, .cld-ic { transition: none; }
}

/* ---- item 4: the live screens inside the hero tablet and phone ----------
   Each clone is laid out at its own design width and then scaled to the
   screen box, so the markup keeps vector crispness at 2x instead of being a
   resampled picture. Inert: no pointer events, no tab stops, aria-hidden. */
.h13-live {
  position: absolute; left: 0; top: 0; transform-origin: 0 0;
  pointer-events: none; user-select: none;
}
.h13-trio .pad-screen[data-live], .h13-trio .ph-screen[data-live] { background: var(--bone); }
.h13-live .ui { height: 100%; border-radius: 0; }
.h13-live .ph-ui { position: absolute; inset: 0; }
.h13-live .ph-view { opacity: 1; transform: none; }

/* ---- item 5: four things ported from the two reference sites ------------
   From apple.com/macbook-pro: the light sweeping across a display (its hero
   has it inside the film; ours is CSS, because our screens are live markup),
   and the layered gradient glow behind a pinned device. From componentry:
   the rolling-digit ticker and the pointer-tracked spotlight. */

/* (a) the sweep across the hero trio's screens, once, after they settle.
   The MacBook is a photograph, so its band is clipped to the screen's own
   box inside the image (rows 4.3 to 49.8 percent, columns 7.7 to 92.2,
   measured off the file); the tablet and phone screens are boxes already. */
.h13-sweep {
  position: absolute; inset: 0; display: block; z-index: 4;
  pointer-events: none; overflow: hidden;
}
.h13-sweep.sw-mac { clip-path: polygon(7.7% 4.3%, 92.2% 4.3%, 92.2% 49.8%, 7.7% 49.8%); }
.h13-sweep::before {
  content: ""; position: absolute; top: -40%; bottom: -40%; left: 0; width: 42%;
  background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.09) 50%, rgba(255,255,255,0));
  transform: translateX(-170%) skewX(-14deg); opacity: 0;
}
/* Round 25, item 10: the three bands are one light now. They wait for the
   entrance to settle (`.is-swept`, set by js/apple.js once the last spring
   is home) and each runs the delay and the duration its own position in the
   group earns, so the pass crosses the trio left to right in 1.2s total
   instead of three separate flashes on one shared 2.7s timer. */
.h13-trio.is-swept .h13-sweep::before {
  animation: dashSweep var(--sw-dur, .6s) cubic-bezier(.32,.06,.4,1) var(--sw-delay, 0s) both;
}
@media (prefers-reduced-motion: reduce) { .h13-trio.is-swept .h13-sweep::before { animation: none; } }

/* (b) the runway glow. Apple's pinned-device sections carry a layered
   gradient behind the machine; here it fades up only while the Talk about
   Ctrl callouts hold the screen, so the scrub itself stays clean. */
.egg-glow {
  position: absolute; left: 50%; top: 46%; width: 900px; height: 620px;
  margin: -310px 0 0 -450px; border-radius: 50%;
  background:
    radial-gradient(closest-side, rgba(255,107,61,.20), rgba(255,107,61,0) 70%),
    radial-gradient(closest-side at 32% 38%, rgba(255,138,91,.16), rgba(255,138,91,0) 72%),
    radial-gradient(closest-side at 70% 66%, rgba(255,107,61,.12), rgba(255,107,61,0) 74%);
  filter: blur(24px); opacity: 0;
  transition: opacity .7s var(--glide);
}
.scrub-sticky.is-tac .egg-glow { opacity: 1; }

/* (c) the rolling-digit ticker. One column per character; a digit column is
   a strip of whole-em cells that translates to the digit it lands on, 30ms
   after the column to its left. */
/* Round 53: every counter uses TABULAR figures, rolling and settled.

   The split-flap roll gives each digit its own inline-block cell holding a
   0-9 strip, so the cell is as wide as the WIDEST figure in that strip.
   Inter's default figures are proportional -- measured at the reports
   counter, "19" sets 18.13px while two full-width cells set 22.85px -- so a
   number was 26% wider while it rolled and snapped narrower the instant
   `settleRoll` replaced the reel with plain text. That is the "different
   spacing, then it changes" on screen, and it was on all 83 counters across
   13 pages, not just the one.

   Tabular figures make every digit one width, so the reel's cells and the
   settled text measure the same and nothing moves on landing. It is also
   simply the right setting for a number that animates.

   The rule itself lives in css/base.css, not here: this sheet is loaded
   LAST and not render-blocking, so a counter could paint proportional
   before it arrived (measured: one run in three). base.css is second in
   every page's order and already owns the other tabular settings. */
.roll { display: inline-flex; align-items: flex-end; }
/* Round 29, item 2: the reel's own boxes are SPANs inside somebody else's
   card, and the em the cell is measured in has to be the em the digits are
   set in. Any descendant-span rule in a host card that changed the font
   size, the family or the opacity used to land on the cell and not on the
   digit, and the window then showed a slice of the wrong glyph. The reel
   takes its type from the element that carries the number, always. */
.roll-s, .roll-d, .roll-strip { font: inherit; letter-spacing: inherit; opacity: 1; }
.roll-s { white-space: pre; }
.roll-d { display: inline-block; overflow: hidden; height: 1em; line-height: 1; }
.roll-strip { display: block; transform: translateY(0); }
.roll-strip b { display: block; height: 1em; line-height: 1; font-weight: inherit; }
.roll.is-roll .roll-strip {
  transform: translateY(calc(var(--n) * -1em));
  transition: transform .9s cubic-bezier(.16, 1, .3, 1);
}
@media (prefers-reduced-motion: reduce) {
  .roll.is-roll .roll-strip { transition: none; }
}

/* (d) the spotlight tile: a radial highlight that follows the pointer inside
   the black bento tiles. It sits under the tile's content (the tiles already
   have `isolation: isolate`), so it lights the ground and never the type. */
.db.has-spot::before, .offline-tile.has-spot::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  border-radius: inherit; opacity: 0;
  background: radial-gradient(220px circle at var(--mx, 50%) var(--my, 50%),
              rgba(255,107,61,.16), rgba(255,107,61,.05) 42%, transparent 70%);
  transition: opacity .3s var(--glide);
}
@media (hover: hover) and (pointer: fine) {
  .db.has-spot:hover::before, .offline-tile.has-spot:hover::before { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .db.has-spot::before, .offline-tile.has-spot::before { display: none; }
  .h13-sweep { display: none; }
  .egg-glow { display: none; }
}

/* (e) the headline shimmer: one pass, once, after the intro has handed over.
   The headline already paints itself through `background-clip: text`; the
   shimmer is a second background layer above that gradient, so nothing about
   the resting headline changes. */
.h13-head.is-shimmer {
  background-image:
    linear-gradient(100deg, rgba(255,255,255,0) 42%, rgba(255,255,255,.55) 50%, rgba(255,255,255,0) 58%),
    linear-gradient(180deg, #FFFFFF 0%, var(--hl-1) 55%, var(--hl-2) 100%);
  background-size: 260% 100%, 100% 100%;
  background-repeat: no-repeat;
  /* Round 17: opacity and transform are declared here because this rule
     replaces the h13pop shorthand the headline arrives on. Without them the
     entrance's `forwards` fill goes with it and `.h13-head`'s own
     `opacity: 0` reasserts itself -- the headline disappeared. */
  opacity: 1; transform: none;
  animation: headShimmer 1.2s cubic-bezier(.4, 0, .2, 1) 1 both;
}
@keyframes headShimmer {
  from { background-position: -160% 0, 0 0; }
  to   { background-position: 260% 0, 0 0; }
}

/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  Round 21 — the keynote bentos                                           ║
   ╚══════════════════════════════════════════════════════════════════════════╝
   Parth sent Apple's WWDC OS pages (iPadOS, macOS, watchOS, visionOS, tvOS,
   iOS) and asked for features to be showcased that way. Their grammar, as
   read off those pages and written down here once so three bentos can share
   it: the ground is light and the tiles are pure white; the radius is 24 and
   the gap is 12; there is no drawn edge to speak of, just a 1px hairline at 5
   percent and a very soft shadow, so the tile reads as a card lying ON the
   ground rather than a box cut INTO it; spans are mixed and dense; and every
   tile carries exactly one element plus one short centred label.

   This is deliberately the opposite of the same round's black tiles, which
   needed a hard 14 percent edge to exist at all against #000000. White on
   eggshell separates on value alone, so the edge can almost disappear.
   ------------------------------------------------------------------------ */
.kb {
  display: grid; gap: 12px;
  /* Round 23, item 1: the same rhythm as the "Fourteen modules" wall in
     css/site.css -- four columns, a 12px gap and rows that start at 150px
     and grow with what is in them. Spans are 1 or 2, the lead tile 2 by 2,
     and `dense` is what lets a span-1 tile fall into the hole a span-2
     leaves, so no row ever ends ragged. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: minmax(150px, auto);
  grid-auto-flow: dense;
}
.kb-t {
  position: relative; isolation: isolate; overflow: hidden; min-width: 0;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 14px; text-align: center;
  padding: 20px 18px;
  border-radius: 24px;
  background: #FFFFFF;
  border: 1px solid rgba(0,0,0,.05);
  box-shadow: 0 4px 14px rgba(0,0,0,.05);
  color: var(--n-900, #000);
  transition: transform .3s var(--glide), box-shadow .3s var(--glide);
}
@media (hover: hover) and (pointer: fine) {
  .kb-t:hover { transform: translateY(-2px); box-shadow: 0 10px 26px rgba(0,0,0,.09); }
  a.kb-t:hover { text-decoration: none; }
}
a.kb-t { text-decoration: none; color: inherit; }
/* Round 22, Apple Design audit section 1: every bento tile that is actually
   a link (`m-till.html`, etc.) had a hover lift and nothing on pointer-down
   -- the first feedback a touch user ever saw was the page already
   navigating. Press flattens it back toward the ground instead of lifting,
   the instant a finger lands. */
a.kb-t:active { transform: translateY(0) scale(.98); transition-duration: .1s; }
@media (prefers-reduced-motion: reduce) { a.kb-t:active { transform: none; } }

/* the one label, 17px / 600, centred, top or bottom of the tile */
.kb-l {
  margin: 0; font-size: 17px; font-weight: 600; line-height: 1.3;
  letter-spacing: -.01em; color: var(--n-900, #000); max-width: 22ch;
}
.kb-t.lab-top { flex-direction: column; }
.kb-t.lab-top .kb-l { order: -1; }

/* ---- number tiles: one value in the orange gradient, one label ---------- */
.kb-v {
  font-family: var(--font-display); font-weight: 700; font-size: 52px;
  line-height: 1.04; letter-spacing: -.035em; padding-bottom: .08em;
  background: var(--grad-text); -webkit-background-clip: text; background-clip: text;
  color: transparent; width: fit-content;
}
/* Round 30, item 3: a time reads "12 seconds". The number stays the tile's
   big value and the unit is its own smaller line under it, painted by the
   same gradient (it is text inside the value, so the value's own
   background-clip reaches it). Used by .kb-v and .db-v alike. */
.v-unit {
  display: block; font-size: .34em; font-weight: 600; letter-spacing: -.01em;
  line-height: 1.15; margin-top: .04em; padding-bottom: .06em;
}
/* while the reel is rolling the value is a flex row; the unit keeps its own line */
.roll:has(> .v-unit) { flex-wrap: wrap; }
.roll > .v-unit { flex: 0 0 100%; }
.kb-t .roll { justify-content: center; }
.kb-t .kb-cap { margin: 0; font-size: 13px; line-height: 1.4; color: var(--n-600, #6E6E73); max-width: 20ch; }

/* ---- gradient-text tiles: a two-word phrase and the line that explains it
   Round 26, item 3: the phrase used to be the whole tile. Two words in
   orange is a title, and a title on its own is decoration -- every other
   value tile on the site carries a caption, so this one does too, at the
   same 15px the black tiles use rather than the 13px the number tiles do,
   because it is a sentence and not a label. */
.kb-phrase {
  font-family: var(--font-display); font-weight: 700; font-size: 40px;
  line-height: 1.06; letter-spacing: -.035em; padding-bottom: .08em;
  background: var(--grad-text); -webkit-background-clip: text; background-clip: text;
  color: transparent; text-wrap: balance;
}
.kb-phrase-t { justify-content: flex-end; gap: 8px; }
.kb-phrase-t .kb-cap {
  font-size: 15px; line-height: 1.42; color: var(--n-600, #6E6E73); max-width: 42ch;
}
@media (max-width: 560px) { .kb-phrase-t .kb-cap { font-size: 14.5px; } }

/* ---- glossy 3D icon tiles ----------------------------------------------
   The one place on the site where an icon is an illustration rather than a
   naked glyph. Eight objects off a single nano_banana_pro sheet, sliced and
   exported at 512px so they are still over 2x at their 110px slot. The
   naked-glyph rule (round 14) is untouched everywhere else. */
.kb-obj { display: block; width: 110px; height: 110px; object-fit: contain; }

/* ---- photo and video tiles: the label sits over the foot in white ------- */
.kb-t.kb-media { padding: 0; justify-content: flex-end; align-items: stretch; }
.kb-media > img, .kb-media > video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: 0;
}
.kb-media .kb-l {
  position: relative; z-index: 2; color: #FFFFFF; max-width: none;
  padding: 16px 18px; text-align: left; text-shadow: 0 1px 12px rgba(0,0,0,.45);
}
.kb-media::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 64%;
  z-index: 1; pointer-events: none;
  /* Round 29, item 2: .55 at the foot left "Kitchen screens read the same
     orders." at 1.3:1 over the bright frames of its own loop and the module
     pages' stills at 1.8:1. The ramp is deeper and reaches its weight
     earlier, so the label's own band is dark wherever the picture is not. */
  background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,.18) 38%,
              rgba(0,0,0,.52) 66%, rgba(0,0,0,.82) 100%);
}

/* ---- UI fragment tiles: a real screen, cropped at the tile edge --------- */
/* ---- Round 25, item 11: a dark fragment on a dark tile ------------------
   This tile cropped the kitchen display, a `#1C1C1E` surface, into a pure
   white bento tile and then faded the two together with a white gradient
   across the bottom half. A screen does not dissolve into paper: the
   fragment lost its own bottom row, the white band read as a fault in the
   picture rather than as a label plate, and the tile disagreed with every
   other tile in the grid about what it was made of. The tile's own ground
   is the fragment's ground now, the fragment runs full bleed with no fade
   at all, and the label sits in eggshell at the foot over a soft dark
   gradient -- the same plate the photo tiles already use over their images.
   ------------------------------------------------------------------------- */
.kb-t.kb-frag {
  padding: 0; justify-content: flex-start; align-items: stretch; overflow: hidden;
  background: #1C1C1E; border-color: rgba(255,255,255,.10);
}
.kb-frag .kb-fragbox {
  position: absolute; left: 0; top: 0; width: 172%; pointer-events: none;
  transform: scale(.58); transform-origin: 0 0;
}
.kb-frag .kb-l {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 3; margin: 0;
  padding: 44px 18px 14px; text-align: center; max-width: none;
  color: var(--bone);
  background: linear-gradient(180deg, rgba(28,28,30,0) 0%, rgba(28,28,30,.78) 46%, rgba(28,28,30,.94) 100%);
}
a.kb-t.kb-frag:hover, .kb-t.kb-frag:hover { border-color: rgba(255,255,255,.18); }
/* the graph tiles put their label above the plot rather than over it: a
   fourteen-bar chart has no quiet corner for a line of text to sit in. */
.kb-t.kb-plot { justify-content: flex-start; gap: 10px; padding: 16px 18px 12px; }
.kb-plot .kb-l { order: -1; }
.kb-plot .kb-graph { flex: 1 1 auto; min-height: 0; width: 100%; }
.kb-plot .db-bars-plot { min-height: 0; }
.kb-plot .db-bars-ax { flex: 0 0 auto; padding-bottom: 2px; }

/* ---- the hero tile ------------------------------------------------------
   A full-bleed corner gradient that drifts over 14s, with "delEat" set in
   glossy glass type: white at 80 percent over a blurred copy of itself at 30
   percent, which is what gives the letters a body rather than a cut-out. */
.kb-hero { padding: 0; border: 0; overflow: hidden; }
.kb-hero .kb-grad {
  position: absolute; inset: -18%; z-index: 0;
  background:
    radial-gradient(60% 70% at 14% 20%, #FF6B3D 0%, rgba(255,107,61,0) 62%),
    radial-gradient(62% 72% at 72% 30%, #FFB088 0%, rgba(255,176,136,0) 66%),
    radial-gradient(52% 64% at 92% 96%, #C2F222 0%, rgba(194,242,34,0) 62%),
    linear-gradient(120deg, #FF5A1F 0%, #FF8A5B 52%, #FFB088 100%);
  animation: kbDrift 14s ease-in-out infinite alternate;
}
@keyframes kbDrift {
  from { transform: translate3d(-2.5%, -1.5%, 0) scale(1.04); }
  to   { transform: translate3d(2.5%, 1.5%, 0) scale(1.10); }
}
.kb-hero .kb-word {
  position: relative; z-index: 2; margin: 0;
  font-family: var(--font-display); font-weight: 800;
  /* Round 23, item 1: the hero tile is two of four columns now (658px at
     1440, down from 881), so the word is sized and nudged to clear the
     leaning phone rather than running under it -- "delEa" with the t behind
     glass is not a wordmark. */
  font-size: clamp(44px, 6vw, 86px); line-height: 1; letter-spacing: -0.04em;
  transform: translateX(-19%);
  color: rgba(255,255,255,.80);
  text-shadow: 0 1px 0 rgba(255,255,255,.55);
  -webkit-user-select: none; user-select: none;
}
.kb-hero .kb-word::before {
  content: attr(data-word); position: absolute; inset: 0; z-index: -1;
  color: rgba(255,255,255,.30); filter: blur(16px);
}
.kb-hero .kb-l { position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  padding: 16px; color: #FFFFFF; text-shadow: 0 1px 10px rgba(0,0,0,.28); }
/* the CSS iPhone leans across the hero's lower right corner */
.kb-hero .kb-phone {
  position: absolute; right: 2%; bottom: -28%; z-index: 2;
  transform: rotate(-12deg); transform-origin: 100% 100%;
  pointer-events: none; filter: drop-shadow(0 24px 48px rgba(0,0,0,.35));
}
.kb-hero .kb-phone .ph-box { --s: .42; perspective: none; }
/* the tile narrows a step before the phone breakpoint does, so the phone
   steps down with it rather than eating the wordmark (round 23, item 1). */
@media (max-width: 1200px) { .kb-hero .kb-phone .ph-box { --s: .30; } }

/* the graph tiles are the dashboard's own components on a white ground, so
   the three colours that were written for black are re-declared here rather
   than the components being forked. */
.kb-graph { width: 100%; height: 100%; display: flex; flex-direction: column; }
.kb-graph .db-bars { min-height: 0; margin-top: 0; }
.kb-graph .db-bars-hd b { color: var(--n-900, #000); }
.kb-graph .db-bars-hd i { color: var(--n-600, #6E6E73); border-color: rgba(0,0,0,.14); }
.kb-graph .dbar { background: rgba(0,0,0,.06); }
.kb-graph .db-bars-ax { color: var(--n-600, #6E6E73); }
.kb-graph .dr-last { background: rgba(0,0,0,.12); }
.kb-graph .dr-col em { color: var(--n-600, #6E6E73); }
.kb.is-in .kb-graph .dbar i { transform: scaleY(var(--v, 0)); }
.kb.is-in .kb-graph .dr-bar { transform: scaleY(1); }

/* ---- the swatch tile ---------------------------------------------------- */
.kb-sw { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }
.kb-sw i {
  display: block; width: 30px; height: 30px; border-radius: 999px;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.10);
}

/* ---- motion: a 30ms stagger in, and nothing that moves a tile off its row - */
/* round 30: a tile is hidden only once js/apple.js has armed its grid's
   observer (`.is-armed`), so a script that never runs leaves every tile on
   the page instead of seventeen blank cards. */
.kb.is-armed:not(.is-in) .kb-t { opacity: 0; transform: translateY(18px); }
/* Round 23, item 1: the scroll depth parallax is gone. `data-depth` rode
   each tile 6, 12 or 18px against the page, which meant no two tiles in a
   row ever shared a top edge -- measured at 1440 the highlights bento's
   first row sat at -34, -23, -11 and 0 -- and that, not the placement, is
   what read as "not aligned". The dashboard bento, which Parth calls right,
   never had it. Tiles rest where the grid puts them now; the entry stagger
   and the hover lift are the motion that is left. */
.kb.is-in .kb-t {
  opacity: 1; transform: none;
  transition: opacity .5s var(--glide) calc(var(--i, 0) * 30ms),
              transform .3s var(--glide), box-shadow .3s var(--glide);
}
@media (hover: hover) and (pointer: fine) {
  .kb.is-in .kb-t:hover { transform: translateY(-2px); }
}
@media (prefers-reduced-motion: reduce) {
  .kb-t { opacity: 1; transform: none; transition: none; }
  .kb-hero .kb-grad { animation: none; }
}

/* ---- phones: two columns, the hero first and full width -----------------
   1024 reads the desktop grid unchanged, which is the point of matching the
   modules wall: four columns all the way down to the phone breakpoint. */
@media (max-width: 700px) {
  .kb { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: minmax(136px, auto);
        gap: 10px; }
  .kb-t { grid-column: auto / span 1 !important; grid-row: auto !important; padding: 16px 12px; }
  .kb-hero { grid-column: 1 / -1 !important; grid-row: auto !important; min-height: 260px; order: -1; }
  .kb-t.kb-wide { grid-column: 1 / -1 !important; }
  .kb-v { font-size: 40px; }
  .kb-phrase { font-size: 28px; }
  .kb-obj { width: 78px; height: 78px; }
  .kb-l { font-size: 15px; }
  /* the phone leans further out and the word moves off centre: at 390 the
     two were fighting for the same 350px and "Eat" ended up behind glass. */
  .kb-hero { min-height: 300px; }
  .kb-hero .kb-word { font-size: 56px; transform: translate(-15%, -16%); }
  .kb-hero .kb-phone { right: -8%; bottom: -30%; }
  .kb-hero .kb-phone .ph-box { --s: .30; }
}


/* ---- Round 23, item 1: the highlights bento on the modules wall's rhythm
   Four columns, a 2-by-2 lead tile and nothing else wider than 2, so every
   row is exactly four cells and the grid closes. Sixteen tiles could not do
   that at a readable size (26 cells is six and a half rows); ten can, in
   four rows, which is also what brings the bento back under the old rail's
   height plus 200px. Round 21's five hand-placed rows are gone: spans plus
   `dense` place them, and the same spans survive the tablet and the phone.
   ------------------------------------------------------------------------ */
.kb-hl { margin-top: var(--bento-top); }
.kb-hl > .kb-hero { grid-column: span 2; grid-row: span 2; }
.kb-hl > .kb-wide { grid-column: span 2; }

/* ---- Round 21, item 2: "Which one are you" as a Watch-style bento -------
   The tab body was a list of eight module rows beside a photograph. The
   Watch reference Parth sent is the opposite shape: one big photo tile, a
   few white tiles carrying one point each, and a couple of small chip cards
   floating over the grid's edge as if they had been dropped on top. Same
   tile styling as every other bento here; the section head and the eight
   format tabs are untouched.
   ------------------------------------------------------------------------ */
.kb-svwrap { position: relative; margin-top: var(--s-5); }
/* Round 23, item 1: spans rather than hand-placed cells, on the same four
   columns as every other bento here. Eight tiles, 4 + 2 + 6 x 1 = twelve
   cells, three full rows at every width above the phone breakpoint. */
.kb-sv > .kb-t:nth-child(1) { grid-column: span 2; grid-row: span 2; }
/* Round 24, item 0: the wide slot is the middle of the third row now, which
   is the modules wall's own 1, 2, 1 rhythm, so it is read off the class the
   builder writes rather than a hand-counted child index. */
.kb-sv > .kb-wide { grid-column: span 2; }

.kb-mod { justify-content: flex-start; gap: 8px; padding: 20px 18px; }
.kb-mic { width: 28px; height: 28px; flex: 0 0 auto; color: var(--n-900, #000); }
.kb-mic use { fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.kb-mod .kb-l { font-size: 20px; font-weight: 600; letter-spacing: -.015em; }
/* Round 26: no clamp. The three-line `-webkit-line-clamp` here put an
   ellipsis inside four tiles of every "which one are you" panel and inside
   the module pages' own bentos -- a tile that ends in "..." is a tile that
   did not say its one thing. The rows are `minmax(150px, auto)`, so a tile
   grows to its copy instead, and where the copy is too long for that it is
   the copy that gets shorter. */
.kb-mline {
  margin: 0; font-size: 14px; line-height: 1.45; color: var(--n-600, #6E6E73);
}
@media (hover: hover) and (pointer: fine) { .kb-mod:hover .kb-mic { color: #FF6B3D; } }

/* Round 26, item 3: the two floating chip cards that hung over this grid's
   edge are gone from the markup (tools/build-serve.py) and their rules with
   them. They were the last floating chips on the page: a tile that has to
   escape its own grid to be read is a tile the grid has no room for. */

/* the tab crossfade: 200ms out, 250ms in, driven by js/site.js's select() */
.sv-panel.is-fading { opacity: 0; transition: opacity .2s var(--glide); }
.sv-panel.is-entering { animation: svFade .25s var(--glide) both; }
@keyframes svFade { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .sv-panel.is-fading { transition: none; }
  .sv-panel.is-entering { animation: none; }
}

@media (max-width: 900px) {
  .kb-sv > .kb-t:nth-child(1) { grid-column: 1 / -1 !important; grid-row: auto !important; min-height: 260px; }
}

/* ---- Round 21, item 3: the module pages' feature bento ------------------
   Auto-placed rather than hand-placed, because the number of features is a
   property of the module and runs from six to a dozen. `grid-auto-flow:
   dense` is what lets a span-1 tile fall back into the hole a span-2 left,
   so a page with an odd count still tiles without a gap.
   ------------------------------------------------------------------------ */
.kb-feat {
  margin-top: var(--bento-top);
  grid-auto-flow: dense;
  grid-auto-rows: minmax(150px, auto);
}
.kb-feat > .kb-f1 { grid-row: span 2; }
/* every tile carries the span the packer gave it, so the rows close exactly
   (round 23, item 1); `kb-wide` is still what the phone grid reads. */
.kb-feat > .kb-t { grid-column: span var(--span, 1); }
.kb-feat .kb-f-g, .kb-feat .kb-f-l { justify-content: flex-start; gap: 8px; padding: 20px 18px; }
.kb-feat .kb-f-n .kb-l, .kb-feat .kb-f-s .kb-l { font-size: 17px; }
/* round 30: no clamp here either; the tile grows to its sentence */
.kb-media .kb-mline { position: relative; z-index: 2; color: var(--nt-on-photo);
  padding: 0 18px 18px; text-align: left; margin: 0; }
.kb-media .kb-l + .kb-mline { padding-top: 0; }
.kb-media .kb-l { padding-bottom: 6px; }
/* Round 29, item 2: a media tile that carries a label AND a line under it
   has a text block roughly twice as tall, and its top sat above where the
   76 percent band had any weight at all: "Three service types" measured
   1.7:1 over the bright half of the module hero still. The band runs the
   whole tile for those, reaching its weight by the middle, which is where
   that block starts. Tiles with a label only keep the shorter ramp. */
.kb-media::after { height: 76%; }
.kb-media:has(.kb-mline)::after {
  height: 100%;
  background: linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,0,0,.22) 26%,
              rgba(0,0,0,.62) 48%, rgba(0,0,0,.80) 72%, rgba(0,0,0,.88) 100%);
}
@media (max-width: 700px) {
  /* the generic reset has to come FIRST: it and the two rules under it are
     all `!important` at the same specificity, so source order is what
     decides, and for eight rounds it decided the wrong way -- the module
     hero photo was half a phone wide because the reset sat after it. */
  .kb-feat > .kb-t { grid-column: auto / span 1 !important; }
  .kb-feat > .kb-t.kb-wide { grid-column: 1 / -1 !important; }
  .kb-feat > .kb-f1 { grid-column: 1 / -1 !important; grid-row: auto !important; min-height: 240px; }
  /* the odd narrow tile, marked by the builder, so the two-column grid
     closes on a full row rather than on one half-width orphan. */
  .kb-feat > .kb-odd { grid-column: 1 / -1 !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Round 24, item 4: the key CTAs as liquid glass
   Parth's references are frosted and liquid glass UI in a warm orange and
   muted grey palette. Here that is one recipe, applied to the six controls
   that actually ask for a click: the nav's two, the hero's key, the trial
   band's two and the local nav's Start free, plus the chapter pill's plus.
   Everything else on the site keeps the solid `.btn`.

   Contrast, measured rather than assumed. The orange glass is
   rgba(255,107,61,.85), so what the label actually sits on is the tint
   composited over whichever ground is behind it: #D85B34 over black and
   #FE7F58 over eggshell. Brand black on those is 5.49:1 and 8.40:1, both
   past 4.5. White on them is 3.83:1 and 2.50:1, both short -- which is why
   `.h13-key`'s white label, carried since round 13, is brand black now. The
   token file has said "ink on orange is 6.34:1, white is 2.83" since round
   10; the hero was the one place that did not follow it.
   ═════════════════════════════════════════════════════════════════════════ */
.nav-cta .btn,
#trial .hero-actions .btn,
.mh3-copy .hero-actions .btn,
.ln-cta.btn,
.h13-key,
.chapter-pill-open {
  position: relative; overflow: hidden; border: 0;
  -webkit-backdrop-filter: blur(12px) saturate(180%);
          backdrop-filter: blur(12px) saturate(180%);
  transition: transform .18s var(--glide), box-shadow .18s var(--glide),
              background-color .18s var(--glide);
}

/* the orange ones */
.nav-cta .btn.btn-primary,
#trial .hero-actions .btn.btn-primary,
.mh3-copy .hero-actions .btn.btn-primary,
.ln-cta.btn.btn-primary,
.h13-key,
.chapter-pill-open {
  --btn-bg: transparent; --btn-edge: transparent;
  background: rgba(255,107,61,.85);
  color: #000000; -webkit-text-fill-color: #000000;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.45),
    inset 0 -1px 0 rgba(0,0,0,.15),
    0 8px 22px rgba(255,107,61,.26);
}
.nav-cta .btn.btn-primary:hover,
#trial .hero-actions .btn.btn-primary:hover,
.mh3-copy .hero-actions .btn.btn-primary:hover,
.ln-cta.btn.btn-primary:hover,
.h13-key:hover {
  background: rgba(255,107,61,.94);
  transform: translateY(-1px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.55),
    inset 0 -1px 0 rgba(0,0,0,.18),
    0 12px 28px rgba(255,107,61,.34);
}
.chapter-pill-open:hover { background: rgba(255,107,61,.94); }

/* the clear ones: black at 6 percent on eggshell, white at 10 on black */
.nav-cta .btn.btn-ghost,
.mh3-copy .hero-actions .btn.btn-ghost,
#trial .hero-actions .btn.btn-ghost {
  --btn-bg: transparent; --btn-edge: transparent;
  background: rgba(0,0,0,.06); color: var(--ink);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.45),
    inset 0 -1px 0 rgba(0,0,0,.15),
    0 8px 22px rgba(0,0,0,.10);
}
.nav.on-dark .nav-cta .btn.btn-ghost,
#trial .hero-actions .btn.btn-ghost {
  background: rgba(255,255,255,.10); color: var(--bone);
}
.nav.on-dark .nav-cta .btn.btn-ghost:hover { background: rgba(255,255,255,.16); }

/* Round 53: the same button, over a black ground, on the glass pill. The
   rule above is bone on a 10% white fill -- correct on the black pill, and
   invisible once the pill is white glass (measured: #F7F3EE on
   rgba(255,255,255,.1)). Ink on a faint ink wash instead, with an ink
   hairline. Specificity has to match the rule above and add the state class,
   or it loses on source order. */
.nav.on-dark.over-dark .nav-cta .btn.btn-ghost {
  background: rgba(0,0,0,.06); color: var(--n-900); border-color: rgba(0,0,0,.18);
}
.nav.on-dark.over-dark .nav-cta .btn.btn-ghost:hover { background: rgba(0,0,0,.10); }
.nav-cta .btn.btn-ghost:hover,
.mh3-copy .hero-actions .btn.btn-ghost:hover,
#trial .hero-actions .btn.btn-ghost:hover {
  transform: translateY(-1px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.55),
    inset 0 -1px 0 rgba(0,0,0,.18),
    0 12px 28px rgba(0,0,0,.14);
}
.nav-cta .btn.btn-ghost:hover,
.mh3-copy .hero-actions .btn.btn-ghost:hover { background: rgba(0,0,0,.10); }
#trial .hero-actions .btn.btn-ghost:hover { background: rgba(255,255,255,.16); }

/* the press, under 100ms (round 22's pointer-down rule). The chapter pill is
   left out on purpose: its transform carries the plus's 45 degree rotation
   into the cross, and a scale written here would fight it. */
.nav-cta .btn:active,
#trial .hero-actions .btn:active,
.mh3-copy .hero-actions .btn:active,
.ln-cta.btn:active,
.h13-key:active { transform: scale(.97); transition-duration: .09s; }

/* the specular sweep: a 40 percent wide white band at 14 percent, 600ms */
.nav-cta .btn::after,
#trial .hero-actions .btn::after,
.ln-cta.btn::after,
.h13-key::after,
.chapter-pill-open::after {
  content: ''; position: absolute; top: -20%; bottom: -20%; left: -50%;
  width: 40%; pointer-events: none; opacity: 0;
  background: linear-gradient(100deg,
    rgba(255,255,255,0), rgba(255,255,255,.14) 50%, rgba(255,255,255,0));
}
@media (hover: hover) and (pointer: fine) {
  .nav-cta .btn:hover::after,
  #trial .hero-actions .btn:hover::after,
  .ln-cta.btn:hover::after,
  .h13-key:hover::after,
  .chapter-pill-open:hover::after { animation: gsweep .6s var(--glide) 1; }
}
@keyframes gsweep {
  from { transform: translateX(0);    opacity: 0; }
  18%  { opacity: 1; }
  to   { transform: translateX(430%); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .nav-cta .btn:active, #trial .hero-actions .btn:active,
  .ln-cta.btn:active, .h13-key:active { transform: none; }
  .nav-cta .btn:hover::after, #trial .hero-actions .btn:hover::after,
  .ln-cta.btn:hover::after, .h13-key:hover::after,
  .chapter-pill-open:hover::after { animation: none; }
}
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .nav-cta .btn, #trial .hero-actions .btn, .ln-cta.btn,
  .h13-key, .chapter-pill-open {
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  .nav-cta .btn.btn-primary, #trial .hero-actions .btn.btn-primary,
  .ln-cta.btn.btn-primary, .h13-key, .chapter-pill-open { background: var(--o-500); }
  .nav-cta .btn.btn-ghost,
  .mh3-copy .hero-actions .btn.btn-ghost { background: var(--surface); }
  #trial .hero-actions .btn.btn-ghost { background: #1C1C1E; }
}
@media (prefers-contrast: more) {
  .nav-cta .btn, #trial .hero-actions .btn, .ln-cta.btn, .h13-key { border: 2px solid var(--ink); }
  #trial .hero-actions .btn { border-color: var(--bone); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Round 24, item 5: frosted glass cards
   One recipe, on the four surfaces the brief names: the chapter sheet, the
   "Talk about Ctrl." callout plates, the floating chips in the "which one
   are you" bento, and the local nav bar. The bento TILES stay pure white and
   are not touched -- the WWDC grammar round 21 wrote down is that a tile is
   a card lying on the ground, and glass is for the things that float OVER
   the page.

   Ground: white at 55 percent on eggshell, #1C1C1E at 60 on black. Edge: one
   pixel of white at 40 percent. Under it, the warm glow, an orange radial at
   10 percent offset to the top left, painted as the surface's own lowest
   background layer rather than as a separate element behind it: a negative
   z-index child paints ABOVE its parent's background, not behind it, so it
   would never reach the backdrop-filter's sample anyway. What the glass
   actually refracts is item 6's drifting blobs, which are real siblings
   underneath.
   ═════════════════════════════════════════════════════════════════════════ */
.ch-sheet,
.tac-c,
.local-nav-in {
  -webkit-backdrop-filter: blur(18px) saturate(150%);
          backdrop-filter: blur(18px) saturate(150%);
  background:
    radial-gradient(72% 88% at 14% 8%, rgba(255,107,61,.10), rgba(255,107,61,0) 62%),
    rgba(255,255,255,.72);   /* was .55: denser so the links clear 4.5:1 over black; matches the CTA pill */
  border: 1px solid rgba(255,255,255,.40);
  box-shadow: 0 12px 40px rgba(0,0,0,.12);
}
/* the callout plates had no plate at all before this: they were type on the
   eggshell. --tac-pad carries the padding into the leader's own offset and
   into the row the callout is placed on, so the hairline still leaves the
   plate on the tablet's quarter and three-quarter lines to the pixel. */
.tac-c { --tac-pad: 14px; padding: var(--tac-pad) 16px; border-radius: var(--r-lg); }
.tac-lead { top: calc(11px + var(--tac-pad, 0px)); }
@media (min-width: 1200px) {
  .tac-c[data-tac="0"], .tac-c[data-tac="2"] {
    top: calc(var(--pad-t) + var(--pad-h) * .25 - 11px - var(--tac-pad));
  }
  .tac-c[data-tac="1"], .tac-c[data-tac="3"] {
    top: calc(var(--pad-t) + var(--pad-h) * .75 - 11px - var(--tac-pad));
  }
}
/* The sheet keeps its own radius (a bottom sheet on a phone is square along
   its foot) and its own lift: it is a modal over a dimmed page, and the card
   shadow above is not enough to separate it.

   It also keeps a much higher white, and the reason is measured rather than
   taste. The other three surfaces sit on EGGSHELL, so white at 55 percent
   composites to about #FB -- practically paper -- and --ink-2 body copy on
   it is past 10:1. The sheet sits over the dimmed, blurred page: 55 percent
   white over that scrim lands near #A9A9A9, where --ink-2 (#4D4D4D) measures
   3.60:1 and fails. 92 percent puts the ground at #EFEFEF, where the same
   body copy measures 7.35:1, and the callout plates on eggshell, at the
   brief's own 55 percent, land on #FDF7F3 and 7.96:1. Same material, same blur, same edge, same warm
   glow; only the ground it has to carry text against is different. */
.ch-sheet {
  box-shadow: var(--lift-4);
  background:
    radial-gradient(72% 88% at 14% 8%, rgba(255,107,61,.10), rgba(255,107,61,0) 62%),
    rgba(255,255,255,.92);
}

@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .ch-sheet, .tac-c, .local-nav-in {
    -webkit-backdrop-filter: none; backdrop-filter: none;
    background: var(--n-0);
  }
}
@media (prefers-contrast: more) {
  .ch-sheet, .tac-c, .local-nav-in { border: 2px solid var(--n-900); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Round 24, item 6: something for the glass to refract
   Frosted glass on flat eggshell blurs a flat colour, which is the same flat
   colour, so the material does not read. Where a glass surface from items 4
   and 5 sits on eggshell, one soft blob drifts behind it: orange at 12
   percent and chartreuse at 8, 400px across, blurred 80px, one 16s cycle.
   On black the hero's and the dashboard's existing glow blobs already do
   this job, so nothing is added there.

   Each blob is a `::before` on the glass surface's own PARENT with a
   negative z-index, which paints behind that parent's in-flow content (the
   glass) and above its background -- the one place a pseudo-element can sit
   and still be inside the backdrop-filter's sample.
   ═════════════════════════════════════════════════════════════════════════ */
.tac-list::before,
.kb-svwrap::before,
.local-nav::before {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
  width: 400px; height: 400px; border-radius: 50%;
  background:
    radial-gradient(circle at 38% 36%, rgba(255,107,61,.12), rgba(255,107,61,0) 62%),
    radial-gradient(circle at 66% 64%, rgba(194,242,34,.08), rgba(194,242,34,0) 60%);
  filter: blur(80px);
  animation: gdrift 16s ease-in-out infinite alternate;
}
.tac-list::before   { left: 4%;  top: 18%; }
.kb-svwrap::before  { left: -6%; top: 34%; }
.local-nav::before  { left: 8%;  top: -140px; }
@keyframes gdrift {
  from { transform: translate3d(0, 0, 0)        scale(1); }
  to   { transform: translate3d(46px, 28px, 0)  scale(1.08); }
}
@media (prefers-reduced-motion: reduce) {
  .tac-list::before, .kb-svwrap::before, .local-nav::before { animation: none; }
}
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  /* nothing left to refract, and under more contrast a decorative wash
     behind text is noise rather than depth */
  .tac-list::before, .kb-svwrap::before, .local-nav::before { display: none; }
}
@media (max-width: 700px) {
  /* a 400px blob under a 390px phone is a full-viewport wash, which is the
     one thing this must not become */
  .tac-list::before, .kb-svwrap::before, .local-nav::before { width: 240px; height: 240px; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Round 29, item 4: named galleries rail on the phone
   ───────────────────────────────────────────────────────────────────────
   Supersedes the standing "nothing rails on a phone" rule for two named
   galleries: the highlights bento and "which one are you". (Round 29 railed
   three more; round 30 gave the offline tiles, the Fourteen modules wall and
   the module pages' own bento back as phone bentos, see `.phb` below.) The
   desktop grids are untouched; this is a 900px-and-under branch.

   Apple's mechanics, not an approximation of them: one card per snap
   point, the next card peeking at 78vw, a 12px gap, the first card on the
   same line as the section head above it (the rail bleeds out of `.wrap`
   by exactly the gutter and puts it back as its own padding, so at 390 the
   card starts at the 20px the head starts at), momentum scrolling, and
   `overscroll-behavior-inline: contain` so a horizontal swipe can never
   hand its overflow to the page's vertical scroll. Nothing pins.
   ═══════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {
  .kb-hl, .kb-sv {
    display: flex; flex-wrap: nowrap; align-items: stretch;
    grid-template-columns: none; grid-auto-flow: row;
    gap: 12px;
    overflow: auto hidden;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--gutter);
    overscroll-behavior-inline: contain;
    -webkit-overflow-scrolling: touch;
    /* the snap is the only motion here: no smooth-scroll animation, which
       is also what reduced motion asks for, so there is nothing to switch */
    scroll-behavior: auto;
    scrollbar-width: none;
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
    /* room above and below the cards for a focus ring drawn OUTSIDE them:
       the rail clips its own block axis, and a ring inside a photo card is
       painted under the card's own positioned picture and scrim */
    padding-block: 6px 8px;
  }
  .kb-hl::-webkit-scrollbar, .kb-sv::-webkit-scrollbar { display: none; }
  .kb-hl:focus-visible, .kb-sv:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 3px;
  }
  .kb-hl > *, .kb-sv > * {
    flex: 0 0 78vw; width: 78vw; max-width: 78vw; min-width: 0;
    grid-column: auto !important; grid-row: auto !important;
    order: 0 !important;
    scroll-snap-align: start; scroll-snap-stop: always;
  }
  /* a card that links somewhere is a real tab stop, and the browser scrolls
     the rail to it on focus. The ring sits 3px OUTSIDE the card: measured, an
     inset ring on a photo card was painted beneath the card's own picture
     and scrim and never showed at all. */
  .kb-hl > a:focus-visible, .kb-sv > a:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 2px;
  }
}

/* the position indicator under a rail. Dots, never paddles: a thumb cannot
   hit a 28px paddle on a moving phone, and the rail is already the control. */
.rail-dots { display: none; }
@media (max-width: 900px) {
  .rail-dots {
    display: flex; justify-content: center; align-items: center;
    gap: 6px; margin-top: 14px; min-height: 10px;
  }
  .rail-dots i {
    width: 6px; height: 6px; border-radius: 999px; background: currentColor;
    opacity: .2; transition: opacity .25s var(--glide), transform .25s var(--glide);
  }
  .rail-dots i.on { opacity: .82; transform: scale(1.3); }
}
@media (prefers-reduced-motion: reduce) {
  .rail-dots i { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Round 30, item 2: the feature showcases are bentos on the phone
   ───────────────────────────────────────────────────────────────────────
   The Fourteen modules wall, the dashboard bento, the offline tiles and
   every module page's feature bento (`.phb` in the markup) are laid out on
   a phone the way the desktop lays them out: mixed tile sizes, not a list
   and not a rail. Six columns, an 8px gap, 16px from each edge of the
   screen, `dense` flow. Each tile carries its phone slot as `data-ph`:
   2 is a small square (about 114px at 390), 3 a half, 4 two thirds, 6 the
   full width. The rows are written so each closes at exactly six columns
   (index.html by hand, tools/build-modules.py by rule), and `--pho` is the
   phone order where a module page's reading order differs from its
   desktop packing.

   Content is re-fitted to its slot. A small square holds one number or one
   glyph and a label of one or two words (`.ph-sq`, present only in tiles
   the phone makes small, shown only there); everything else in that tile
   stands down on the phone. Sentences stay in the larger slots. Rows grow
   to their content (`minmax(square, auto)`), so nothing is ever clamped or
   cut, and a square keeps its width while its row sets its height.
   ═══════════════════════════════════════════════════════════════════════ */
.ph-sq { display: none; }
/* Round 56, item 3: the Fourteen modules wall is a horizontal gallery on a
   phone since Round 54 (the block near the end of this file), and every card
   in it now has one full phone layout. The square and half slots below are
   for the other .phb bentos and never apply inside .bento-wall, so the card
   that read "Kitchen" over a photograph and the tiny "0 orders lost" square
   cannot come back. */
@media (max-width: 700px) {
  .phb.phb:not(.bento-wall) {
    --ph-sq: calc((100vw - 72px) / 3 + 8px);
    display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
    grid-auto-flow: row dense; grid-auto-rows: minmax(var(--ph-sq), auto);
    gap: 8px; margin-inline: calc(16px - var(--gutter)); padding: 0;
    overflow: visible; scroll-snap-type: none;
  }
  .phb.phb:not(.bento-wall) > [data-ph] {
    order: var(--pho, 0); grid-row: auto !important;
    min-width: 0; width: auto; max-width: none; min-height: 0;
    border-radius: 20px;
  }
  .phb.phb:not(.bento-wall) > [data-ph="2"] { grid-column: span 2 !important; }
  .phb.phb:not(.bento-wall) > [data-ph="3"] { grid-column: span 3 !important; }
  .phb.phb:not(.bento-wall) > [data-ph="4"] { grid-column: span 4 !important; }
  .phb.phb:not(.bento-wall) > [data-ph="6"] { grid-column: span 6 !important; }

  /* the three slots larger than a square: one padding and one type step
     down from the desktop, because a half is 175px at 390 */
  .phb.phb:not(.bento-wall) > [data-ph="3"], .phb.phb:not(.bento-wall) > [data-ph="4"] { padding: 16px 14px; gap: 8px; }
  .phb.phb:not(.bento-wall) > [data-ph="3"] h3, .phb.phb:not(.bento-wall) > [data-ph="4"] h3 { font-size: 17px; line-height: 1.25; }
  .phb.phb:not(.bento-wall) > [data-ph="3"] p, .phb.phb:not(.bento-wall) > [data-ph="4"] p { font-size: 14px; line-height: 1.4; }

  /* ---- the small square ---- */
  .phb.phb:not(.bento-wall) > [data-ph="2"] {
    padding: 10px 8px; gap: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    text-align: center;
  }
  .phb.phb:not(.bento-wall) > [data-ph="2"] > :not(.ph-sq):not(img):not(video):not(picture):not(.bx-photo):not(.db-media) { display: none !important; }
  .phb.phb:not(.bento-wall) > [data-ph="2"] > .ph-sq {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 6px; position: relative; z-index: 3; min-width: 0; width: 100%;
  }
  .ph-sq .ph-v {
    display: block; font-family: var(--font-display); font-weight: 700;
    font-size: clamp(26px, 8.2vw, 36px); line-height: 1.05; letter-spacing: -.03em; padding-bottom: .06em;
    background: var(--grad-text); -webkit-background-clip: text; background-clip: text;
    color: transparent; -webkit-text-fill-color: transparent;
  }
  .ph-sq .ph-ic {
    width: clamp(24px, 7.4vw, 30px); height: clamp(24px, 7.4vw, 30px);
    stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round;
  }
  .ph-sq .ph-l {
    display: block; font-family: var(--font-ui); font-size: 12.5px; font-weight: 600;
    line-height: 1.2; letter-spacing: -.005em; overflow-wrap: normal; hyphens: none;
  }
  /* inks: black on the white and paper tiles, bone on the dark ones */
  .phb.phb:not(.bento-wall) > [data-ph="2"] .ph-sq { color: #000000; }
  .phb.phb > .db[data-ph="2"] .ph-sq, .phb.phb > .offline-tile[data-ph="2"] .ph-sq { color: #F7F3EE; }

  /* the Fourteen modules wall's own square, half and photo rules that used
     to sit here are gone (Round 56, item 3): the wall is the gallery in the
     Round 54 block near the end of this file. */

  /* ---- the dashboard bento ---- */
  .dbento.phb > .db { min-height: 0; padding: 16px 14px; }
  .dbento.phb > .db-1 { min-height: 0; padding: 18px; }
  .dbento.phb > .db-8 { min-height: 170px; }
  .dbento.phb .db-bars-plot { min-height: 60px; }
  .dbento.phb .db-drill { min-height: 96px; }
  .dbento.phb .db-rank .drk:nth-child(n+4) { display: none; }
  .dbento.phb > .db-6 .db-c { font-size: 13.5px; }
  .dbento.phb > .db-7 { min-height: 0; }
  .dbento.phb > .db-6 .db-v { font-size: 24px; }
  .dbento.phb > .db[data-ph="2"] { padding: 10px 8px; }

  /* ---- the offline tiles ---- */
  .offline-tiles.phb > .offline-tile { padding: 16px 14px; }
  .offline-tiles.phb > .offline-tile[data-ph="6"] { min-height: 260px; }
  .offline-tiles.phb > .offline-tile[data-ph="3"] {
    min-height: 236px; justify-content: flex-start; padding-right: 14px; padding-bottom: 104px;
  }
  .offline-tiles.phb > .offline-tile[data-ph="3"] > b { font-size: 24px; }
  .offline-tiles.phb > .offline-tile[data-ph="3"] > p { font-size: 13.5px; max-width: none; }
  /* a half is too narrow for a picture beside the words: the photograph is
     the tile's lower band instead, under the copy, with the button on it */
  .offline-tiles.phb > .offline-tile.ot-shot[data-ph="3"] .ot-photo {
    width: 100%; height: 96px; top: auto; bottom: 0; left: 0; right: 0;
  }
  .offline-tiles.phb > .offline-tile[data-ph="3"] .ot-chip { left: 12px; bottom: 12px; }
  .offline-tiles.phb > .offline-tile[data-ph="2"] { padding: 10px 8px; }

  /* ---- a module page's feature bento ---- */
  .kb-feat.phb > .kb-f1 { min-height: 240px; }
  .kb-feat.phb > [data-ph="3"] .kb-l, .kb-feat.phb > [data-ph="4"] .kb-l { font-size: 15.5px; max-width: none; }
  .kb-feat.phb > [data-ph="3"] .kb-mline, .kb-feat.phb > [data-ph="4"] .kb-mline { font-size: 13.5px; }
  .kb-feat.phb > [data-ph="3"] .kb-v, .kb-feat.phb > [data-ph="4"] .kb-v { font-size: 36px; }
  .kb-feat.phb > [data-ph="6"]:not(.kb-f1) { padding: 18px 16px; }
}
@media (max-width: 360px) {
  .ph-sq .ph-l { font-size: 11.5px; }
  .phb.phb > [data-ph="2"] { padding: 8px 6px; }
}

/* ============================================================================
   Round 34 (2026-09-14): the home page rebuilt around sofihealth, iyo and
   mute. GSAP ScrollTrigger + SplitText and Lenis drive it (js/scroll.js);
   everything below is the CSS side. Every state that hides or moves
   something is keyed to a class the script sets, so without the script the
   page is whole: sections keep their own grounds, phones sit side by side,
   the dashboard card lies flat.
   ========================================================================= */

/* ---- Lenis: the document scrolls natively under it, no CSS smoothing ------ */
html.lenis-smooth { scroll-behavior: auto !important; }

/* ---- item 1: one ground behind the page ---------------------------------
   `.ground34` is the only ground while html.g34 is set. Sections declare
   theirs and go transparent; their free text reads --g-* (written by
   js/scroll.js for whatever colour the ground has at that instant, each ink
   pushed toward black or white only as far as 4.5:1 needs). Tiles, cards,
   photographs and pills keep their own grounds and their own static tokens,
   keyed to the ground of the section they live in. The hero keeps its own
   black and its own blobs. */
.ground34 {
  position: fixed; left: 0; right: 0; top: 0; z-index: -1; pointer-events: none; background: #000000;
  /* Round 52b: the layer is as tall as the LARGE viewport, the one that
     includes the strip an iPhone's floating address bar sits over. At
     100% of the small viewport it stopped at the top of that bar, so
     there was nothing for Safari to blur through the bar and it fell back
     to a flat fill. Now the ground runs under it and the page shows
     through, the way apple.com does. lvh where it exists, the old
     behaviour where it does not. */
  height: 100vh; height: 100lvh;
  /* Round 53k: and past the bottom safe-area inset. Filmed 23 Sep 00:10: a
     uniform light band (luma 240 = the eggshell canvas) sat under the floating
     pill over black sections, hard-edged. If that is html showing where this
     layer stops, this closes it; if it is Safari's own band, it costs nothing. */
  height: calc(100lvh + env(safe-area-inset-bottom, 0px));
}
html.g34, html.g34 body { background: transparent; }
html.g34 [data-ground]:not(.hero13) {
  background-color: transparent !important; background-image: none !important;
  --ink: var(--g-ink); --ink-2: var(--g-ink-2); --ink-3: var(--g-ink-3);
  --accent-text: var(--g-accent); --line: var(--g-line);
  --hair: 1px solid var(--g-line);
  color: var(--ink);
}
html.g34 [data-ground]:not(.hero13) .section-head h2 {
  background-image: linear-gradient(180deg, var(--g-h0) 0%, var(--g-h1) 55%, var(--g-h2) 100%);
}
:where(html.g34 [data-ground="eggshell"]) :where(.kb-t, .bx, .mini-card, .plus-card, .cu-card, .chapter-pill,
  .moment-stage, .scrub-frame, .tac-c, .sv-pills, .ui-frame, .sx34, .pcf, .kb-fragbox) {
  --ink: #000000; --ink-2: #4D4D4D; --ink-3: #6E6D6B; --accent-text: #A13D20; --line: #DEDEDE;
  --hair: 1px solid #DEDEDE; color: var(--ink);
}
:where(html.g34 [data-ground="black"]) :where(.db, .offline-tile, .dash-new-card, .chapter-pill, .sc-stage,
  .cld-plate, .rl34-card, .db34-card, .kds2),
:where(html.g34 [data-ground="eggshell"]) :where(.bx.ink, .kb-frag, .kds2) {
  --ink: #F7F3EE; --ink-2: #A1A1A6; --ink-3: var(--hl-2); --accent-text: #FF906D; --line: #313131;
  --hair: 1px solid #313131; color: var(--ink);
}

/* ---- item 2: the statements ---------------------------------------------- */
.st34 { min-height: 100vh; min-height: 100svh; display: grid; place-items: center; }
.st34-in { text-align: center; }
.st34-line {
  margin: 0 auto; max-width: 13ch; text-wrap: balance;
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(48px, 9vw, 150px); letter-spacing: -0.045em; line-height: .95;
  color: var(--ink);
}
.st34-line .wr-w { will-change: opacity; }
.st34-sub { margin: clamp(22px, 2.4vw, 34px) auto 0; max-width: 44ch; font-size: 17px; line-height: 1.5; color: var(--ink-2); }
@media (max-width: 900px) { .st34 { min-height: 70svh; } .st34-line { font-size: clamp(44px, 12.4vw, 56px); max-width: 11ch; } }

/* the lede highlight is SplitText now, and gsap writes each word's opacity
   inline; the round 12 custom property and its transition would only lag it */
.wr .wr-w { display: inline-block; }

/* ═══════════════════ Round 63, item 5: the Ask delEat moment ═════════════
   A short, centred black section: eyebrow, headline, the 240px orb
   (js/orbs.js, 200px on phones), then the question and answer as a plain
   two-line exchange, a source pill and a text link to /m-ask. js/site.js
   runs the question/answer/orb cycle; everything here is layout only. */
.ask63 { text-align: center; }
.ask63-in {
  max-width: 640px; margin-inline: auto;
  display: grid; justify-items: center; gap: clamp(18px, 2.6vw, 28px);
}
.ask63-head { text-align: center; }
.ask63-head .eyebrow { justify-content: center; color: var(--ink-2); }
.ask63-head h2 { max-width: 20ch; margin-inline: auto; }
.ask63-orb { display: block; width: 240px; height: 240px; }
@media (max-width: 900px) { .ask63-orb { width: 200px; height: 200px; } }
.ask63-chat { display: grid; justify-items: center; gap: 8px; }
.ask63-q { margin: 0; font-size: 17px; line-height: 1.4; color: var(--ink-2); min-height: 1.4em; }
.ask63-a {
  margin: 0; max-width: 30ch; font-family: var(--font-display); font-weight: 600;
  font-size: clamp(19px, 2.2vw, 24px); line-height: 1.32; color: var(--ink);
  /* both lines reserved, so the link below never moves while the answer streams */
  min-height: 2.64em;
}
.ask63-src {
  margin: 4px 0 0; font-size: 12px; font-weight: 600; letter-spacing: .01em;
  color: var(--ink-2); border: 1px solid var(--nt-line); border-radius: var(--r-full);
  padding: 3px 10px; opacity: 0; transition: opacity var(--d-3) var(--glide);
}
.ask63-chat.is-done .ask63-src { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .ask63-src { transition: none; opacity: 1; } }

/* ---- item 3: the pocket, three phones to one ---------------------------- */
.pk34 { overflow: clip; }
.pk34-kick { display: flex; justify-content: center; margin: 0 0 clamp(16px, 2vw, 28px); }
.pk34.is-pinned .pk34-kick { position: absolute; bottom: 26px; left: 0; right: 0; z-index: 3; margin: 0; }
.pk34-pin { position: relative; }
.pk34-giant {
  margin: 0 0 clamp(20px, 3vw, 40px); width: max-content; max-width: none; white-space: nowrap;
  font-family: var(--font-display); font-weight: 800; font-size: clamp(56px, 12vw, 200px);
  letter-spacing: -0.045em; line-height: 1; padding-bottom: .08em;
  background-image: linear-gradient(180deg, var(--g-h0, #FFFFFF) 0%, var(--g-h1, var(--hl-1)) 55%, var(--g-h2, var(--hl-2)) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent; -webkit-text-fill-color: transparent;
  margin-inline: auto; opacity: .92;
}
.pk34-stage { display: flex; justify-content: center; align-items: center; gap: clamp(28px, 5vw, 96px); }
.pk34-ph .ph-box { --s: .62; }
.pk34-ph .phone { --ry: 0deg; --rx: 0deg; }
.pk34-view { padding: 70px 18px 0; }
/* The board still scrolls up under the status bar the way an app does, but
   the fade is painted now, not masked. Round 40, item 2: this view is the
   one copy of this markup whose feed is moved by a tween, so it is the one
   masked element on the site with a promoted child inside a `preserve-3d`
   phone; WebKit drops that subtree and the screen comes up blank, which is
   what Parth saw on the phone and never in the hero's still copy of the
   same board. A gradient in the screen's own ground is the same picture
   with no masked layer, and it keeps the board's own pixels untouched. */
.pk34-view::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 74px;
  z-index: 3; pointer-events: none;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--ui-bg) 100%, transparent) 0,
    color-mix(in srgb, var(--ui-bg) 100%, transparent) 50px,
    color-mix(in srgb, var(--ui-bg) 0%, transparent) 74px);
}
/* The feed keeps its layer where the board is scrubbed by the pin and there
   is no 3D phone rotating around it; on a phone it does not, so the one
   moving thing inside the shell is a plain transform. */
@media (min-width: 901px) { .pk34-feed { will-change: transform; } }
.pk34-sep { height: 18px; }
.pk34-feed .ph-hd + .ph-tiles, .pk34-feed .ph-tiles + .ph-hd { margin-top: 0; }
.pk34-menu { grid-template-columns: 1fr 1fr; padding: 0; gap: 8px; }
.pk34-menu .dish .nm { padding: 7px 9px 9px; }
.pk34-menu .dish .nm b { font-size: 12px; }
.pk34-menu .dish .nm span { font-size: 11px; }
.pk34-bill { margin-top: 10px; }
.pk34-lines { display: grid; grid-template-columns: 1fr auto; gap: 6px 10px; margin-top: 8px; font-size: 12px; }
.pk34-lines span:nth-child(2n) { font-variant-numeric: tabular-nums; }
.pk34-pay { margin-top: 12px; padding: 10px 12px; border-radius: 10px; background: #FF6B3D; color: #000000; font-weight: 700; font-size: 13px; text-align: center; }
.pk34-calls { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(16px, 2vw, 28px);
              width: min(100% - 2 * var(--gutter), var(--page-wide)); margin: clamp(32px, 4vw, 56px) auto 0; }
.pk34-call h3 { margin: 6px 0 0; font-family: var(--font-display); font-weight: 700; font-size: clamp(20px, 1.8vw, 26px); letter-spacing: -0.02em; line-height: 1.15; color: var(--ink); }
.pk34-call p { margin: 8px 0 0; font-size: 15px; line-height: 1.45; color: var(--ink-2); }
.pk34-call .pk34-eb { margin: 0; font-family: var(--font-mono); font-size: var(--t-xs); font-weight: 600; letter-spacing: var(--tr-caps); text-transform: uppercase; color: var(--accent-text); }
/* the pinned desktop stage */
.pk34.is-pinned .pk34-pin { height: 100vh; overflow: hidden; }
.pk34.is-pinned .pk34-giant { position: absolute; left: 0; top: 50%; margin: 0; transform: translateY(-50%); font-size: 13vw; z-index: 0; }
/* round 39, item 1: 13vw, and js/scroll.js computes the travel from the
   rendered width and the viewport so the whole line passes through. */
.pk34.is-pinned .pk34-stage { position: absolute; inset: 0; z-index: 1; gap: clamp(40px, 6vw, 110px); }
.pk34.is-pinned .pk34-calls { position: absolute; inset: 0; width: auto; margin: 0; display: block; z-index: 2; pointer-events: none; }
.pk34.is-pinned .pk34-call { position: absolute; width: min(21vw, 300px); }
.pk34.is-pinned .pk34-call.pk34-l { left: max(var(--gutter), 6vw); text-align: right; }
.pk34.is-pinned .pk34-call.pk34-r { right: max(var(--gutter), 6vw); }
.pk34.is-pinned .pk34-call:nth-child(1), .pk34.is-pinned .pk34-call:nth-child(3) { top: 12%; }
.pk34.is-pinned .pk34-call:nth-child(2), .pk34.is-pinned .pk34-call:nth-child(4) { bottom: 12%; }
@media (max-width: 900px) {
  .pk34-pl, .pk34-pr { display: none; }
  .pk34-ph .ph-box { --s: .7; }
  .pk34-calls { grid-template-columns: 1fr 1fr; }
  .pk34-giant { font-size: clamp(44px, 13vw, 72px); }
}
@media (max-width: 364px) { .pk34-ph .ph-box { --s: .62; } .pk34-calls { grid-template-columns: 1fr; } }
@media (prefers-reduced-motion: reduce) { .pk34-giant { width: auto; white-space: normal; text-align: center; font-size: clamp(44px, 8vw, 120px); } }
/* Round 59: the line travels on phones again (Round 57b's wrap removed; the travel is the point). */

/* ---- item 4: the dashboard, flat and exploded --------------------------- */
.db34 { margin-top: var(--bento-top); }
.db34-pin { position: relative; }
.db34-scene { position: relative; perspective: 1000px; padding-block: clamp(8px, 2vw, 24px); }
.db34-tilt { width: min(100%, 980px); margin-inline: auto; transform-style: preserve-3d; transform-origin: 50% 40%; will-change: transform; }
.db34-card {
  position: relative; box-sizing: border-box; padding: 8px; overflow: hidden;
  border-radius: var(--r-6); border: 4px solid #3A3A3C; background: #1C1C1E;
  box-shadow: 0 0 #0000004d, 0 9px 20px #0000004a, 0 37px 37px #00000042, 0 84px 50px #00000026, 0 149px 60px #0000000a;
  transform-style: preserve-3d;
}
.db34-fit { width: 1100px; transform: scale(var(--k, .8)); transform-origin: 0 0; transform-style: preserve-3d; }
.db34-ui { border-radius: 20px; }
.db34-ui .bento > .tile { will-change: transform; }
.db34.is-exploded .db34-card, .db34.is-exploded .db34-ui, .db34.is-exploded .db34-ui .ui-main,
.db34.is-exploded .db34-ui .bento { overflow: visible; transform-style: preserve-3d; }
.db34.is-exploded .db34-ui .bento > .tile { box-shadow: 0 18px 40px rgba(0,0,0,.45), 0 0 0 1px rgba(255,255,255,.08); }
.db34-leads { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 3; }
.db34-leads line { stroke: rgba(247,243,238,.5); stroke-width: 1; }
.db34-tags { position: absolute; inset: 0; margin: 0; padding: 0; list-style: none; pointer-events: none; z-index: 4; }
.db34-tags li {
  position: absolute; left: 0; top: 0; opacity: 0; white-space: nowrap;
  padding: 6px 12px; border-radius: 999px; background: #1C1C1E; border: 1px solid #3A3A3C;
  font: 600 13px/1.2 var(--font-ui); color: #F7F3EE;
}
.db34-list { display: none; }
/* round 39, item 9: .db34-iso is gone; the phone runs the one card. */
@media (max-width: 900px), (prefers-reduced-motion: reduce) {
  .db34-list { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; list-style: none; margin: 20px 0 0; padding: 0; }
  .db34-list li { padding: 7px 12px; border-radius: 999px; background: #1C1C1E; border: 1px solid #3A3A3C; color: #F7F3EE; font: 600 13px/1.2 var(--font-ui); }
  .db34-leads, .db34-tags { display: none; }
}
/* Round 39, item 9: the phone's second, static copy of the exploded card is
   gone. There is one card on the phone and it does the whole sequence in
   place: it tilts flat as it arrives and then explodes, both scrubbed by the
   scroll, with no pin (js/scroll.js). */
@media (max-width: 900px) {
  .db34-scene { overflow: visible; }
}

/* ---- Round 34, item 6: scroll media. Round 58: restored. Round 54 took
   this block out with the support scene next to it, which left the kitchen
   chapter's photograph and head unstyled: the head at 0px from the edge on
   a phone and under the photograph on a desktop. The head is the frame's
   sibling now (index.html): over the photograph on a desktop, on its bottom
   scrim, as round 34 drew it; under it on a phone, in the page's gutter and
   the till chapter's rhythm (28px, the kicker, 12px, the headline). ---- */
.sm34 { position: relative; margin-bottom: var(--sec-y); }
.sm34-pin { position: relative; padding-inline: var(--gutter); }
.sm34-frame { position: relative; aspect-ratio: 16 / 9; overflow: hidden; border-radius: var(--r-6); background: #E9E3DA; }
.sm34-media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.sm34-scrim { position: absolute; left: 0; right: 0; bottom: 0; height: 58%; pointer-events: none;
              background: linear-gradient(0deg, rgba(0,0,0,.66) 0%, rgba(0,0,0,.34) 55%, rgba(0,0,0,0) 100%); }
.sm34-copy { position: absolute; z-index: 2; left: calc(var(--gutter) + clamp(20px, 5vw, 80px)); right: calc(var(--gutter) + clamp(20px, 5vw, 80px)); bottom: clamp(24px, 5vw, 72px); }
.sm34-copy .kicker { color: rgba(255,255,255,.9); }
.sm34-copy h2 { margin-top: var(--s-3); max-width: 16ch; font-size: var(--t-2xl); color: #FFFFFF; -webkit-text-fill-color: #FFFFFF; background: none; }
.sm34.is-pinned { margin-bottom: 0; }
#dashboard, #onesystem { overflow-x: clip; }
.sm34.is-pinned .sm34-pin { height: 100vh; padding: 0; }
.sm34.is-pinned .sm34-frame { position: absolute; inset: 0; aspect-ratio: auto; border-radius: 0; }
.sm34.is-pinned .sm34-copy { left: clamp(20px, 5vw, 80px); right: clamp(20px, 5vw, 80px); }
@media (max-width: 900px) {
  .sm34 { margin-bottom: 0; }
  .sm34-pin { padding: 0; }
  .sm34-frame { aspect-ratio: 4 / 5; }
  html.g34 .sm34-frame { border-radius: 0; }
  /* Round 52: the loop is 16/9 and this frame is 4/5; the pour sits about
     three quarters of the way across, so the crop holds the right. */
  .sm34-media { object-position: 78% center; }
  .sm34-copy { position: static; padding: 28px var(--gutter) 0; text-align: center; }
  .sm34-copy .kicker {
    font-family: var(--font-mono); font-size: 11px; font-weight: 600;
    letter-spacing: var(--tr-caps); text-transform: uppercase; color: var(--accent-text);
  }
  .sm34-copy h2 {
    margin: var(--s-3) auto 0; max-width: 16ch; font-size: clamp(30px, 8.5vw, 38px);
    color: var(--ink); -webkit-text-fill-color: currentColor;
  }
}
/* reduced motion: the card never grows, so it keeps its gutter and radius
   (and on a phone the head under it drops its own gutter, the pin has it) */
@media (prefers-reduced-motion: reduce) {
  html.g34 .sm34-frame { border-radius: var(--r-6); }
  .sm34-pin { padding-inline: var(--gutter); }
}
@media (max-width: 900px) and (prefers-reduced-motion: reduce) { .sm34-copy { padding-inline: 0; } }
/* Round 58, item 4: one head grammar on a phone. The chapter heads (the
   till's, the kitchen's) take the section heads' own gaps: the eyebrow 18px
   over the headline, the lede 16px under it. */
@media (max-width: 900px) {
  .moment-copy h2, .sm34-copy h2 { margin-top: 18px; }
}

/* (Round 54, item 9a: the round 34 support scene, its three plates and
   its grid left the page; the "Why run on delEat" rail is in the Round 54
   block at the end of this file.) */

/* ---- the "One database" rail (round 34/39), unchanged ---------------- */
.rl34 { position: relative; margin-top: var(--s-7); }
.rl34-track {
  display: flex; gap: 16px; overflow-x: auto; overscroll-behavior-inline: contain;
  scroll-snap-type: x mandatory; scrollbar-width: none;
  margin-inline: calc(-1 * var(--gutter)); padding: 6px var(--gutter) 8px; scroll-padding-inline: var(--gutter);
}
/* the rail runs off the right edge of the window, the way mute's does; the
   section clips it (overflow-x: clip) so a classic scrollbar's width can never
   turn into sideways scroll */
@media (min-width: 901px) { .rl34-track { margin-right: calc(50% - 50vw); } }
.rl34-track::-webkit-scrollbar { display: none; }
.rl34-card {
  position: relative; flex: 0 0 clamp(250px, 23vw, 320px); aspect-ratio: 4 / 5;
  border-radius: var(--r-6); overflow: hidden; isolation: isolate; scroll-snap-align: start; background: #1C1C1E;
}
.rl34-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; }
.rl34-card::after { content: ""; position: absolute; inset: 34% 0 0 0; z-index: -1;
                    background: linear-gradient(0deg, rgba(0,0,0,.74) 0%, rgba(0,0,0,.46) 52%, rgba(0,0,0,0) 100%); }
.rl34-copy { position: absolute; left: 22px; right: 22px; bottom: 22px; }
.rl34-v { display: block; font-family: var(--font-display); font-weight: 800; font-size: clamp(46px, 4.4vw, 66px); letter-spacing: -0.045em; line-height: 1; color: #FFFFFF; }
.rl34-u { font-size: .4em; font-weight: 700; letter-spacing: -0.02em; margin-left: .22em; }
.rl34-l { margin: 8px 0 0; font-size: 15px; line-height: 1.35; color: #FFFFFF; max-width: 22ch; }
.rl34-more {
  margin-top: 16px; display: inline-flex; align-items: center; gap: 7px; height: 36px; padding: 0 15px;
  border: 0; border-radius: 999px; background: #FFFFFF; color: #000000; cursor: pointer;
  font: 600 14px/1 var(--font-ui);
  transition: transform var(--d-2) var(--glide);
}
.rl34-more svg { width: 12px; height: 12px; }
.rl34-more:active { transform: scale(.96); }
.rl34-more:focus-visible { outline: 2px solid #FFFFFF; outline-offset: 3px; }
.rl34-pad { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.rl34-arw { width: 44px; height: 44px; display: grid; place-items: center; border: 0; border-radius: 50%; cursor: pointer;
            background: var(--g-ink, #F7F3EE); color: var(--g-bg, #000); transition: opacity var(--d-2) var(--glide), transform var(--d-2) var(--glide); }
.rl34-arw svg { width: 16px; height: 16px; }
.rl34-arw:disabled { opacity: .3; cursor: default; }
.rl34-arw:not(:disabled):active { transform: scale(.94); }
@media (max-width: 900px) {
  .rl34-card { flex-basis: 78vw; }
  .rl34-track { gap: 12px; }
  .rl34-pad { display: none; }
}
@media (prefers-reduced-motion: reduce) { .rl34-more, .rl34-arw { transition: none; } }

/* the closing card */
.tr34-card {
  position: relative; isolation: isolate; overflow: hidden; border-radius: var(--r-6);
  min-height: clamp(420px, 54vh, 580px); display: grid; place-items: center; text-align: center;
}
.tr34-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: -2; }
.tr34-scrim { position: absolute; inset: 0; z-index: -1; background: rgba(0,0,0,.52); }
.tr34-in { padding: clamp(44px, 6vw, 96px) clamp(20px, 5vw, 80px); color: #FFFFFF; }
.tr34-in h2 {
  margin: 0 auto; max-width: 12ch; font-family: var(--font-display); font-weight: 800;
  font-size: clamp(48px, 8.2vw, 132px); letter-spacing: -0.045em; line-height: .95;
  color: #FFFFFF; -webkit-text-fill-color: #FFFFFF; background: none; text-wrap: balance;
}
.tr34-sub { margin: clamp(18px, 2vw, 26px) auto 0; max-width: 46ch; font-size: 17px; line-height: 1.5; color: #FFFFFF; }
.tr34 .hero-actions { justify-content: center; margin-top: clamp(24px, 3vw, 36px); }
.tr34 .cta-price-line { margin-top: 20px; color: #FFFFFF; }
.tr34 .cta-price-line a { color: #FFFFFF; text-decoration: underline; text-underline-offset: 3px; }
.tr34 .tr34-ghost { color: #FFFFFF; background: rgba(255,255,255,.14); box-shadow: inset 0 0 0 1px rgba(255,255,255,.5); }
@media (prefers-reduced-transparency: reduce) { .tr34 .tr34-ghost { background: #1C1C1E; } }

/* the split card */
.sx34 {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); overflow: hidden;
  border-radius: var(--r-6); background: #F7F3EE; border: 1px solid rgba(0,0,0,.07);
  box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 10px 30px rgba(0,0,0,.07), 0 30px 70px rgba(0,0,0,.07);
  min-height: clamp(340px, 34vw, 480px);
}
.sx34-photo { position: relative; min-height: 100%; }
.sx34-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.sx34-panel { display: flex; flex-direction: column; justify-content: flex-end; align-items: flex-start; gap: 28px;
              padding: clamp(28px, 4.4vw, 64px); color: #000000; }
.sx34-panel h2 { margin: 0; max-width: 13ch; font-family: var(--font-display); font-weight: 800;
                 font-size: clamp(34px, 4vw, 60px); letter-spacing: -0.04em; line-height: 1.02; color: #000000; }
@media (max-width: 900px) {
  .sx34 { grid-template-columns: 1fr; }
  .sx34-panel { order: -1; }
  .sx34-photo { aspect-ratio: 4 / 3; min-height: 0; }
}

/* ---- item 8: length. The statement above already carries a section's worth
   of air, so the split card starts on its padding; the kitchen runway gives
   back 10vh (its three beats keep their thirds of it). */
.sx34-sec { padding-top: 0; }
@media (min-width: 901px) { #scrub-kitchen { --scrub-h: 140vh; } }

/* the evidence strip follows the ground like the sections above it */
html.g34 .evid-line { color: var(--ink-2); }
html.g34 .evid-line a { color: var(--ink); }
html.g34 .evid-line a:hover { color: var(--accent-text); }
html.g34 .evid-line span.evid-sep { opacity: 1; color: var(--ink-3); }

/* ==========================================================================
   Round 35 (2026-09-14): seven refinements to the round 34 home page
   ========================================================================== */

/* ---- item 1: the photo card rail bleeds to both edges of the window and
   takes the site's rail fade (css/base.css), so a card leaving on either
   side fades instead of being cut. The first card still lands on the
   section's wrap line, as the padding and the snap padding say. */
.rl34-track {
  --rl-pad: max(var(--gutter), calc((100vw - var(--page)) / 2 + var(--gutter)));
  --fade-w: 48px;
  margin-inline: calc(50% - 50vw);
  padding-inline: var(--rl-pad);
  scroll-padding-inline: var(--rl-pad);
}
@media (max-width: 760px) { .rl34-track { --fade-w: 40px; } }

/* ---- item 2: "Everything is under Ctrl." is the brand moment, on black.
   Round 41, item 3: the keycap is a key again. Round 38 flattened fourteen
   3D layers into one to stop the edge flickering and what was left read as
   a flat square with a bite out of it. This is a real cap instead, drawn in
   two pieces on one layer and with no bite: a top face on the brand's own
   orange ramp with a fine light top edge and a soft inner bevel, and a
   darker side wall below it that gives the key its height. The wall is a
   little wider than the face on each side, which is the taper: the cap
   narrows as it rises. A soft contact shadow sits under it, on the ground.
   The press is the face travelling down its own wall and back, a transform
   and nothing else; no shadow and no clip path is ever animated, and the
   key holds its one compositor layer for the life of the section. */
.uc35 { position: relative; overflow: clip; }
.uc35 .st34-in { position: relative; z-index: 1; }
.uc35-ctrl {
  background-image: linear-gradient(180deg, #FFB298 0%, #FF906D 38%, #FF6B3D 70%, #E25D34 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
  padding-bottom: .06em;
}
.uc35-stage {
  height: clamp(210px, 19vw, 270px); margin: clamp(10px, 1.6vw, 22px) auto 0;
  display: grid; place-items: center;
}
.uc35-tilt { display: grid; place-items: center; }
.uc35-key {
  --k: 180px; --wall: 20px; --r: 22px; --flare: 2px; --press: 0px; --rise: 0px;
  position: relative; width: var(--k); height: calc(var(--k) + var(--wall));
  /* one layer, taken once and kept: the press repaints inside it and never
     asks the compositor for another (round 38's flicker) */
  will-change: transform; backface-visibility: hidden;
  transform: translateY(var(--rise));
}
/* the side wall: what gives the cap its height. It stands a little proud of
   the face on each side, so the cap reads as tapering in as it rises. */
.uc35-wall {
  position: absolute; left: calc(-1 * var(--flare)); right: calc(-1 * var(--flare));
  top: var(--wall); height: var(--k);
  border-radius: calc(var(--r) + 2px);
  /* the wall is darker than the face and its own shoulders catch a little
     light, so the sliver either side of the cap reads as a chamfer rather
     than a second square behind the first */
  background:
    linear-gradient(90deg, rgba(255,150,110,.30) 0, rgba(255,150,110,0) 12px,
                           rgba(255,150,110,0) calc(100% - 12px), rgba(140,44,18,.45) 100%),
    linear-gradient(180deg, #C2492A 0%, #A93E20 34%, #8E3016 74%, #7A2711 100%);
  box-shadow: inset 0 1px 0 rgba(255,178,152,.22);
}
/* the top face. The press moves this and only this. */
.uc35-face {
  position: absolute; left: 0; right: 0; top: 0; height: var(--k);
  display: grid; place-items: center;
  border-radius: var(--r);
  background: linear-gradient(168deg, #FFAC83 0%, #FF8557 30%, #FF6B3D 64%, #F1602F 100%);
  box-shadow:
    inset 0 1.5px 0 rgba(255,255,255,.52),
    inset 0 -1.5px 0 rgba(122,36,10,.34),
    inset 0 -20px 30px -14px rgba(122,36,10,.26),
    inset 4px 0 10px -8px rgba(255,255,255,.26),
    inset -4px 0 10px -8px rgba(122,36,10,.20);
  transform: translate(var(--px, 0px), calc(var(--press) + var(--py, 0px)));
}
.uc35-face b {
  font-family: var(--font-mono); font-weight: 700; font-size: calc(var(--k) * .21);
  letter-spacing: -.01em; color: #1A1411;
}
/* the contact shadow, under the key and on the ground. A gradient, not a
   blur: nothing here is filtered and nothing here is ever animated. */
.uc35-shade {
  position: absolute; left: -26%; right: -26%; top: 62%; bottom: -30%; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255,107,61,.32), rgba(255,107,61,.10) 54%, rgba(255,107,61,0));
  opacity: .78;
}
.uc35-cta { margin: 24px 0 0; }
.uc35-pill { border-radius: 999px; }
/* Round 52: the press pays off. The capsule is the same object as the key --
   a cap with a coloured edge -- so the section resolves from a generic ctrl
   key into the mark instead of parking a logo next to it. It is a plain
   <img>: no filter and no shadow, so it never asks the key's compositor
   layer for a second one. Visible by default; only the motion branch hides
   it before animating it in, which is why it survives no-JS and reduced
   motion (js/scroll.js, underCtrl). */
.uc35-lift { display: grid; place-items: center; will-change: transform; }
.uc35-logo {
  display: block; width: clamp(190px, 23vw, 320px); height: auto;
  will-change: transform; backface-visibility: hidden;
}
/* iyo's arcs: 1px rings at low opacity and a few brighter segments, centred
   on the key (js/scroll.js sets --cy and draws them). Static by default. */
.uc35-rings, .uc35 > .uc35-rings {
  position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
  /* the rings fade out over the section's top and bottom 120px, so they
     never stop on a line at the section's edge (item 4) */
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 120px, #000 calc(100% - 120px), transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 120px, #000 calc(100% - 120px), transparent);
}
.uc35-rings svg {
  position: absolute; left: 50%; top: var(--cy, 62%); width: max(1300px, 118vw); height: auto; aspect-ratio: 1;
  transform: translate(-50%, -50%); display: block; overflow: visible;
}
.a35-ring, .a35-seg, .a35-wave { fill: none; vector-effect: non-scaling-stroke; }
.a35-rot { transform-box: view-box; transform-origin: 50% 50%; animation: a35spin var(--dur, 90s) linear infinite; animation-direction: var(--dir, normal); }
@keyframes a35spin { to { transform: rotate(360deg); } }
.uc35 .a35-ring { stroke: #FFFFFF; stroke-opacity: .085; stroke-width: 1px; }
.uc35 .a35-seg { stroke-width: 1.5px; stroke-linecap: round; }
.uc35 .a35-seg.o { stroke: #FF6B3D; stroke-opacity: .75; }
.uc35 .a35-seg.w { stroke: #FFFFFF; stroke-opacity: .32; }
.uc35 .a35-wave { stroke: #FF906D; stroke-width: 1.5px; stroke-opacity: 0; }
@media (max-width: 900px) {
  .uc35-key { --k: 124px; --wall: 14px; --r: 15px; --flare: 1.5px; }
  .uc35-stage { height: 170px; margin-top: 8px; }
  .uc35-logo { width: clamp(170px, 56vw, 240px); }
  .uc35-rings svg { width: max(900px, 220vw); }
}
@media (prefers-reduced-motion: reduce) {
  .a35-rot { animation: none; }
  /* pressed and still: the face rests on its wall and nothing moves */
  .uc35-key { --press: var(--wall); }
}

/* ---- item 3: "Around the clock." Every person is wholly in one layer now:
   the seated colleague lives in the back plate (office-seated, the room with
   her in it) and the front cut-out carries only the two people nearest the
   camera (team-front). The layers start flush with the top of the frame and
   only rise, so the photograph's own headroom is all on screen, and the
   title sits in it, left, clear of both heads: sized in container units so
   it keeps the same place in the frame at every width. */
/* (rules removed in Round 54, item 9a) */

/* ---- item 4: no line where black meets eggshell. Every source found by
   sampling a 40px band across each boundary through each fade: the trust
   band's, the evidence strip's and the footer's hairlines (the footer now
   declares its ground and goes transparent with the rest); the dark bands'
   vignette (a per-section darkening that the one ground makes redundant);
   their grain tile and every particle canvas, which stopped dead at their
   section's edges and now fade out over the top and bottom 120px. */
html.g34 .trust, html.g34 .evid, html.g34 .foot { border-color: transparent; }
html.g34 .section.on-dark[data-ground]::before { display: none; }
html.g34 .section.on-dark[data-ground]::after,
.sec-web, .h13-web {
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 120px, #000 calc(100% - 120px), transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 120px, #000 calc(100% - 120px), transparent);
}

/* ---- item 5: the cash-up as a scene --------------------------------------
   Copy and three cards on the left, a calculator on the right with its
   paper tape feeding up out of a slot in its top edge. js/scroll.js drives
   the whole run from one progress value; without it the scene rests on its
   last frame (the tape whole, the variance green). */
.cz35-grid {
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
  gap: clamp(32px, 5vw, 84px); align-items: end;
}
.cz35 .section-head { max-width: 34rem; margin-bottom: 0; }
.cz35 .section-head h2 { max-width: 12ch; }
.cz35-cards { display: grid; gap: 14px; margin-top: clamp(26px, 3vw, 40px); max-width: 34rem; }
.cz35-card {
  display: grid; grid-template-columns: 112px minmax(0, 1fr); gap: 18px; align-items: center;
  background: #FFFFFF; border-radius: var(--r-5); padding: 14px 20px 14px 14px;
  box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 24px rgba(0,0,0,.06), inset 0 0 0 1px rgba(0,0,0,.045);
}
.cz35-t { display: grid; gap: 4px; }
.cz35-t b { font-family: var(--font-display); font-size: 17px; font-weight: 700; letter-spacing: -0.01em; color: #000000; }
.cz35-t small { font-size: 14px; line-height: 1.4; color: #4D4D4D; }
.cz35-art {
  position: relative; height: 84px; border-radius: 14px; background: #F7F3EE; overflow: hidden;
  display: grid; place-items: center;
}
/* 1. notes fanned, then squared into a banded stack */
.cz35-note {
  position: absolute; left: 50%; top: 50%; width: 58px; height: 32px; margin: -16px 0 0 -29px; border-radius: 5px;
  background: linear-gradient(135deg, #EFE9DC, #E2D8C4); box-shadow: 0 1px 0 rgba(0,0,0,.08), inset 0 0 0 1px rgba(0,0,0,.08);
  transform: translateY(calc(var(--n) * -2px));
}
.cz35-note::before { content: ""; position: absolute; right: 8px; top: 50%; width: 11px; height: 11px; margin-top: -5.5px; border-radius: 50%; border: 1.5px solid rgba(161,61,32,.55); }
.cz35-note::after { content: ""; position: absolute; left: 8px; top: 9px; width: 22px; height: 2px; border-radius: 1px; background: rgba(0,0,0,.14); box-shadow: 0 6px 0 rgba(0,0,0,.1); }
.cz35-band { position: absolute; left: 50%; top: 50%; width: 14px; height: 40px; margin: -24px 0 0 -7px; border-radius: 2px; background: #FF6B3D; box-shadow: 0 1px 0 #C14D2A; }
/* 2. the variance needle settles on zero, against a named person */
.cz35-var .cz35-art { grid-template-rows: auto auto; gap: 8px; align-content: center; }
.cz35-gauge { position: relative; width: 86px; height: 20px; border-bottom: 1.5px solid rgba(0,0,0,.2); }
.cz35-tick { position: absolute; bottom: -1.5px; width: 1.5px; height: 8px; background: rgba(0,0,0,.28); }
.cz35-tick.l { left: 0; } .cz35-tick.r { right: 0; } .cz35-tick.c { left: 50%; height: 12px; margin-left: -.75px; background: #0E5C40; }
.cz35-needle { position: absolute; left: 50%; bottom: -1px; width: 2px; height: 20px; margin-left: -1px; border-radius: 1px; background: #000000;
               transform-origin: 50% 100%; transform: translateX(var(--nx, 0px)); }
.cz35-needle::after { content: ""; position: absolute; left: -2.5px; top: -3px; width: 7px; height: 7px; border-radius: 50%; background: #000000; }
.cz35-chip { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding: 0 9px 0 3px; border-radius: 999px; background: #FFFFFF;
             font: 600 12px/1 var(--font-ui); color: #000000; box-shadow: inset 0 0 0 1px rgba(0,0,0,.08); }
.cz35-chip i { width: 18px; height: 18px; border-radius: 50%; display: grid; place-items: center; font-style: normal; font-size: 10px; color: #FFFFFF; background: #FF6B3D; }
.cz35-chip b { font-family: var(--font-mono); font-variant-numeric: tabular-nums; color: #0E5C40; font-weight: 700; }
/* 3. the Z-report prints and is stamped */
.cz35-zr .cz35-art { align-content: start; }
.cz35-printer { position: absolute; left: 50%; top: 10px; width: 72px; height: 8px; margin-left: -36px; border-radius: 4px; background: #1C1C1E; }
.cz35-slip {
  position: absolute; left: 8px; right: 8px; top: 4px; height: 62px; background: #FFFFFF; border-radius: 0 0 3px 3px;
  box-shadow: 0 2px 6px rgba(0,0,0,.08); display: grid; align-content: start; gap: 6px; padding: 10px 7px 0;
  clip-path: inset(0 0 var(--cut, 0%) 0); z-index: -1;
}
.cz35-slip i { height: 2px; border-radius: 1px; background: rgba(0,0,0,.16); }
.cz35-slip i:nth-child(2) { width: 70%; } .cz35-slip i:nth-child(4) { width: 48%; background: rgba(0,0,0,.3); }
.cz35-stamp {
  position: absolute; left: 50%; top: 44px; transform: translateX(-50%) rotate(-9deg) scale(var(--ss, 1)); opacity: var(--so, 1);
  padding: 3px 7px; border: 1.5px solid #C14D2A; border-radius: 5px; color: #A13D20; background: rgba(255,255,255,.85);
  font: 700 10.5px/1 var(--font-mono); letter-spacing: .06em; text-transform: uppercase; white-space: nowrap;
}

/* the calculator */
.cz35-stage { display: flex; justify-content: center; }
.cz35-calc { position: relative; width: min(100%, 372px); padding-top: 226px; }
.cz35-tapewin {
  position: absolute; left: 13%; right: 13%; top: 0; height: 238px; overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 70px);
          mask-image: linear-gradient(to bottom, transparent 0, #000 70px);
}
.cz35-roll {
  position: absolute; left: 0; right: 0; bottom: 12px; margin: 0; padding: 8px 12px 0; list-style: none;
  background: #FFFDF8; box-shadow: 0 1px 2px rgba(0,0,0,.06), 0 8px 18px rgba(0,0,0,.06);
  transform: translateY(var(--feed, 0px)); transition: transform .28s var(--glide);
}
.cz35-ln {
  display: flex; justify-content: space-between; gap: 10px; height: 24px; align-items: center;
  font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 12.5px; color: #1C1C1E;
}
.cz35-ln span { color: #6E6D6B; }
.cz35-ln b { font-weight: 600; }
.cz35-rule { border-top: 1px dashed rgba(0,0,0,.28); }
.cz35-rule span, .cz35-rule b { color: #000000; font-weight: 700; }
.cz35-ok b, .cz35-ok span { color: #0E5C40; }
.cz35-z span, .cz35-z b { color: #000000; font-weight: 700; }
.cz35-tear { height: 12px; margin: 2px -12px 0; background:
  linear-gradient(135deg, #FFFDF8 33%, transparent 33.5%) 0 0 / 10px 10px repeat-x,
  linear-gradient(225deg, #FFFDF8 33%, transparent 33.5%) 0 0 / 10px 10px repeat-x; }
.cz35-body {
  position: relative; z-index: 1; border-radius: var(--r-6); padding: 20px 20px 22px;
  background: linear-gradient(180deg, #FFFFFF, #FAF7F3);
  box-shadow: 0 1px 2px rgba(0,0,0,.05), 0 14px 36px rgba(0,0,0,.10), 0 40px 80px rgba(0,0,0,.08), inset 0 0 0 1px rgba(0,0,0,.05);
}
.cz35-slot { position: absolute; left: 11%; right: 11%; top: -3px; height: 8px; border-radius: 5px; background: #1C1C1E; box-shadow: inset 0 -2px 0 rgba(255,255,255,.08); }
.cz35-disp {
  display: grid; gap: 6px; padding: 14px 16px 12px; border-radius: 16px; background: #0B0B0C; color: #F7F3EE;
  box-shadow: inset 0 2px 8px rgba(0,0,0,.6);
}
.cz35-mode { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; font: 500 11px/1.2 var(--font-mono); color: var(--hl-2); letter-spacing: .02em; }
.cz35-mode i { font-style: normal; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cz35-lab { font-style: normal; color: #A1A1A6; text-transform: uppercase; letter-spacing: .08em; white-space: nowrap; }
.cz35-num { display: block; text-align: right; font: 600 clamp(30px, 3vw, 40px)/1.05 var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; white-space: nowrap; overflow: hidden; }
.cz35-disp.is-ok .cz35-num, .cz35-disp.is-ok .cz35-lab { color: #3DDC97; }
.cz35-fn { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 14px; }
.cz35-keys { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 10px; }
.cz35-k {
  --face: #F3EEE8; --edge: #D6CCBF; --fg: #1C1C1E;
  display: grid; place-items: center; height: 48px; border-radius: 12px; font-style: normal;
  font: 600 18px/1 var(--font-mono); color: var(--fg); background: var(--face);
  box-shadow: 0 3px 0 var(--edge), 0 4px 8px rgba(0,0,0,.06);
  transition: transform .09s var(--snap), box-shadow .09s var(--snap), filter .09s;
}
.cz35-k.cz35-ko { --face: #1C1C1E; --edge: #000000; --fg: #F7F3EE; }
.cz35-k.cz35-kf { --face: #FF6B3D; --edge: #C14D2A; --fg: #1A1411; height: 38px; font: 700 12px/1 var(--font-ui); letter-spacing: .04em; text-transform: uppercase; }
.cz35-k.is-down { transform: translateY(3px); box-shadow: 0 0 0 var(--edge), 0 1px 2px rgba(0,0,0,.05); filter: brightness(.95); }
@media (max-width: 900px) {
  .cz35-grid { grid-template-columns: minmax(0, 1fr); align-items: start; row-gap: 32px; }
  .cz35-copy { display: contents; }
  .cz35 .section-head { order: 1; }
  .cz35-cards { margin-top: 0; }
  .cz35 .section-head h2 { max-width: 14ch; }
  .cz35-stage { order: 2; }
  .cz35-cards { order: 3; max-width: none; }
}
@media (max-width: 520px) {
  .cz35-card { grid-template-columns: 108px minmax(0, 1fr); gap: 14px; padding: 12px 14px 12px 12px; }
  .cz35-chip { gap: 4px; padding-right: 7px; font-size: 11px; }
  .cz35-art { height: 76px; }
  .cz35-calc { padding-top: 200px; }
  .cz35-tapewin { height: 212px; }
  .cz35-k { height: 44px; }
}
@media (prefers-reduced-motion: reduce) { .cz35-roll, .cz35-k { transition: none; } }

/* ---- item 6: the exploded dashboard keeps every corner. Exploding needs
   `overflow: visible` on the card and the screen (anything that clips would
   flatten the 3D stack), so nothing may rely on the screen's clip for its
   corners: the white rail, the one child that reached the screen's corners,
   carries the screen's own 20px on its left side, and the tiles are
   rasterised at the scale they are drawn at (no frozen will-change layer),
   so each keeps its own radius at every point of the tilt and explosion. */
.db34-ui > .ui-rail { border-top-left-radius: 20px; border-bottom-left-radius: 20px; }
.db34-ui .bento > .tile { will-change: auto; }

/* ---- item 7, as round 36 left it: "Talk about Ctrl." is a black section.
   Two layers under the tablet, inside the till's sticky and faded out over
   its top and bottom 120px so neither ends on a line: the particle field
   (js/apple.js, clipped clear of the heading, the beat line and the
   callouts) and a warm orange glow that breathes, centred on the tablet by
   js/scroll.js. The round 35 rings and outlined line are gone. */
.tk35 {
  position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 120px, #000 calc(100% - 120px), transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 120px, #000 calc(100% - 120px), transparent);
}
#scrub-till .tac-head { position: relative; }
.tk36-web { position: absolute; inset: 0; width: 100%; height: 100%; display: block; pointer-events: none; }
.tk36-gp { position: absolute; inset: 0; transform-origin: var(--cx, 50%) var(--cy, 55%); }
.tk35-glow {
  position: absolute; left: var(--cx, 50%); top: var(--cy, 55%); width: min(1400px, 104vw); height: min(940px, 92vh);
  transform: translate(-50%, -50%); border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255,107,61,.5), rgba(255,122,72,.24) 50%, rgba(255,107,61,.08) 76%, rgba(255,107,61,0) 100%);
}
@media (prefers-reduced-motion: no-preference) {
  .tk35-glow { animation: tk36breathe 7s ease-in-out infinite alternate; }
}
@keyframes tk36breathe {
  from { opacity: .64; transform: translate(-50%, -50%) scale(.9); }
  to   { opacity: 1;   transform: translate(-50%, -50%) scale(1.06); }
}
@media (max-width: 900px) { .tk35-glow { width: 130vw; height: 70vh; } }

/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  Round 36 (2026-09-15)                                                   ║
   ╚══════════════════════════════════════════════════════════════════════════╝ */

/* ---- item 1: "Talk about Ctrl." on black ---------------------------------
   The runway and the pill under it declare a black ground. The heading takes
   the hero's white gradient, the callouts are dark frosted glass (#1C1C1E at
   70 percent, the site's 18px blur, a 1px white-at-12-percent edge, a white
   title and a var(--nt-ink-2) line) and the leaders are white at 30 percent. The
   eggshell blob behind the plates goes: the glow is what they frost now. */
#scrub-till .tac-head h3 {
  background-image: linear-gradient(180deg, #FFFFFF 0%, var(--hl-1) 52%, var(--hl-2) 100%);
}
#scrub-till .tac-c {
  background: rgba(28, 28, 30, .7);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
          backdrop-filter: blur(18px) saturate(150%);
  border: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .45);
}
#scrub-till .tac-c b { color: #FFFFFF; }
#scrub-till .tac-c span { color: var(--nt-ink-2); }
#scrub-till .tac-lead { background: #FFFFFF; opacity: .3; }
#scrub-till .tac-list::before { display: none; }
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  #scrub-till .tac-c { -webkit-backdrop-filter: none; backdrop-filter: none; background: #1C1C1E; }
}
@media (prefers-contrast: more) { #scrub-till .tac-c { border: 2px solid #FFFFFF; } }

/* ---- item 3: the pricing split card, completed ----------------------------
   Glyph and eyebrow, headline, the plan line, the button, the payment marks.
   The panel stacks from the top now, one rhythm: 12px inside the head, the
   headline 20px under it, 28px to the button, 28px to the marks. */
.sx34-panel { justify-content: center; gap: 0; }
.sx36-top { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
.sx36-ic { width: 32px; height: 32px; color: #FF6B3D; stroke-width: 1.6; vertical-align: 0; flex: none; }
.sx36-eyebrow { margin: 0; font-family: var(--font-display); font-weight: 600; font-size: 13px; line-height: 1.2;
                letter-spacing: .12em; text-transform: uppercase; color: #A13D20; }
.sx36-line { margin: 16px 0 28px; max-width: 34ch; font-size: 17px; line-height: 1.5; color: #4D4D4D; }
.sx36-marks { margin-top: 28px; gap: 22px; justify-content: flex-start; }
.sx36-marks .pay-ic { fill: #000000; }
@media (max-width: 700px) { .sx36-marks { gap: 16px; } .sx36-marks .pay-ic { height: 24px; } }

/* ---- item 4: a stronger hero -----------------------------------------------
   The same content, landing harder. The headline is much larger (Inter 800,
   the white gradient) and enters character by character on load, each rising
   out of its own line's mask (js/scroll.js, SplitText); iyo's stage rises
   behind the devices; on a desktop the hero pins for 60vh while the headline
   steps back and fades, the trio comes up toward the reader and the rings
   widen. Everything still fails open: without script, or with the clock
   held, the settled hero is exactly what shows. */
.h13-stack { max-width: min(1320px, 100%); }
.h13-head { font-size: clamp(56px, 10vw, 168px); letter-spacing: -0.045em; line-height: 1.0; padding-bottom: .1em; }
/* Round 57b: on a desktop the headline is sized off the window's height as
   well as its width (--h13-f, with the rest of the copy block's rhythm, at
   the Round 57b block after the phone hero rules) so the film fits the fold */
@media (min-width: 901px) { .h13-head { font-size: var(--h13-f); } }
@media (max-width: 900px) { .h13-head { font-size: clamp(44px, 14.6vw, 76px); } }
/* the CSS path waits a beat longer, so the character entrance (which starts
   as soon as the script arrives, inside that beat) never follows a headline
   the reader has already seen; if the script is late the headline pops in
   exactly as before */
/* the split: every character carries its own slice of the one gradient
   (background size and position written per character), since a transformed
   child is not painted through its parent's text clip */
.h13-head.is-split { background-image: none; }
.h13-head .h36-ch {
  display: inline-block; will-change: transform;
  background-image: linear-gradient(180deg, #FFFFFF 0%, var(--hl-1) 52%, var(--hl-2) 100%);
  background-repeat: no-repeat;
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
.h13-head .h36-ln-mask { padding: .12em .08em .16em; margin: -.12em -.08em -.16em; }

/* round 39, item 2: the round 36 concentric half-arcs behind the device
   trio are gone; the hero keeps the particle field, the glow and the
   devices. */
.h13-trio { transform-origin: 50% 100%; }

/* ---- item 5: the Features page speaks the home page's language ------------
   Each family is a section on the one ground (black and eggshell in turn),
   with a SplitText head, a bento on the Fourteen modules span pattern that
   mixes photo, number, chart, fragment, glyph and phrase tiles, and a row of
   links to its module pages. On black the tiles are the dashboard's own
   #1C1C1E with a 1px white-at-8-percent edge. */
.fam36 { scroll-margin-top: 90px; }
.fam36 .section-head { max-width: 780px; }
.fam36 .kb-feat { margin-top: clamp(28px, 3vw, 44px); }
.kb-dark > .kb-t { background: var(--nt-surface); border-color: var(--nt-hair); color: var(--bone);
  box-shadow: var(--nt-lift-1); }
.kb-dark > .kb-t .kb-l { color: var(--bone); }
.kb-dark > .kb-t .kb-mline, .kb-dark > .kb-t .kb-cap { color: var(--nt-ink-3); }
.kb-dark > .kb-t .kb-mic { color: var(--bone); }
.kb-dark > .kb-media .kb-mline { color: var(--nt-on-photo); }
@media (hover: hover) and (pointer: fine) {
  .kb-dark > .kb-t:hover { box-shadow: var(--nt-lift-2); border-color: var(--nt-hair-2); }
}
/* the charts: white tiles take the graph palette above; dark tiles keep the
   dashboard's own colours */
.kb-dark .kb-graph .db-bars-hd b { color: #F7F3EE; }
.kb-dark .kb-graph .db-bars-hd i { color: #A1A1A6; border-color: #3A3A3C; }
.kb-dark .kb-graph .dbar { background: rgba(255,255,255,.07); }
.kb-dark .kb-graph .db-bars-ax { color: var(--hl-2); }
.kb-dark .kb-graph .dr-last { background: rgba(255,255,255,.16); }
.kb-dark .kb-graph .dr-col em { color: #A1A1A6; }
.kb-graph .db-scatter { min-height: 150px; flex: 1 1 auto; }
.kb-graph .dsc-plot { border-color: rgba(0,0,0,.16); }
.kb-graph .dsc-dot { background: rgba(0,0,0,.30); }
.kb-graph .dsc-dot.is-hero { background: #FF6B3D; }
.kb-graph .dsc-ax-y, .kb-graph .dsc-ax-x { color: #6E6E73; }
.kb-dark .kb-graph .dsc-plot { border-color: rgba(255,255,255,.14); }
.kb-dark .kb-graph .dsc-dot { background: rgba(255,255,255,.42); }
.kb-dark .kb-graph .dsc-dot.is-hero { background: #FF6B3D; }
.kb.is-in .kb-graph .dsc-dot { opacity: 1; transform: none; }
.kb.is-in .kb-graph .dsc-dot.is-hero { animation: dscPulse 2.4s var(--glide) 1.1s 2; }
.kb-t.kb-plot .kb-graph { min-height: 150px; }
.kb-t.kb-plot .db-range { min-height: 110px; }
/* the number tiles roll (js/apple.js); the value stays centred while it does */
.kb-f-n .kb-v { font-size: clamp(52px, 5vw, 72px); }
.kb-f-n .kb-l { max-width: 18ch; color: var(--n-600, #6E6E73); font-weight: 500; font-size: 15px; }
.kb-dark > .kb-f-n .kb-l { color: #A1A1A6; }

/* the live fragments: real interface markup on the tile's own dark ground,
   cropped at the tile's edge, the label on a plate at the foot */
.kb-frag36 { min-height: 280px; }
.kb-frag36 .kb-fragbox { width: calc((100% - 28px) / .66); transform: scale(.66); left: 14px; top: 14px; }
.kb-frag36 .fr36, .kb-frag36 .kds2 { width: 100%; box-sizing: border-box; }
.kb-frag36 .kds2 { padding: 18px; border-radius: 18px; }
.kb-frag36 .kds2 > .kds { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.fr36 { width: 520px; max-width: 100%; padding: 22px; border-radius: 22px; background: #2C2C2E; color: #F7F3EE;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08); font-size: 16px; }
.fr36-hd { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; margin-bottom: 16px; }
.fr36-hd b { font-size: 22px; font-weight: 700; letter-spacing: -.02em; }
.fr36-hd span { color: #A1A1A6; font-family: var(--font-mono); font-size: 15px; }
.fr36-seg, .fr36-ways { display: flex; gap: 4px; padding: 4px; border-radius: 999px; background: rgba(255,255,255,.06); margin-bottom: 12px; }
.fr36-seg b, .fr36-ways b { flex: 1; text-align: center; padding: 9px 0; border-radius: 999px; font-weight: 600; font-size: 15px; color: #A1A1A6; }
.fr36-seg b.on, .fr36-ways b.on { background: #FF6B3D; color: #000000; }
.fr36-rows { list-style: none; margin: 6px 0 0; padding: 0; display: grid; gap: 6px; }
.fr36-rows li { display: flex; justify-content: space-between; padding: 12px 14px; border-radius: 12px; background: rgba(255,255,255,.05);
  font-family: var(--font-mono); font-size: 16px; }
.fr36-rows li b { font-weight: 600; }
.fr36-tot { display: flex; justify-content: space-between; margin-top: 12px; padding-top: 12px; border-top: 1px dashed rgba(255,255,255,.18);
  font-family: var(--font-mono); color: #A1A1A6; }
.fr36-tot b { color: #34C759; }
.fr36-grp { margin: 4px 0 10px; font-weight: 600; font-size: 15px; }
.fr36-grp em { font-style: normal; font-weight: 500; color: #FF906D; margin-left: 8px; font-size: 13px; }
.fr36-opts { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.fr36-opts b { padding: 10px 14px; border-radius: 12px; background: rgba(255,255,255,.06); font-weight: 600; font-size: 15px; color: var(--nt-ink-2);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.08); }
.fr36-opts b.on { background: rgba(255,107,61,.16); color: #FFFFFF; box-shadow: inset 0 0 0 1.5px #FF6B3D; }
.fr36-note { padding: 12px 14px; border-radius: 12px; background: rgba(255,255,255,.05); color: var(--nt-ink-2); margin-bottom: 14px; }
.fr36-add { display: flex; justify-content: space-between; align-items: center; }
.fr36-add span { color: #A1A1A6; font-size: 14px; }
.fr36-add b { padding: 11px 18px; border-radius: 999px; background: #FF6B3D; color: #000; font-weight: 700; font-size: 15px; }
.fr36-disp { padding: 16px 18px; border-radius: 14px; background: #000000; display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 10px; }
.fr36-disp span { color: #A1A1A6; font-size: 14px; }
.fr36-disp b { font-family: var(--font-mono); font-size: 34px; color: #34C759; font-weight: 600; }
.fr36-keys { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 12px; }
.fr36-keys b { padding: 12px 0; text-align: center; border-radius: 10px; background: #F7F3EE; color: #000; font-weight: 600; font-family: var(--font-mono);
  box-shadow: 0 3px 0 var(--nt-ink-2); }
.fr36-keys b.fn { background: #FF6B3D; box-shadow: 0 3px 0 #C2410C; font-family: var(--font-display); font-size: 14px; }
/* the fragments arrive once, a small stagger on their rows */
@media (prefers-reduced-motion: no-preference) {
  .kb.is-armed:not(.is-in) .kb-frag36 .fr36-rows li, .kb.is-armed:not(.is-in) .kb-frag36 .fr36-opts b { opacity: 0; transform: translateY(8px); }
  .kb-frag36 .fr36-rows li, .kb-frag36 .fr36-opts b { transition: opacity .45s var(--glide), transform .45s var(--glide);
    transition-delay: calc(var(--i, 0) * 90ms + 250ms); }
}

/* the family's links to its module pages: naked glyphs on hairline pills,
   wrapping on a desktop, a rail with the site's edge fade on a phone */
.fam36-links { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 28px; }
.fam36-links a { display: inline-flex; align-items: center; gap: 8px; flex: none; padding: 9px 16px 9px 12px; border-radius: 999px;
  font-weight: 600; font-size: 14px; line-height: 1.2; color: var(--ink); text-decoration: none; box-shadow: inset 0 0 0 1px var(--line); }
.fam36-links a .ic { width: 18px; height: 18px; stroke-width: 1.75; }
@media (hover: hover) and (pointer: fine) { .fam36-links a:hover { box-shadow: inset 0 0 0 1px currentColor; } .fam36-links a:hover .ic { color: #FF6B3D; } }
.fam36-pay { margin-top: 28px; }
@media (max-width: 700px) {
  .fam36-links { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; width: 100vw; margin-inline: calc(50% - 50vw);
    padding-inline: var(--gutter); box-sizing: border-box; --fade-w: 40px; }
  .fam36-links::-webkit-scrollbar { display: none; }
}
.prod-hero3 .fam-jump { margin-top: 26px; }
@media (max-width: 700px) {
  .prod-hero3 .fam-jump { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; width: 100vw; margin-inline: calc(50% - 50vw);
    padding-inline: var(--gutter); box-sizing: border-box; --fade-w: 40px; }
  .prod-hero3 .fam-jump::-webkit-scrollbar { display: none; }
  .prod-hero3 .fam-jump a { flex: none; }
}
/* the heading reveal's line masks give the glyphs room (js/scroll.js) */
.sh36-ln-mask { padding-block: .1em .14em; margin-block: -.1em -.14em; }

/* ---- item 6: the solution pages ------------------------------------------
   The hero is the module pages' own (css/modules.css .mod-hero3) with the
   format's photograph; the walkthrough is four feature cards in a row, each
   numbered; the Works with row is the module pages' cards, a rail on phones. */
.sol36-steps { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1100px) { .sol36-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px)  { .sol36-steps { grid-template-columns: 1fr; } }
.sol36-step { position: relative; }
.sol36-n { font-family: var(--font-mono); font-size: 12px; font-weight: 600; letter-spacing: .08em; color: #A13D20; margin-bottom: 6px; }
.sol36-walk .mini-bento { margin-top: clamp(24px, 3vw, 40px); }
@media (max-width: 700px) {
  .sol36-rel .rel-grid.rail36 { display: flex; flex-wrap: nowrap; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none;
    width: 100vw; margin-inline: calc(50% - 50vw); padding-inline: var(--gutter); box-sizing: border-box; gap: 12px; --fade-w: 40px; }
  .sol36-rel .rel-grid.rail36::-webkit-scrollbar { display: none; }
  .sol36-rel .rel-grid.rail36 > .rel { flex: 0 0 78%; scroll-snap-align: start; }
}

/* ---- item 7: the glass buttons on every page -----------------------------
   The clear glass button is keyed to its ground on every page, not only in
   the home page's named places: black at 6 percent on eggshell, white at 10
   on black. pricing.html's own #trial is an eggshell section, not the home
   page's photograph card, so it takes the eggshell glass. */
[data-ground="eggshell"] .hero-actions .btn.btn-ghost,
#trial:not(.tr34) .hero-actions .btn.btn-ghost {
  --btn-bg: transparent; --btn-edge: transparent;
  background: rgba(0,0,0,.06); color: #000000;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.45), inset 0 -1px 0 rgba(0,0,0,.15), 0 8px 22px rgba(0,0,0,.10);
}
[data-ground="eggshell"] .hero-actions .btn.btn-ghost:hover,
#trial:not(.tr34) .hero-actions .btn.btn-ghost:hover { background: rgba(0,0,0,.10); }
[data-ground="black"] .hero-actions .btn.btn-ghost {
  --btn-bg: transparent; --btn-edge: transparent;
  background: rgba(255,255,255,.10); color: #F7F3EE;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.18), inset 0 -1px 0 rgba(0,0,0,.3), 0 8px 22px rgba(0,0,0,.3);
}
[data-ground="black"] .hero-actions .btn.btn-ghost:hover { background: rgba(255,255,255,.16); }
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  [data-ground="eggshell"] .hero-actions .btn.btn-ghost, #trial:not(.tr34) .hero-actions .btn.btn-ghost { background: var(--surface); }
  [data-ground="black"] .hero-actions .btn.btn-ghost { background: #1C1C1E; }
}
/* a small square's glyph and label on a dark tile read in eggshell */
.kb-dark.phb > [data-ph="2"] .ph-sq, .kb-dark.phb > [data-ph="2"] .ph-l { color: #F7F3EE; }
/* phones: nothing pins, so the head and the four callouts are a plain list
   under the tablet and always shown; the runway's armed state (which hides
   them until the desktop scrub reaches them) never applies here */
@media (max-width: 900px) {
  [data-scrub-armed] .tac-head:not(.is-on), [data-scrub-armed] .tac-c:not(.is-on) { opacity: 1; transform: none; }
  #scrub-till .tac-list { padding-inline: var(--gutter); box-sizing: border-box; }
}

/* ==========================================================================
   Round 37: performance and stability. Nothing here changes a colour, a size
   or a timing the reader can see; each rule removes a cost the trace found.

   backdrop-filter is kept on the nav pill, the local nav and its sheet, the
   chapter sheet and the phone menu, and taken off everything else. Every
   element below already carries a ground of its own at 70 to 94 percent, so
   what the blur changed was the few percent of page showing through it; the
   grounds that sat over moving pictures (the cloud's plates, the offline
   tile's chip, the play button, the phone's bottom bar) go a step more
   opaque so that sliver stays as quiet as it was blurred. A blur on a
   control that moves (the buttons lift a pixel on hover, the callouts rise)
   has to be recomputed every frame and is where WebKit shows seams.
   ========================================================================== */
.nav-cta .btn, #trial .hero-actions .btn, .mh3-copy .hero-actions .btn, .ln-cta.btn, .h13-key,
.chapter-pill-open, .cld-plate, #scrub-till .tac-c, .offline-tile .ot-chip, .play-pause,
.sv-pills, .hl-arrow, .flow .fs-dev, .hero-film .btn-ghost {
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;
}
/* Round 40, item 5: the phone's bottom bar is a floating glass pill again,
   and it is the exception this block allows itself. The reasoning above is
   about a blur on a control that is recomputed every frame; the pill is at
   rest the whole time it is on screen and moves only on its own entrance
   and exit, which is one transition each way. css/site.css owns its glass. */
.cld-plate { background-color: rgba(28, 28, 30, .94); }
.offline-tile .ot-chip { background: rgba(20, 20, 22, .86); }
.play-pause { background-color: rgba(0, 0, 0, .58); }
.flow .fs-dev { background: rgba(28, 28, 30, .86); }
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .play-pause { background: rgba(0, 0, 0, .86); }
}

/* will-change only on what is moving all the time. Every SplitText word of
   every lede and statement was its own compositor layer (139 of the phone's
   414), and every bento tile another, so each frame's layer update walked
   hundreds of layers for a few words' opacity. A word repaints its own
   glyphs when its opacity moves; a tile is promoted by its own transition
   for as long as the hover lift runs. */
.wr .wr-w, .st34-line .wr-w { will-change: auto; }
.bx { will-change: auto; }

/* Ambient loops rest while their section is off screen (js/site.js sets
   .r37-off on any section more than 100px outside the window). They ran
   everywhere, all the time: the hero's thirteen ring segments and two blobs,
   the Ctrl rings, the till's glow, the live dots, the bento's breaths. Paused,
   not stopped, so each carries on from where it was when it comes back. */
.r37-off .h13-blob, .r37-off .a35-rot, .r37-off .tk35-glow, .r37-off .dash-glow, .r37-off .kb-grad,
.r37-off .kb-svwrap::before, .r37-off .tac-list::before, .r37-off .live,
.r37-off .bxs-bars i, .r37-off .bxa-line, .r37-off .bxt-print em, .r37-off .marq-in,
.r37-off .receipt > * {
  animation-play-state: paused !important;
}

/* ==========================================================================
   Round 38: two flickers, fixed at their causes. Nothing here changes a
   colour, a size, a position or a timing; js/scroll.js carries the rest.

   The hero. The type, the trio and the rings keep one compositor layer
   each for as long as the pin can move them (they were dropped at the
   pin's ends and made again on the way back). The characters carry the
   gradient the headline rests in (the shimmer's own, 55 percent to the
   mid grey), so nothing steps when the split is taken away.
   ========================================================================== */
.hero13.is-pinned .h13-stack, .hero13.is-pinned .h13-trio {
  will-change: transform; backface-visibility: hidden;
}
.h13-head .h36-ch { background-image: linear-gradient(180deg, #FFFFFF 0%, var(--hl-1) 55%, var(--hl-2) 100%); }
/* a text clip paints only inside the element's own box: a character's box
   stopped at its line, so the tails of "y" and "g" and the edges the tight
   tracking pushes past a neighbour were cut while the characters rose and
   came back whole when the split went. The box now reaches past the glyph
   on every side and the margins give the room back, so nothing moves. */
.h13-head .h36-ch { padding: 0 .08em .26em; margin: 0 -.08em -.26em; }

/* Round 38 drew thirteen edge slices into one flat plane from where the
   stage's eye saw them. Round 41 has no slices: the key is a face and a
   wall, so the projection, the `is-flat` switch and the per-frame sort are
   all gone. What is left of that round is the rule it proved -- one layer,
   taken once, and only transforms moving inside it. */
.uc35-shade { z-index: 0; }
.uc35-wall  { z-index: 1; }
.uc35-face  { z-index: 2; }

/* "Ctrl.": the word fades (the statement highlight), the inner span
   carries the gradient, set out as the word was so the gradient spans the
   same box */
.st34-line .uc38-in { display: inline-block; }

/* ==========================================================================
   Round 39, item 3: the number cards on the "One database" rail.
   Six of the eight cards draw their own number instead of standing on a
   photograph. The shell is the photo card's: same flex basis, same 4:5, same
   radius, same rail and paddles. Each one runs once when it arrives (.is-in,
   js/apple.js tileMotion) and then rests. The live board is the one cycle on
   the page, twelve seconds long, and .r37-off stops it off screen.
   ========================================================================== */
.rl34-fig { background: linear-gradient(180deg, #26262A 0%, #141416 62%, #101012 100%); }
.rl34-fig::after { display: none; }
.rl34-fig::before { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
                    border: 1px solid rgba(255,255,255,.10); z-index: 2; }
.rl34-art { position: absolute; left: 22px; right: 22px; top: 24px; bottom: 48%; z-index: 1; }
.rl34-fig .rl34-v { color: #FFFFFF; }
.rl34-fig .rl34-l { color: var(--nt-ink-2); }
@media (max-width: 900px) { .rl34-art { bottom: 46%; } }

/* --- the live board: the line redraws and the dot pulses on 12 seconds --- */
.rl34-live { display: flex; flex-direction: column; gap: 10px; }
.rl34-badge { margin: 0; display: inline-flex; align-items: center; gap: 7px; align-self: flex-start;
              font-family: var(--font-mono); font-size: 10px; font-weight: 600; letter-spacing: var(--tr-caps);
              text-transform: uppercase; color: var(--nt-ink-2); }
.rl34-dot { width: 7px; height: 7px; border-radius: 50%; background: #FF6B3D; opacity: .9; }
.rl34-spark { flex: 1; width: 100%; min-height: 0; display: block; overflow: visible; }
.rl34-spark .gd { stroke: rgba(255,255,255,.10); stroke-width: 1; fill: none; }
.rl34-spark .ln { fill: none; stroke: #FF6B3D; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round;
                  stroke-dasharray: 1; stroke-dashoffset: 1; }
.rl34-card.is-in .rl34-spark .ln { animation: rl39Draw 12s linear infinite; }
.rl34-card.is-in .rl34-dot { animation: rl39Dot 12s linear infinite; }
@keyframes rl39Draw { 0% { stroke-dashoffset: 1; } 8% { stroke-dashoffset: 0; } 100% { stroke-dashoffset: 0; } }
@keyframes rl39Dot { 0% { opacity: .3; transform: scale(.7); } 3% { opacity: 1; transform: scale(1.3); }
                     11% { opacity: .9; transform: scale(1); } 100% { opacity: .9; transform: scale(1); } }

/* --- nineteen reports: the rows land and the CSV chips light in turn ----- */
.rl34-rows { display: flex; flex-direction: column; justify-content: flex-end; gap: 6px; }
.rl34-rows span { display: flex; align-items: center; justify-content: space-between; gap: 8px;
                  padding: 7px 9px; border-radius: 9px; background: rgba(255,255,255,.055);
                  opacity: 0; transform: translateY(8px);
                  transition: opacity var(--d-3) var(--glide), transform var(--d-3) var(--glide);
                  transition-delay: calc(var(--i) * 90ms); }
.rl34-card.is-in .rl34-rows span { opacity: 1; transform: none; }
.rl34-rows b { font: 600 12px/1.2 var(--font-ui); color: #FFFFFF; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rl34-rows em { flex: none; font: 600 9px/1 var(--font-mono); letter-spacing: .06em; font-style: normal;
                padding: 4px 6px; border-radius: 5px; background: rgba(255,255,255,.10); color: var(--hl-2);
                transition: background var(--d-2) var(--glide), color var(--d-2) var(--glide);
                transition-delay: calc(320ms + var(--i) * 130ms); }
.rl34-card.is-in .rl34-rows em { background: rgba(255,107,61,.22); color: #FF9A75; }

/* --- 02:00: the hands sweep round to two -------------------------------- */
.rl34-clock { display: grid; place-items: center; }
.rl34-clock svg { height: 100%; max-height: 100%; aspect-ratio: 1; overflow: hidden; }
.rl34-clock .fc { fill: rgba(255,255,255,.04); stroke: rgba(255,255,255,.14); stroke-width: 1.2; }
.rl34-clock .tk line { stroke: rgba(255,255,255,.28); stroke-width: 1.6; stroke-linecap: round; }
.rl34-clock .hh, .rl34-clock .mh { stroke-linecap: round; transform-origin: 50px 50px; transform: rotate(0deg);
  transition: transform 1500ms cubic-bezier(.22, 1, .36, 1) 160ms; }
.rl34-clock .hh { stroke: #FFFFFF; stroke-width: 4; }
.rl34-clock .mh { stroke: #FF6B3D; stroke-width: 2.6; }
.rl34-clock .pn { fill: #FFFFFF; }
.rl34-card.is-in .rl34-clock .hh { transform: rotate(60deg); }
.rl34-card.is-in .rl34-clock .mh { transform: rotate(720deg); }

/* --- nothing lost offline: the line drops, the queue fills and clears ---- */
.rl34-off { display: flex; flex-direction: column; justify-content: flex-end; gap: 12px; }
.rl34-bars { display: flex; align-items: flex-end; gap: 5px; height: 34px; }
.rl34-bars i { width: 9px; border-radius: 3px; background: #FF6B3D; transform-origin: 50% 100%;
               height: calc(12px + var(--i) * 7px); transition: transform var(--d-3) var(--glide), background var(--d-3) var(--glide);
               transition-delay: calc(var(--i) * 70ms); }
.rl34-card.is-in .rl34-bars i { transform: scaleY(.08); background: rgba(255,255,255,.22); }
.rl34-card.is-done .rl34-bars i { transform: none; background: #FF6B3D; transition-delay: calc(var(--i) * 70ms); }
.rl34-q { font: 600 13px/1 var(--font-ui); color: var(--nt-ink-2); opacity: 0; transition: opacity var(--d-2) var(--glide); }
.rl34-q b { font-variant-numeric: tabular-nums; color: #FFFFFF; }
.rl34-card.is-in .rl34-q { opacity: 1; }
.rl34-card.is-done .rl34-q { opacity: 0; }
.rl34-ok { display: inline-flex; align-items: center; gap: 7px; font: 600 13px/1 var(--font-ui); color: #FF9A75;
           opacity: 0; transform: translateY(6px); transition: opacity var(--d-2) var(--glide), transform var(--d-2) var(--glide);
           position: absolute; left: 0; bottom: 0; }
.rl34-ok svg { width: 15px; height: 15px; }
.rl34-ok path { stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
                stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 420ms var(--glide) 120ms; }
.rl34-card.is-done .rl34-ok { opacity: 1; transform: none; }
.rl34-card.is-done .rl34-ok path { stroke-dashoffset: 0; }

/* --- eight tenders: the chips deal in one by one ------------------------- */
.rl34-tend { display: grid; grid-template-columns: 1fr 1fr; grid-auto-rows: 1fr; gap: 7px; align-content: end; }
.rl34-tend i { border-radius: 7px; background: rgba(255,255,255,.07); border: 1px solid rgba(255,255,255,.10);
               position: relative; opacity: 0; transform: translate(14px, -10px) rotate(-6deg) scale(.92);
               transition: opacity 340ms var(--glide), transform 460ms var(--out-back, cubic-bezier(.22, 1.2, .36, 1));
               transition-delay: calc(var(--i) * 85ms); }
.rl34-tend i::before { content: ""; position: absolute; left: 8px; top: 50%; margin-top: -3px; width: 6px; height: 6px;
                       border-radius: 50%; background: #FF6B3D; opacity: .85; }
.rl34-tend i::after { content: ""; position: absolute; left: 20px; right: 9px; top: 50%; margin-top: -1.5px; height: 3px;
                      border-radius: 2px; background: rgba(255,255,255,.26); }
.rl34-card.is-in .rl34-tend i { opacity: 1; transform: none; }

/* --- thirty-three permissions: the ring fills, the lock closes ----------- */
.rl34-perm { display: grid; place-items: center; }
.rl34-perm svg { height: 96%; max-height: 96%; aspect-ratio: 1; overflow: hidden; }
.rl34-perm .sg line { stroke: rgba(255,255,255,.16); stroke-width: 3.2; stroke-linecap: round;
                      transition: stroke var(--d-1) linear; transition-delay: calc(var(--i) * 26ms); }
.rl34-card.is-in .rl34-perm .sg line { stroke: #FF6B3D; }
.rl34-perm .sh { fill: none; stroke: #FFFFFF; stroke-width: 4; stroke-linecap: round;
                 transform-origin: 50px 49px; transform: scaleY(.12) translateY(-6px);
                 transition: transform 420ms cubic-bezier(.22, 1.3, .36, 1) 900ms; }
.rl34-perm .bd { fill: #FFFFFF; }
.rl34-card.is-in .rl34-perm .sh { transform: none; }

/* off screen, and under reduced motion, every one of them rests settled */
.r37-off .rl34-spark .ln, .r37-off .rl34-dot { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .rl34-card.is-in .rl34-spark .ln, .rl34-card.is-in .rl34-dot { animation: none; }
  .rl34-spark .ln { stroke-dashoffset: 0; }
  .rl34-rows span, .rl34-tend i { opacity: 1; transform: none; transition: none; }
  .rl34-clock .hh, .rl34-clock .mh, .rl34-perm .sh, .rl34-bars i, .rl34-q, .rl34-ok { transition: none; }
  .rl34-card .rl34-bars i { transform: none; }
  .rl34-q { opacity: 0; }
  .rl34-ok { opacity: 1; transform: none; }
  .rl34-ok path { stroke-dashoffset: 0; }
}

/* ==========================================================================
   Round 39, item 8: "Talk about Ctrl." on the phone.
   Desktop pins the tablet and lights four callouts around it. The phone had
   the tablet floating above a title and then four flat cards with nothing
   holding them together. Same order as the desktop reads it now (title, the
   tablet with the section's glow behind it, the beat it is on, then the
   callouts), the callouts arrive one after another as the reader scrolls
   (js/scroll.js, no pin, fails open) and the two nearest the tablet draw the
   same hairline leader up to it. Nothing pins.
   ========================================================================== */
@media (max-width: 900px) {
  /* the glow and field layer is absolute; give it the sticky to sit in */
  #scrub-till .scrub-sticky { position: relative; gap: clamp(22px, 4vh, 40px); }
  #scrub-till .scrub-sticky > .tac-head    { order: 1; margin-top: 0; }
  #scrub-till .scrub-sticky > .scrub-stage { order: 2; }
  #scrub-till .scrub-sticky > .scrub-beats { order: 3; margin-top: 0; }
  #scrub-till .scrub-sticky > .tac-list    { order: 4; margin-top: var(--s-2); }
  /* the callouts arrive in sequence. The class is written by js/scroll.js,
     so with no script every one of them is simply already there. */
  #scrub-till .tac-c { position: relative; }
  #scrub-till .tac-list.tac-seq .tac-c { opacity: 0; transform: translateY(14px); }
  #scrub-till .tac-list.tac-seq .tac-c.is-on { opacity: 1; transform: none; }
  /* the leader, where there is room: the first row sits directly under the
     tablet, so those two draw a hairline up to it. The second row has the
     first between it and the tablet, so it draws nothing. */
  #scrub-till .tac-list .tac-c:nth-child(-n+2) .tac-lead {
    display: block; position: absolute; top: auto; bottom: 100%; left: 18px;
    width: 1px; height: 18px; margin: 0 0 9px; opacity: .3;
    background: var(--ink); transform: scaleY(0); transform-origin: bottom center;
    transition: transform .5s var(--glide) .14s;
  }
  #scrub-till .tac-list .tac-c:nth-child(-n+2).is-on .tac-lead { transform: scaleY(1); }
}
@media (max-width: 380px) {
  /* one column: only the first card still has the tablet directly above it */
  #scrub-till .tac-list .tac-c:nth-child(2) .tac-lead { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  #scrub-till .tac-list.tac-seq .tac-c { opacity: 1; transform: none; }
  #scrub-till .tac-list .tac-c:nth-child(-n+2) .tac-lead { transform: scaleY(1); transition: none; }
}

/* ==========================================================================
   Round 39, item 10: "Around the clock." fits the phone.
   It was a 1:1 crop of a 1600 x 893 photograph pulled to 42 percent, so the
   man on the right was cut in half by the frame and the title ran off it.
   The picture now gets the phone's whole width: at that width it is 55.81
   percent of the width tall, and the scene is that plus a 20 percent band
   above it for the title, so 75.81 in all. The layers take the bottom 73.6
   percent, which is exactly the picture's own ratio, so cover fits it edge
   to edge and nobody is cut. The title has the band to itself.
   The back plate is the one layer with a rectangle to give away, so on a
   phone it holds still and the title and the cut-out (which carries alpha)
   move against it (js/scroll.js's LP list). This block sits at the end of
   the file on purpose: the round 35 container-unit block above it sets the
   same three selectors.
   ========================================================================== */
/* ==========================================================================
   Round 40, item 4: one scene on the phone, and no white band.
   Round 39's fit gave the title a 20 percent band of its own above the
   picture. That band is the scene's own `#EDEDEA`, which in a black section
   reads as a white strip with a heading printed on it rather than a
   photograph with a title in it. The phone is composed the way the desktop
   is now: the picture is the whole scene, the title sits in the
   photograph's own headroom, and the section's black is the only ground.
   Nobody is cut. The frame is 2:1 and the plates are 112 percent of it, so
   `cover` asks the 1600 x 893 picture for 1.786:1 against its own 1.792 and
   takes about a pixel off the width -- the same sum the desktop has always
   done. The cut-out's topmost alpha sits at 13.9 percent of its height and
   only in the 70 to 80 percent column; the left 30 percent is clear to past
   half height, which is the room the title is laid into, in container units
   so it holds that place at every width.
   ========================================================================== */
/* (rules removed in Round 54, item 9a) */

/* ==========================================================================
   Round 39, item 11: the rings behind "Everything is under Ctrl."
   On a phone they read as loose lines floating with nothing to do, so phones
   get none (js/scroll.js hides the layer and never draws it) and the press
   sends one soft radial pulse out of the key instead. On desktop the rings
   are at nothing until the key goes down and fade back to nothing behind it,
   so they never sit in the background.
   ========================================================================== */
.uc35-pulse {
  position: absolute; left: 50%; top: 50%; z-index: 0;
  width: min(150vw, 620px); aspect-ratio: 1; margin: -1px 0 0;
  translate: -50% -50%; transform-origin: 50% 50%;
  border-radius: 50%; pointer-events: none; opacity: 0;
  background: radial-gradient(closest-side,
    rgba(255,107,61,.34) 0%, rgba(255,122,72,.17) 44%, rgba(255,107,61,.05) 72%, rgba(255,107,61,0) 100%);
}
@media (min-width: 901px) { .uc35-pulse { display: none; } }
@media (prefers-reduced-motion: reduce) { .uc35-pulse { display: none; } }

/* round 39, item 12: the compliance tile's three due rows, one pass on entry */
.bxa-due { display: grid; gap: 6px; margin-top: var(--s-3); }
.bxa-due i { display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
             padding: 6px 9px; border-radius: 8px; background: rgba(0,0,0,.05); font-style: normal;
             opacity: 0; transform: translateY(6px);
             transition: opacity var(--d-3) var(--glide), transform var(--d-3) var(--glide);
             transition-delay: calc(var(--i) * 95ms); }
.bx.is-in .bxa-due i { opacity: 1; transform: none; }
.bxa-due b { font: 600 13px/1.2 var(--font-ui); color: var(--ink); }
.bxa-due em { font: 600 11px/1 var(--font-mono); font-style: normal; letter-spacing: .04em; color: var(--accent-text); }
@media (prefers-reduced-motion: reduce) { .bxa-due i { opacity: 1; transform: none; transition: none; } }

/* ==========================================================================
   Round 41, items 1 and 2: the phone screens are pictures on a phone.
   --------------------------------------------------------------------------
   Every board that sits inside one of this site's CSS device shells is
   composited inside a `preserve-3d` context with a promoted, scaled parent
   and a rounded overflow clip. Chrome draws it; Safari on a real iPhone
   dropped the hero phone's board entirely and let the pocket board fall out
   as the section scrolled. Round 40 removed the one mask that distinguished
   the pocket copy and it was still not enough, so on a phone the live
   subtree is out of the shell altogether: each board is rendered once,
   headlessly, at its frame's own size and 3x (img/screens/), and the frame
   shows that picture. Above 900px nothing changes and the boards stay live.
   ========================================================================== */
.pk34-still { display: none; }
@media (max-width: 900px) {
  /* The board is the picture, not the markup. The picture is the whole feed
     at its own 331 by 1198, so the view's padding, its painted fade and the
     slow travel of the board under the status bar are all exactly what they
     were: one flat layer moves instead of a live subtree. */
  .pk34-view > .pk34-feed { display: none; }
  .pk34-view > .pk34-still {
    display: block; position: relative; width: 100%; height: auto;
    will-change: auto;
  }
}
/* The hero's two live screens keep their picture in the markup rather than
   removing it once a clone lands: below 901px no clone is made at all, and
   above it the picture is hidden by this class instead of being deleted, so
   a window dragged across the breakpoint still has something to show. */
.h13-trio .pad-screen.h13-cloned .h13-still,
.h13-trio .ph-screen.h13-cloned .h13-still { display: none; }


/* ═══════════════════════════════════════════════════════════════════════════
   ROUND 42, item 3: the four callouts under "Talk about Ctrl." are one height
   ═══════════════════════════════════════════════════════════════════════════
   On a phone the four plates lay out to their own content, so "Roles and
   permissions" and "Void with a reason" (three lines of small print each)
   stood 142.2px while "Offline" and "Split by item or evenly" stood 121.2,
   and the small print started at four different heights down the card. This
   is round 40's fix for the cloud's system cards, applied here: the grid's
   rows are `1fr` so every row is the tallest row's height, the plate fills
   the row it is given, and the title and the line each hold two lines of
   room whether this card's text uses them or not, so every title and every
   line starts on the same baseline across all four.
   Phones only. Above 900px the callouts are positioned absolutely against
   the tablet's quarter and three-quarter lines and nothing here applies. */
@media (max-width: 900px) {
  .tac-list { grid-auto-rows: 1fr; align-items: stretch; }
  .tac-c {
    display: flex; flex-direction: column; height: 100%;
    /* the plate is the row; nothing collapses back to its own content */
  }
  .tac-c b { min-height: calc(2 * 1.2em); }
  .tac-c span { min-height: calc(2 * 1.4em); }
  /* And the reason the rows were never rows. Round 39 gave the phone's
     callouts `position: relative` so the leader hairline had something to
     anchor to, which quietly re-activated the desktop's own `top: 30%` and
     `56%` and its `left`/`right: 16px` on each plate: measured at 390, the
     four sat at 354.3, 391.3, 516.5 and 553.4 from the top of the window and
     at two different lefts, inside a grid that had already placed them in two
     tidy rows. The offsets go, the position stays, and the leader is
     untouched. Specific enough to beat `.tac-c[data-tac="0"]`, and inside the
     phone query, so nothing above 900px moves. */
  #scrub-till .tac-list .tac-c[data-tac] { top: auto; right: auto; bottom: auto; left: auto; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ROUND 46: below 901px a device is one flat picture, not a composition
   ═══════════════════════════════════════════════════════════════════════════
   Rounds 40, 41 and 44 each found and removed one link in the chain that makes
   Safari on a real iPhone drop these subtrees -- a zero-width clone, a masked
   fade inside a `preserve-3d` shell, a frame sized by a script that arrives
   late -- and each time the blank screen came back. The chain goes instead of
   the link. Below 901px the hero's tablet and phone, and the phone in "Every
   outlet, one glance.", are a single <img> of the whole device, frame and
   screen together, rendered once headlessly from this page's own paint
   (tools/mkflat.js) at the size each is drawn at on a 430px phone, at 1x, 2x
   and 3x. There is no 3D, no `preserve-3d` ancestor, no mask, no backdrop
   filter, no clone and no scale transform anywhere in what is left, and
   nothing has to run for the picture to be the right size: it is two lengths
   over the box's own `--s`, which css already resolves on its own.

   The <picture> is `display: contents`, so the <img> lays out exactly where
   the composed device did and every selector written against the box still
   reads it as a direct child. The media query lives on the <source> rather
   than on `display`, because a `display: none` <img> is still fetched: above
   900px the source does not match, the img falls to a 1x1 transparent gif in
   its own markup, and not one byte of any of this is asked for.

   The frame's drop shadow is the one thing the picture does not carry. It is
   a soft alpha gradient over half again the device's area, and baking it in
   cost 517KB at 3x for the pocket phone against 94KB without it. It is drawn
   here instead, at the frame's own offsets scaled by `--s`: a paint effect on
   one <img>, which is not a thing any engine drops.

   Nothing above 900px changes. ------------------------------------------- */
.r46-pic { display: contents; }
.r46-flat { display: none; }
@media (max-width: 900px) {
  .ph-box > .r46-pic > .r46-flat,
  .pad-box > .r46-pic > .r46-flat {
    display: block; position: absolute; left: 0; top: 0; z-index: 1;
  }
  /* .ph-frame's own `0 60px 90px -30px rgba(0,0,0,.75)`, over `--s` */
  .ph-box > .r46-pic > .r46-flat {
    width: calc(393px * var(--s)); height: calc(852px * var(--s));
    border-radius: calc(62px * var(--s));
    box-shadow: 0 calc(60px * var(--s)) calc(90px * var(--s)) calc(-30px * var(--s)) rgba(0, 0, 0, .75);
  }
  /* .pad-frame's own `0 50px 80px -30px rgba(0,0,0,.6)`, over `--s` */
  .pad-box > .r46-pic > .r46-flat {
    width: calc(740px * var(--s)); height: calc(520px * var(--s));
    border-radius: calc(28px * var(--s));
    box-shadow: 0 calc(50px * var(--s)) calc(80px * var(--s)) calc(-30px * var(--s)) rgba(0, 0, 0, .6);
  }
  /* the composition itself is not drawn, and the box stops being a 3D context */
  .ph-box > .r46-pic ~ .phone,
  .pad-box > .r46-pic ~ .pad { display: none; }
  .h13-trio .ph-box, .h13-trio .pad-box, .pk34-ph .ph-box { perspective: none; }
}

/* ---- round 46, the till chapter's tablet -------------------------------
   The fourth device the phone audit flags on this page, and the one that is
   flattened rather than replaced: its screen is a <video>, the till scrub,
   which plays on a phone when the chapter arrives (js/apple.js's initScrub),
   and a picture would be that film deleted. So the chain goes instead. Below
   901px there is no perspective on the box, `.pad` is a plain 2D scale with
   `transform-style: flat`, and the four parts that exist only to be seen in
   3D -- the back panel, the four side walls and the two buttons, every one of
   them edge-on because nothing rotates this tablet on a phone -- are not
   drawn. That is the same treatment round 44 gave the module hero's phone.

   Round 44 tried this on the module pages' tablet and reverted it, because
   with `preserve-3d` off the right third of that frame stopped being drawn.
   It does not happen here and it was checked rather than assumed: captured at
   320, 390 and 430 at 2x, before and after, the whole frame is drawn both
   ways and the only difference is the bezel, which is 1.5 percent narrower
   without the perspective projection behind it (58 pixels differ by more than
   12/255 at 320, 11,904 at 390, 18,249 at 430, all of them along the four
   inside edges of the bezel). Those pages' tablets are replaced by a picture
   in this round anyway; this one is not, because of the film. ----------- */
@media (max-width: 900px) {
  .scrub-stage .pad-box { perspective: none; }
  .scrub-stage .pad-box .pad {
    transform-style: flat; will-change: auto; transition: none;
    transform: scale(var(--s));
  }
  .scrub-stage .pad-box .pad-back,
  .scrub-stage .pad-box .pad-side,
  .scrub-stage .pad-box .pad-btn { display: none; }
}

/* ---- round 47: the giant line is solid colour on a phone ----------------
   "Every outlet, one glance." is the one piece of gradient text on this site
   that is also moved by a transform for the whole of its pass. Rounds 44 and
   46 measured its offsets in Chrome and found them right, which they are:
   in the WebKit harness at 390 the line is 566px wide, starts with its first
   character 8px past the right edge and ends with its last 8px past the
   left, at every one of ten scroll positions. What Chrome's numbers cannot
   see is that `-webkit-background-clip: text` paints the glyphs out of a
   background box, and WebKit resolves that box against the element's own
   painted layer: give the element a transform for the length of a scroll and
   the gradient and the mask stop agreeing, so what is drawn is a fraction of
   the line at the start of the travel and nothing at all by the end. On a
   phone the element is transparent text over a transparent background and
   there is nothing left to see. That is exactly Parth's two sentences: not
   visible, and it does not go the whole way.

   So below 901px the treatment goes and the palette's own ink takes its
   place. `--g-h1` is the middle stop of that same gradient, written onto
   this section by the ground machinery in js/scroll.js, so the line is the
   colour it already read as in its middle and it is one solid fill with no
   background box to lose. The opacity goes with it: 0.92 on a transformed
   element is a second reason for a compositor to give it a layer of its own,
   and the ink is already below white. Nothing above 900px changes; the
   desktop keeps the gradient it has had since round 34.
   ---------------------------------------------------------------------- */
@media (max-width: 900px) {
  .pk34-giant {
    background-image: none;
    -webkit-background-clip: border-box; background-clip: border-box;
    color: var(--g-h1, var(--hl-1)); -webkit-text-fill-color: currentColor;
    opacity: 1;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ROUND 48: a device screen is a picture at every width, in every browser
   ═══════════════════════════════════════════════════════════════════════════
   Safari on a Mac blanked the hero phone and the phone in "Every outlet, one
   glance." at desktop width, which is the failure round 46 ended on phones.
   Round 46 ended it with a picture; this round does the same on a desktop,
   without giving up the frames or the turns.

   Every CSS frame is two elements now (tools/r48split.py). The SHELL keeps
   `preserve-3d` and carries only the parts that exist to be seen in 3D: the
   back, the side walls, the buttons. The FACE carries the frame, the glass
   and the screen, and it is flat. Both carry the same classes, so the same
   rules size, place and turn them, and the face lands exactly on the shell's
   front plane. What the screen holds is a headless render of the board it
   used to hold (tools/mkscreens.js, img/screens/, 1x to 3x), so nothing above
   the picture is a `preserve-3d` box, a mask or a clone.

   The shell's filter stays where it was; the face has none, so a device's
   drop shadow is drawn once, as before. ------------------------------------ */
.phone.r48-face, .pad.r48-face { transform-style: flat; }
/* Round 53: the tablet's drop shadow moves from the SHELL to the FACE.

   The shell is the only `preserve-3d` element on this device and it was also
   the only one carrying a filter -- the two properties whose combination the
   CSS transforms spec says must flatten the element, and which WebKit has
   never agreed with Chrome about. The symptom is a second tablet-shaped body
   behind the real one, up and to the left, that Parth photographed and filmed
   in Safari and that no measurement in Chrome ever reproduced: shell and face
   report byte-identical transforms, so it is not a pose that disagrees, it is
   one element's shadow being composited against the wrong geometry.

   The face is `transform-style: flat`, so a filter on it cannot interact with
   a 3D rendering context at all, and its silhouette is the tablet's outline
   anyway -- the shell's only wider parts are the side walls, which are edge-on.
   Same shadow, drawn once, from a box no browser can disagree about. */
.pad.r48-shell { filter: none; }

/* Round 53, second pass. Moving the shadow to the face removed the doubled
   body and revealed what it had been hiding: in Safari the shell renders
   UNSCALED -- a 740x520 grey slab, its natural size, while the face beside it
   is correctly scaled and turned. Its `transform` is not applying there at
   all. The drop-shadow used to flatten it (a filter forces flattening, which
   is the one part of this WebKit disagrees with Chrome on) and the slab sat
   hidden behind the face; without the filter it is simply drawn.

   So this tablet stops relying on the shell. The face already carries the
   frame, the glass and the screen -- the whole device as anyone sees it --
   and the shell contributes only the back panel and four side walls that are
   edge-on at this turn. Hidden, there is nothing left to mis-transform, in
   any browser, and the shadow above is drawn from the face, which is flat.
   Scoped to the scrub tablet: every other device keeps its shell. */
.scrub-stage .pad.r48-shell { display: none; }
.pad.r48-face {
  filter: drop-shadow(0 calc(var(--pad-lift-shadow, 0) * 34px)
                        calc(var(--pad-lift-shadow, 0) * 40px)
                        rgba(0,0,0, calc(var(--pad-lift-shadow, 0) * .22)));
}
img.r48-scr {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
}
/* the pocket board: one tall picture, moved by the pin with a 2D translate
   inside the screen's own rounded clip */
.pk34-feed img.r48-feedimg { display: block; width: 100%; height: auto; }

/* ---- round 48, item 2: every frame has its final size before any script --
   The pocket's phones were sized by js/scroll.js (sizePhones) once the pin
   was built, and the module and solution heroes by js/site.js (fitPads) and
   js/modules.js (fitBoxes) once those files had parsed: until then each was
   drawn at a css default and then snapped. The same numbers are css now,
   and the scripts write what css already says. `calc(length / length)` is
   typed arithmetic, so each is behind the same @supports test round 30 uses
   for the hero; an engine without it keeps the old default and the script. */
@supports (width: calc(100vw / 1px * 1px)) {
  @media (min-width: 901px) and (prefers-reduced-motion: no-preference) {
    /* sizePhones(0.74, 0.86): min(.86, innerHeight * .74 / 852) */
    .pk34-ph .ph-box { --s: min(.86, calc(100vh * .74 / 852px)); }
  }
  @media (min-width: 901px) {
    /* fitPads / fitBoxes read the column the device hangs in, which is
       `.mh3-dev`'s own width; a container query unit is that width */
    .mh3-dev { container-type: inline-size; }
    .mh3-shot.dev-pad .dev-rig .pad-box { --s: clamp(.4, calc(100cqw / 760px), 1.12); }
    .mh3-shot.dev-phone .dev-ph-box { --s: min(.62, calc(100cqw / 393px)); }
  }
}

/* ═════════════════════════════════════════════════════════════════════════
   Round 54: the Apple-page redesign. Every component below is new this
   round and lives here, after everything it builds on. Colours through the
   tokens, one radius scale, one shadow, Inter for everything and JetBrains
   Mono for figures that are already mono. Phones never pin anything here
   and never scroll-jack: every gallery is native scroll-snap.
   ═════════════════════════════════════════════════════════════════════════ */

/* ---- item 4: the bento is one horizontal gallery on a phone -------------
   Same markup, same twelve cards. Each card is 84vw with the next one
   peeking, the page gutter at both ends, native snap. Below it, Apple's
   control: dots whose active one stretches into a pill that fills over the
   slide's duration, and a round pause/play button. js/r54.js runs it. */
/* Round 56, item 3: a photo card's one-line caption, shown only in the phone
   gallery (the desktop bento is unchanged) */
.bx-line { display: none; }
@media (max-width: 700px) {
  .bento-wall.phb {
    display: flex; gap: 12px; align-items: stretch;
    overflow-x: auto; overscroll-behavior-inline: contain;
    scroll-snap-type: x mandatory; scrollbar-width: none;
    width: 100vw; margin-inline: calc(50% - 50vw);
    padding: 4px var(--gutter) 10px; scroll-padding-inline: var(--gutter);
  }
  .bento-wall.phb::-webkit-scrollbar { display: none; }
  /* Round 56, item 3 (Parth: "0 orders lost is too small for the card ...
     There is a card which only reads Kitchen and has a photo"). One phone
     layout for every card: 84vw wide and at least 4:5 (the rail stretches
     every slide to the tallest, so they are one height), 20px padding. Top
     left: the eyebrow, the headline at --t-lg and the one-line caption; the
     rest of the card is the visual, scaled to fill it, with the bx-foot line
     kept at the bottom as a footer. The Round 30 square (.ph-sq) never
     applies here. Desktop bento unchanged. */
  .bento-wall.phb .bx, .bento-wall.phb .bx.w2, .bento-wall.phb .bx.tall {
    flex: 0 0 84vw; width: 84vw; max-width: 84vw; min-height: calc(84vw * 1.25); height: auto;
    padding: 20px; gap: 6px; border-radius: 20px;
    display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start;
    scroll-snap-align: start; grid-column: auto; grid-row: auto;
  }
  .bento-wall.phb .bx > .ph-sq, .bento-wall.phb .bx .bx-obj { display: none; }
  .bento-wall.phb .bx .kicker { order: -1; margin: 0 0 4px; }
  .bento-wall.phb .bx h3, .bento-wall.phb .bx .copy h3 {
    font-size: var(--t-lg); line-height: 1.15; letter-spacing: -.02em; margin: 0; text-wrap: balance;
  }
  .bento-wall.phb .bx p { font-size: var(--t-base); line-height: 1.4; }
  /* the plate cards keep their visual inside .copy: the headline stays at
     the top and everything after it (the visual, the foot) sits at the foot */
  .bento-wall.phb .bx .copy { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin-top: 0; }
  .bento-wall.phb .bx .copy > h3 { margin-bottom: auto; }
  .bento-wall.phb .bx .bxa { margin-top: 18px; }
  .bento-wall.phb .bx .bx-foot { margin-top: 16px; gap: 6px 10px; align-items: baseline; }
  .bento-wall.phb .bx .bx-foot b { font-size: var(--t-xl); letter-spacing: -.03em; line-height: 1; }
  .bento-wall.phb .bx .bx-foot > span { font-size: var(--t-sm); opacity: .8; flex: 1 1 12ch; }
  /* Offline: the counter at 120px or more with its line under it, the
     signal at the foot */
  .bento-wall.phb .bx.ink .figure { font-size: clamp(120px, 36vw, 156px); line-height: .9; letter-spacing: -.06em; margin-top: auto; }
  .bento-wall.phb .bx.ink .figure + p { margin: 6px 0 0; font-size: var(--t-base); opacity: .85; }
  .bento-wall.phb .bx .bxa-signal { margin-top: auto; padding-top: 16px; }
  .bento-wall.phb .bxs-bars { height: 56px; gap: 5px; }
  .bento-wall.phb .bxs-bars i { width: 10px; height: calc(16px + var(--i) * 13px); }
  .bento-wall.phb .bxs-q, .bento-wall.phb .bxs-ok { font-size: 14px; }
  /* Reports: every row, at full width */
  .bento-wall.phb .bx .bx-rows { margin-top: auto; font-size: var(--t-sm); gap: 4px; }
  .bento-wall.phb .bx .bx-rows div { padding: 9px 0; }
  .bento-wall.phb .bx .bxa-dl { font-size: 13px; margin-top: 10px; }
  /* Recipes: the cost stack */
  .bento-wall.phb .bxa-stack { height: 26px; border-radius: 8px; }
  /* Inventory: the four reasons and the stock line */
  .bento-wall.phb .bxa-chips { gap: 8px; }
  .bento-wall.phb .bxa-chips i { font-size: 14px; padding: 9px 13px; }
  .bento-wall.phb .bx .bxa-line { display: block; height: 88px; margin-top: 18px; }
  /* Multi-outlet: the five outlets, then the permissions line */
  .bento-wall.phb .bxa-fan { display: flex; gap: 8px; }
  .bento-wall.phb .bxa-fan i { font-size: 13.5px; padding: 8px 12px; }
  /* Printing: the four transports beside a bigger printer */
  .bento-wall.phb .bxa-tr { gap: 14px; flex-wrap: nowrap; align-items: flex-end; }
  .bento-wall.phb .bxt-chips { gap: 8px; }
  .bento-wall.phb .bxt-chips i { font-size: 14px; padding: 9px 13px; }
  .bento-wall.phb .bxt-print { width: 64px; height: 84px; }
  .bento-wall.phb .bxt-print .ic { width: 55px; height: 55px; margin-left: 4px; }
  .bento-wall.phb .bxt-print em { left: 17px; top: 39px; width: 29px; height: 35px; }
  /* Compliance: what is due, as ruled rows */
  .bento-wall.phb .bxa-due { gap: 0; }
  .bento-wall.phb .bxa-due i { padding: 10px 0; border-top: 1px solid color-mix(in srgb, currentColor 14%, transparent); }
  /* the plate is white whatever the page ground: its labels take the card's
     own ink, not the dark page's bone, and the dates the orange that clears
     4.5:1 on white */
  .bento-wall.phb .bxa-due b { font-size: 15px; color: inherit; }
  .bento-wall.phb .bxa-due em { font-size: 12.5px; color: var(--o-800); }
  /* Photo cards: the picture fills the card; the eyebrow, the headline and
     its line sit over the TOP on a soft dark scrim (Apple's caption over
     media). A label alone is never enough. */
  .bento-wall.phb .bx.photo { justify-content: flex-start; padding: 20px; }
  .bento-wall.phb .bx.photo::after {
    background: linear-gradient(to bottom, rgba(0,0,0,.78) 0%, rgba(0,0,0,.62) 22%, rgba(0,0,0,.34) 44%, rgba(0,0,0,0) 64%);
  }
  .bento-wall.phb .bx.photo .kicker { margin-top: 0; color: rgba(255,255,255,.85); }
  .bento-wall.phb .bx.photo .copy { flex: 0 0 auto; }
  .bento-wall.phb .bx.photo .copy h3 { margin-bottom: 0; }
  .bento-wall.phb .bx.photo .bx-line {
    display: block; position: relative; z-index: 2; margin: 8px 0 0;
    color: rgba(255,255,255,.88); opacity: 1; font-size: var(--t-base); line-height: 1.4; max-width: 30ch;
  }
  /* a card three widths to the right never crosses the vertical observer
     the reveal waits on; rail children are simply there (css/site.css has
     the same rule for the other rails) */
  .rv-armed .bento-wall.phb [data-reveal] { opacity: 1; transform: none; transition: none; }
  .hl54-ctl { display: flex; justify-content: center; align-items: center; gap: 10px; margin-top: 8px; }
}
.hl54-ctl[hidden] { display: none !important; }
@media (min-width: 701px) { .hl54-ctl { display: none !important; } }
.hl54-dots {
  display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 16px; border-radius: 999px;
  background: color-mix(in srgb, var(--ink) 9%, transparent);
}
.hl54-dot {
  position: relative; width: 8px; height: 8px; padding: 0; border: 0; border-radius: 999px; overflow: hidden;
  background: color-mix(in srgb, var(--ink) 34%, transparent); cursor: pointer;
  transition: width .32s var(--glide), background .2s linear;
}
.hl54-dot::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: var(--ink); transform-origin: left center; transform: scaleX(var(--p, 0)); }
.hl54-dot.is-on { width: 28px; }
.hl54-dot:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.hl54-play, .sv54-play {
  flex: none; width: 40px; height: 40px; padding: 0; border: 0; border-radius: 50%; cursor: pointer;
  display: grid; place-items: center; color: var(--ink);
  background: color-mix(in srgb, var(--ink) 9%, transparent);
  transition: transform .15s var(--snap), background .2s linear;
}
.hl54-play:active, .sv54-play:active { transform: scale(.94); }
.hl54-play .ic, .sv54-play .ic { grid-area: 1 / 1; width: 16px; height: 16px; stroke: none; fill: currentColor; }
.hl54-play .hl54-ic-play, .sv54-play .sv54-ic-play { display: none; }
.hl54-play.is-paused .hl54-ic-play, .sv54-play.is-paused .sv54-ic-play { display: block; }
.hl54-play.is-paused .hl54-ic-pause, .sv54-play.is-paused .sv54-ic-pause { display: none; }
@media (prefers-reduced-motion: reduce) { .hl54-play, .sv54-play { display: none; } .hl54-dot.is-on::after { transform: none; } }

/* ---- item 5: take a closer look -----------------------------------------
   Four chips, one stage with a fixed ratio, one order on four screens. The
   devices are the site's own frames sized by --s; the stage is a size
   container, so each frame's --s is solved in css and holds from first
   paint (js/r54.js writes the same number for an engine without typed
   arithmetic). Switching: the outgoing device fades and settles back, the
   incoming one rises in, about 500ms. */
.ds54-sec { min-height: 0; padding-block: var(--sec-y); }
/* Round 58, item 6: "Take a closer look", the section's eyebrow, in the one
   head grammar (eyebrow, 18px, headline, lede) */
.ds58-eb { margin: 0 0 18px; }
.ds54-sec .st34-in { padding-block: clamp(24px, 6vw, 72px) 0; }
.ds54 { margin-top: clamp(28px, 4vw, 48px); }
.ds54-chips { display: flex; justify-content: center; gap: 6px; flex-wrap: nowrap; }
.ds54-chips button {
  flex: none; padding: 10px 18px; border: 0; border-radius: 999px; cursor: pointer;
  font: 600 var(--t-sm)/1 var(--font-ui); letter-spacing: -.005em; color: var(--ink-2);
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  transition: background .2s linear, color .2s linear, transform .15s var(--snap);
}
.ds54-chips button:hover { color: var(--ink); }
.ds54-chips button[aria-selected="true"] { background: var(--ink); color: var(--g-bg, var(--ground)); }
.ds54-chips button:active { transform: scale(.96); }
.ds54-chips button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.ds54-short { display: none; }
.ds54-stage {
  position: relative; margin-top: clamp(22px, 3vw, 36px);
  aspect-ratio: 16 / 10; container-type: size; overflow: visible;
}
/* Round 55, item C5: the incoming device gets a turn, Duo-like, from
   rotateY(-14deg) at .96 scale to rest in 560ms, and the outgoing one settles
   back the other way. The panel is the wrapper; the frames inside it (the
   preserve-3d shells) are never transformed themselves. */
/* Round 57, item 5: the Duo unfold. The incoming device TURNS in, from 26
   degrees on a 1000px perspective, and its screen catches one band of light
   as it faces you; the outgoing one folds away the other side. It reads as a
   turn because the opacity is short and early (in) or short and late (out)
   while the rotation runs the whole 600ms: the device is seen turning, not
   fading. Wrapper transforms only; the frames' own shells never move. */
.ds54-panel {
  position: absolute; inset: 0; display: grid; place-items: center;
  opacity: 0; visibility: hidden; transform: perspective(1000px) rotateY(-26deg) scale(.95);
  transition: opacity .12s linear, transform .6s cubic-bezier(.45, .2, .2, 1), visibility 0s linear .6s;
}
.ds54-panel[hidden] { display: grid; }
/* in: it shows as it starts to turn, and the turn is seen */
.ds54-panel.is-on { opacity: 1; visibility: visible; transform: none; transition-delay: .2s, .2s, 0s; }
/* out: it folds away first and goes only once it is edge-on enough */
.ds54-panel.is-out {
  opacity: 0; visibility: visible; transform: perspective(1000px) rotateY(30deg) scale(.95);
  transition: opacity .12s linear .22s, transform .34s cubic-bezier(.5, 0, .8, .5), visibility 0s linear .6s;
}
/* the light across the incoming screen */
.ds54-panel .pad-screen::before, .ds54-panel .ph-screen::before {
  content: ""; position: absolute; z-index: 8; top: -30%; bottom: -30%; left: 0; width: 40%; pointer-events: none;
  background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.2) 50%, rgba(255,255,255,0));
  transform: translateX(-160%) skewX(-14deg); opacity: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .ds54-panel.is-turn .pad-screen::before, .ds54-panel.is-turn .ph-screen::before {
    animation: mh3sweepA .6s cubic-bezier(.32, .06, .4, 1) .42s both;
  }
}
@keyframes mh3sweepA {
  0%   { transform: translateX(-160%) skewX(-14deg); opacity: 0; }
  15%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { transform: translateX(320%) skewX(-14deg); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .ds54-panel, .ds54-panel.is-out { transition: none; transform: none; } }
/* Round 60, item 1: each device's scale is solved from the stage in css, as
   tan(atan2(a, b)) (a / b as a number wherever CSS has trigonometry, Safari
   15.4 and up), so every panel has its size from the first paint in every
   engine; typed arithmetic, calc(a / b) of two lengths, is not Safari's. The
   tablet's is the number js/site.js's fitPads() used to write over it after
   load (the stage over 760, .4 to 1.12), so it looks exactly as it did.
   The laptop box is the laptop's own outline inside its picture (1229 x 1026
   of 1600 x 1120); the kitchen box is the tablet and its bracket (740 x 596).
   js/r54.js writes the same numbers for an engine without trigonometry. */
.ds54-pad { --s: 1.12; } .ds54-ph { --s: .6; } .ds60-lap { --s: .66; } .ds60-kds { --ks: 1; }
@supports (width: calc(1px * tan(atan2(1px, 1px)))) {
  .ds54-pad { --s: clamp(.4, tan(atan2(100cqw, 760px)), 1.12); }
  .ds54-ph  { --s: min(tan(atan2(90cqw, 393px)), tan(atan2(96cqh, 852px))); }
  .ds60-lap { --s: min(tan(atan2(97cqw, 1229px)), tan(atan2(98cqh, 1026px))); }
  .ds60-kds { --ks: min(tan(atan2(97cqw, 740px)), tan(atan2(99cqh, 596px))); }
}
/* the tablet stands front-on: no turn, its shadow on the flat face */
.ds54-pad .pad { --sry: 0deg; --srx: 0deg; }
.ds54-pad .pad.r48-shell { display: none; }
.ds54-pad .pad.r48-face { filter: drop-shadow(0 30px 40px rgba(0,0,0,.22)); }
.ds54-pad .pad-screen .inner > .ui { height: 100%; }
.ds54-pad .till { min-height: 100%; }
.ds54-ph .phone { --ry: 0deg; --rx: 0deg; }
.ds54-ph .phone.r48-face { filter: drop-shadow(0 30px 40px rgba(0,0,0,.24)); }
.ds54-phui { padding: 74px 20px 30px; display: flex; flex-direction: column; gap: 14px; font-size: 14px; }
.ds54-phui .ph-hd { margin: 0; }
.ds54-lines { display: grid; gap: 10px; }
.ds54-line {
  display: grid; grid-template-columns: 26px minmax(0, 1fr) auto; gap: 10px; align-items: baseline;
  padding: 12px 14px; border-radius: 14px; background: var(--ui-card); border: 1px solid var(--ui-line);
  font-size: 14px; line-height: 1.35;
}
.ds54-line b { font-family: var(--font-mono); font-weight: 700; color: var(--ui-acc); }
.ds54-line em { font-style: normal; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.ds54-line small { display: block; font-size: 12px; color: var(--ui-ink-3); margin-top: 2px; }
.ds54-sum { display: flex; justify-content: space-between; align-items: baseline; padding: 6px 4px 0; font-size: 13px; color: var(--ui-ink-2); }
.ds54-sum b { font-family: var(--font-mono); font-size: 24px; font-weight: 700; letter-spacing: -.03em; color: var(--ui-ink); }
.ds54-pay { display: grid; gap: 8px; margin-top: auto; }
.ds54-pay .pb { display: block; text-align: center; font-size: 15px; font-weight: 700; padding: 15px; border-radius: 14px; background: var(--ui-acc); color: #000000; }
.ds54-pay .pb.sec { background: var(--ui-card); border: 1px solid var(--ui-line); color: var(--ui-ink-2); font-weight: 600; font-size: 13px; padding: 12px; }
/* ---- Round 60, item 1: the laptop is a picture, the kitchen is a tablet --
   The flat CSS laptop and the drawn monitor on a stand are gone. The laptop
   is img/devices/mod/closer-mac.webp (tools/mk-mod-macs.py closer): the
   module pages' photoreal laptop, the dashboard with Table 7 in the live feed
   warped onto its screen, clipped to the laptop's own outline. Its glare is
   one band clipped to the screen's quad in the picture (the numbers
   tools/mk-mod-macs.py prints), so it crosses the glass and nothing else. */
.ds60-lap { position: relative; width: calc(1229px * var(--s)); height: calc(1026px * var(--s)); overflow: hidden; }
.ds60-lap > img, .ds60-glare {
  position: absolute; left: calc(-185px * var(--s)); top: calc(-47px * var(--s));
  width: calc(1600px * var(--s)); height: calc(1120px * var(--s)); max-width: none; display: block;
}
.ds60-glare {
  pointer-events: none; overflow: hidden;
  clip-path: polygon(13.40% 7.49%, 86.60% 8.33%, 80.07% 49.93%, 19.93% 49.93%);
}
.ds60-glare::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 12%; width: 26%;
  background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.2) 50%, rgba(255,255,255,0));
  transform: translateX(-160%) skewX(-14deg); opacity: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .ds54-panel.is-turn .ds60-glare::before { animation: mh3sweepA .6s cubic-bezier(.32, .06, .4, 1) .42s both; }
}
/* The kitchen screen: the Tablet panel's own frame, landscape, four tickets
   two by two on its screen, on a wall bracket: a plate on the wall down and
   to the left, a short arm on a joint running up to the tablet's back. A
   centred neck and foot read as a desk stand; an arm off to one side reads
   as a mount. Flat colours from the frame's own darks, no gloss. The mount
   is drawn at the tablet's natural size (740 x 520) and scaled with it. */
.ds60-kds { position: relative; width: calc(740px * var(--ks)); height: calc(596px * var(--ks)); }
.ds60-kds .pad-box.ds60-kpad { --s: var(--ks); position: absolute; left: 0; top: 0; }
.ds60-kpad .pad { --sry: 0deg; --srx: 0deg; }
.ds60-kpad .pad.r48-face { filter: drop-shadow(0 30px 40px rgba(0,0,0,.3)); }
.ds60-kpad .pad-screen, .ds60-kpad .pad-screen .inner { background: #1C1C1E; }
/* the board is laid out on a 805px screen and drawn at .86, so two rows of
   tickets fit a 692 x 472 screen whole: a wall display carries more than
   the till does, at the same type size a cook reads from the pass */
.ds60-kpad .kds2 { border-radius: 0; width: calc(100% / .86); min-height: calc(100% / .86); padding: 18px 18px 16px; gap: 14px;
  transform: scale(.86); transform-origin: 0 0; }
.ds60-kpad .kds2 > .kds { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.ds60-mount { position: absolute; left: 0; top: 0; width: 740px; height: 596px; transform: scale(var(--ks)); transform-origin: 0 0; }
.ds60-mount i { position: absolute; display: block; }
.ds60-plate { left: 154px; top: 512px; width: 132px; height: 84px; border-radius: 18px; background: #2A2A2E; }
.ds60-plate i { top: 40px; width: 8px; height: 8px; border-radius: 50%; background: #18181A; }
.ds60-plate i:first-child { left: 18px; } .ds60-plate i:last-child { right: 18px; }
.ds60-arm { left: 205px; top: 541px; width: 190px; height: 30px; border-radius: 15px; background: #3A3A3F;
  transform-origin: 15px 15px; transform: rotate(-24deg); }
.ds60-joint { left: 201px; top: 537px; width: 38px; height: 38px; border-radius: 50%; background: #444449; }
@media (max-width: 700px) {
  .ds54-chips { gap: 4px; }
  .ds54-chips button { padding: 9px 12px; font-size: 13px; }
  .ds54-long { display: none; } .ds54-short { display: inline; }
  .ds54-stage { aspect-ratio: 1 / 1; margin-top: 18px; }
}

/* ---- item 6: the service panel, the Duo pattern -------------------------
   One media card (16:10, 4:5 on a phone) playing a six-second product-UI
   scene per service; three chips with a thin progress bar in the active
   one; the caption; the pause/play button. The scenes are the product-UI
   components (css/product-ui.css): dish tiles, order lines, the floor
   plan. Each step is a class js/r54.js adds on a timer (.s1 to .s4);
   under reduced motion every scene carries all four and nothing moves. */
.sv54-card {
  position: relative; aspect-ratio: 16 / 10; max-width: 920px; margin-inline: auto;
  border-radius: var(--r-6); overflow: hidden; isolation: isolate; container-type: inline-size;
  background: #F7F3EE; border: 1px solid rgba(0,0,0,.07); box-shadow: var(--lift-3);
}
.sv54-scene {
  position: absolute; inset: 0; opacity: 0; visibility: hidden;
  transition: opacity .45s var(--glide), visibility 0s linear .45s;
}
.sv54-scene[hidden] { display: block; }
.sv54-scene.is-on { opacity: 1; visibility: visible; transition-delay: 0s; }
.sv54-ui {
  --ui-bg: #F7F3EE; --ui-card: #FFFFFF; --ui-sunk: #F0EDE8; --ui-line: #E4E0DA; --ui-ink: #000000;
  --ui-ink-2: #5C5A57; --ui-ink-3: #6E6D6B; --ui-acc: #FF6B3D; --ui-acc-sf: #FFF0E9; --ui-ph: #E9E2D8;
  --ui-warn-line: #E8C87A; --ui-go-line: #A6DCC6;
  position: absolute; inset: 0; padding: 18px; display: grid; gap: 14px;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  font-family: var(--font-ui); font-size: 13px; line-height: 1.4; color: var(--ui-ink);
}
.sv54-menu { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-rows: repeat(2, minmax(0, 1fr)); gap: 10px; min-height: 0; }
.sv54-menu-photo { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.sv54-ui .dish { border-radius: 12px; transition: transform .25s var(--snap), box-shadow .25s var(--glide); }
.sv54-ui .dish .ph img { display: block; width: 100%; height: 100%; object-fit: cover; }
.sv54-ui .dish .nm b { font-size: 11.5px; overflow-wrap: break-word; } .sv54-ui .dish .nm span { font-size: 11.5px; }
.sv54-ui .dish { display: flex; flex-direction: column; min-height: 0; }
.sv54-ui .dish .ph { flex: 1 1 auto; min-height: 0; }
.sv54-ui .dish .nm { flex: none; }
.sv54-order {
  display: flex; flex-direction: column; gap: 10px; min-width: 0;
  padding: 14px; border-radius: 16px; background: var(--ui-card); border: 1px solid var(--ui-line);
}
.sv54-oh b { display: block; font-size: 15px; font-weight: 700; }
.sv54-oh small { display: block; font-size: 11px; color: var(--ui-ink-3); margin-top: 2px; }
.sv54-olines { position: relative; display: grid; gap: 8px; align-content: start; flex: 1; min-height: 76px; }
.sv54-ol { display: grid; grid-template-columns: 22px minmax(0, 1fr) auto; gap: 8px; align-items: baseline; font-size: 12.5px; }
.sv54-ol b { font-family: var(--font-mono); font-weight: 700; color: var(--ui-acc); }
.sv54-ol em { font-style: normal; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.sv54-ol small { display: block; font-size: 11px; color: var(--ui-ink-3); }
.sv54-empty { position: absolute; left: 0; right: 0; top: 0; margin: 0; font-size: 12px; color: var(--ui-ink-3); transition: opacity .3s linear; }
.sv54-tot { display: flex; justify-content: space-between; align-items: baseline; padding-top: 10px; border-top: 1px dashed var(--ui-line); font-size: 12px; color: var(--ui-ink-2); }
.sv54-tot b { font-family: var(--font-mono); font-size: 20px; font-weight: 700; letter-spacing: -.03em; color: var(--ui-ink); }
.sv54-tot i { display: none; font-style: normal; }
.sv54-pb { display: block; text-align: center; font-size: 13px; font-weight: 700; padding: 11px; border-radius: 11px; background: var(--ui-acc); color: #000000;
  transition: transform .2s var(--snap), background .2s linear, opacity .3s linear; }
.sv54-pb.sv54-pb-quiet { background: var(--ui-sunk); color: var(--ui-ink-2); font-weight: 600; }
.sv54-paid { display: none; text-align: center; font-size: 13px; font-weight: 700; padding: 11px; border-radius: 11px; background: #E7F4EE; color: #0E5C40; }
/* the steps: everything with data-step waits for its class */
.sv54-ol[data-step], .sv54-queue, .sv54-sheet, .sv54-toast { opacity: 0; transform: translate3d(0, 8px, 0); transition: opacity .4s var(--glide), transform .45s var(--h13-ease); }
.sv54-scene.s1 [data-step="1"], .sv54-scene.s2 [data-step="2"], .sv54-scene.s3 [data-step="3"], .sv54-scene.s4 [data-step="4"] { opacity: 1; transform: none; }
.sv54-scene.s2 .sv54-ol[data-step="2"][style*="--k"] { transition-delay: .18s; }
.sv54-scene.s1 .sv54-empty, .sv54-scene.s2 .sv54-empty, .sv54-scene.s3 .sv54-empty { opacity: 0; }
.sv54-tot i[data-t="0"] { display: inline; }
.sv54-scene.s1 .sv54-tot i[data-t="0"], .sv54-scene.s2 .sv54-tot i[data-t="0"], .sv54-scene.s3 .sv54-tot i[data-t="0"] { display: none; }
.sv54-scene.s1:not(.s2) .sv54-tot i[data-t="1"] { display: inline; }
.sv54-scene.s2 .sv54-tot i[data-t="2"] { display: inline; }
.sv54-scene.s3 .sv54-tot i[data-t="3"] { display: inline; }
.sv54-scene.s1 .dish[data-step="1"], .sv54-scene.s2 .dish[data-step="2"] { animation: sv54tap .55s var(--snap) both; }
@keyframes sv54tap { 0% { transform: none; box-shadow: none; } 35% { transform: scale(.96); box-shadow: 0 0 0 3px var(--ui-acc); } 100% { transform: none; box-shadow: 0 0 0 2px var(--ui-acc); } }
.sv54-scene.s3 .sv54-pb[data-step="3"], .sv54-scene.s4 .sv54-pb[data-step="4"] { display: none; }
.sv54-scene.s3 .sv54-paid[data-step="3"], .sv54-scene.s4 .sv54-paid[data-step="4"] { display: block; animation: sv54pop .5s var(--h13-ease) both; }
@keyframes sv54pop { from { opacity: 0; transform: translate3d(0, 6px, 0) scale(.98); } to { opacity: 1; transform: none; } }
/* QSR: the number called. Round 56, item 2: a customer display, not a black
   box over the till with the tile grid showing round it. The panel covers
   the whole screen of the mock (the tiles and the basket disappear under it),
   solid black, no blur, no shadow: "Now serving" small, the number large in
   the brand orange, one quiet line in the mock's mono. It fades in as the
   fourth step and is the settled state of the scene; reduced motion shows it. */
.sv54-queue {
  position: absolute; inset: 0; z-index: 4; width: auto; aspect-ratio: auto;
  display: grid; place-content: center; justify-items: center; row-gap: 10px; text-align: center;
  border-radius: 0; background: #000000; color: #F7F3EE; box-shadow: none;
  transform: none; transition: opacity .5s var(--glide);
}
.sv54-queue small { font-size: 13px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: #A1A1A6; }
.sv54-queue b { font-family: var(--font-mono); font-size: clamp(84px, 20cqw, 156px); font-weight: 700; letter-spacing: -.05em; line-height: 1; color: var(--ui-acc); }
.sv54-queue span { font-family: var(--font-mono); font-size: 14px; font-weight: 500; letter-spacing: .02em; color: #A1A1A6; }
/* Café: the modifier sheet over the tiles */
.sv54-sheet {
  position: absolute; left: 18px; bottom: 18px; width: calc((100% - 50px) * 1.25 / 2.25);
  padding: 14px; border-radius: 16px; background: var(--ui-card); box-shadow: var(--lift-4); border: 1px solid var(--ui-line);
  display: grid; gap: 10px; transform: translate3d(0, 24px, 0);
}
.sv54-sh b { display: block; font-size: 15px; font-weight: 700; } .sv54-sh small { display: block; font-size: 11px; color: var(--ui-ink-3); }
.sv54-mods { display: grid; grid-template-columns: 1fr 1fr; gap: 7px; }
.sv54-mod { display: flex; justify-content: space-between; gap: 6px; padding: 8px 10px; border-radius: 9px; font-size: 12px; font-weight: 600;
  background: var(--ui-sunk); border: 1px solid transparent; transition: background .25s linear, border-color .25s linear, color .25s linear; }
.sv54-mod em { font-style: normal; font-family: var(--font-mono); font-size: 11px; color: var(--ui-ink-3); }
.sv54-scene.s2 .sv54-mod[data-mod="oat"], .sv54-scene.s2 .sv54-mod[data-mod="shot"] { background: var(--ui-acc-sf); border-color: var(--ui-acc); color: #A13D20; }
.sv54-scene.s2 .sv54-mod[data-mod="shot"] { transition-delay: .32s; }
.sv54-done { transition: transform .2s var(--snap), background .2s linear; }
.sv54-scene.s3 .sv54-done { transform: scale(.97); background: #E25D34; }
.sv54-scene.s3 .sv54-sheet { opacity: 0; transform: translate3d(0, 24px, 0); }
/* Casual: the room, then the kitchen */
.sv54-floor { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.sv54-flhd b { display: block; font-size: 15px; font-weight: 700; } .sv54-flhd small { display: block; font-size: 11px; color: var(--ui-ink-3); }
.sv54-floor .floor { flex: none; grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: minmax(0, 132px); align-content: start; gap: 8px; }
.sv54-floor .tbl { display: flex; flex-direction: column; justify-content: flex-end; }
.sv54-floor .tbl b { font-size: 15px; } .sv54-floor .tbl small { font-size: 10.5px; }
.sv54-floor .tbl { padding: 9px 9px; border-radius: 10px; transition: background .3s linear, border-color .3s linear; }
.sv54-floor .tbl b { font-size: 12px; } .sv54-floor .tbl small { font-size: 9.5px; }
.sv54-floor .tbl.seated .amt { font-size: 10.5px; }
.sv54-seated { display: none; }
.sv54-t7 .amt { display: none; font-family: var(--font-mono); font-size: 10.5px; font-weight: 700; margin-top: 3px; opacity: 0; transform: none; }
.sv54-scene.s1 .sv54-t7 { border-color: #FFB298; background: #FFF0E9; }
.sv54-scene.s1 .sv54-t7 .dot { background: var(--ui-acc); }
.sv54-scene.s1 .sv54-t7 .sv54-open { display: none; } .sv54-scene.s1 .sv54-t7 .sv54-seated { display: block; }
.sv54-scene.s2 .sv54-t7 .amt { display: block; opacity: 1; }
.sv54-toast {
  position: absolute; left: 18px; bottom: 18px; display: flex; align-items: center; gap: 12px;
  padding: 12px 16px 12px 12px; border-radius: 14px; background: #000000; color: #F7F3EE; box-shadow: var(--lift-4); font-size: 12.5px;
}
.sv54-toast .ic-tile { width: 32px; height: 32px; border-radius: 9px; background: rgba(255,255,255,.1); color: #F7F3EE; display: grid; place-items: center; flex: none; }
.sv54-toast .ic-tile .ic { width: 18px; height: 18px; }
.sv54-toast b { display: block; font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ui-acc); }
/* the phone card is 4:5: the scenes stack */
@container (max-width: 560px) {
  .sv54-ui { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); padding: 14px; gap: 12px; }
  .sv54-menu { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-rows: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .sv54-ui .dish .ph { aspect-ratio: 16 / 10; flex: none; }
  .sv54-ui .dish .nm { padding: 6px 7px 7px; }
  .sv54-sheet { width: calc(100% - 28px); left: 14px; }
  .sv54-sheet { bottom: 14px; }
  .sv54-floor .floor { flex: none; grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-rows: auto; gap: 6px; }
  .sv54-floor .tbl { padding: 7px 6px; justify-content: flex-start; }
  .sv54-floor .tbl b { font-size: 11px; } .sv54-floor .tbl small { font-size: 8.5px; }
  .sv54-toast { left: 14px; right: 14px; bottom: 14px; }
}
.sv54-ctl { display: flex; align-items: center; justify-content: center; gap: 12px; margin-top: 22px; }
.sv54-chips { display: flex; gap: 6px; flex-wrap: nowrap; }
.sv54-chips button {
  position: relative; flex: none; padding: 10px 16px 12px; border: 0; border-radius: 999px; cursor: pointer; overflow: hidden;
  font: 600 var(--t-sm)/1 var(--font-ui); letter-spacing: -.005em; color: var(--ink-2);
  background: color-mix(in srgb, var(--ink) 7%, transparent);
  transition: background .2s linear, color .2s linear, transform .15s var(--snap);
}
.sv54-chips button:hover { color: var(--ink); }
.sv54-chips button[aria-selected="true"] { color: var(--ink); background: color-mix(in srgb, var(--ink) 12%, transparent); }
.sv54-chips button:active { transform: scale(.96); }
.sv54-chips button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.sv54-bar { position: absolute; left: 14px; right: 14px; bottom: 5px; height: 2px; border-radius: 1px; background: color-mix(in srgb, var(--ink) 14%, transparent); opacity: 0; }
.sv54-bar::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: var(--ink); transform-origin: left center; transform: scaleX(var(--p, 0)); }
.sv54-chips button[aria-selected="true"] .sv54-bar { opacity: 1; }
.sv54-cap { margin: 14px auto 0; max-width: 52ch; text-align: center; font-size: var(--t-base); line-height: 1.5; color: var(--ink-2); min-height: 1.5em; }
.sv54-more { margin: 18px auto 0; max-width: 60ch; text-align: center; font-size: var(--t-sm); line-height: 1.6; color: var(--ink-3); }
.sv54-more a { color: var(--ink-2); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, var(--ink) 25%, transparent); }
.sv54-more a:hover { color: var(--ink); }
@media (max-width: 700px) {
  .sv54-card { aspect-ratio: 4 / 5; border-radius: var(--r-5); }
  .sv54-ctl { gap: 8px; margin-top: 16px; }
  .sv54-chips { gap: 4px; }
  .sv54-chips button { padding: 9px 11px 11px; font-size: 12.5px; }
  .sv54-bar { left: 10px; right: 10px; }
  .sv54-cap { font-size: var(--t-sm); }
}
@media (prefers-reduced-motion: reduce) {
  .sv54-ol[data-step], .sv54-queue, .sv54-sheet, .sv54-toast, .sv54-scene, .sv54-scene .dish { transition: none; animation: none; }
  .sv54-bar { display: none; }
}

/* ---- item 7: the numbers ---------------------------------------------- */
.nm54 { padding-block: clamp(72px, 9vw, 128px); }
.nm54-list { list-style: none; margin: 0; padding: 0; display: grid; gap: clamp(40px, 5.5vw, 72px); justify-items: center; text-align: center; }
.nm54-stat { max-width: 34ch; }
/* Round 57b: a figure wider than its caption's measure ("33 permissions" at
   112px on a 430px phone is 18px wider than the 34ch the caption keeps; 4px
   at 1440) overflowed its own box to the right and sat off-centre. As a flex
   column the figure keeps its own width and centres over the caption,
   spilling evenly both ways and never past the gutter; the caption is
   unchanged. */
.nm54-stat { display: flex; flex-direction: column; align-items: center; }
/* Round 58, item 5: one pattern for all four. The figure alone on its line
   (line-height .9), the unit under it at 36 percent of the figure with 8px
   above it, the caption under that. At 390 "33 permissions" no longer has to
   fit one line, so no stat wraps and none leaves a hole. The figure takes
   the section's own ink (--ink follows the ground: bone on a phone's black,
   ink on the desktop's eggshell). */
.nm54-v {
  display: flex; flex-direction: column; align-items: center;
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(60px, 8.4vw, 118px); letter-spacing: -.045em; line-height: .9;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
/* Round 57, item 5: Apple's stats rhythm. The digits sit in their own span
   (js/r57.js) so the count writes text, never layout, in a box already as
   wide as the final figure. */
.nm54-n { display: block; min-width: var(--nm-w, auto); text-align: center; }
@media (max-width: 700px) { .nm54-v { font-size: clamp(72px, 24.6vw, 108px); } }
.nm54-u { display: block; margin-top: 8px; font-size: .36em; font-weight: 700; letter-spacing: -.02em; line-height: 1.1; }
.nm54-stat p { margin: 14px auto 0; font-size: 17px; line-height: 1.45; color: var(--ink-2); text-wrap: balance; }
@media (max-width: 700px) { .nm54-stat p { font-size: 15px; } }
/* the sequence, per stat as it enters (js/r57.js adds .is-in, 120ms apart
   when two arrive together): the figure counts up (900ms), the unit fades
   and rises as the count lands (300ms from .78s), one band of light crosses
   the figure (1.2s from .9s) and the caption rises with it (300ms from .9s).
   The band is background-clip: text from the ink through the brand orange
   and back. Reduced motion, and no script: everything at rest. */
@media (prefers-reduced-motion: no-preference) {
  .js .nm54-list.is-armed .nm54-n {
    background-image: linear-gradient(90deg, var(--ink) 0%, var(--ink) 40%, var(--o-300) 47%, var(--o-500) 50%, var(--o-300) 53%, var(--ink) 60%, var(--ink) 100%);
    background-size: 300% 100%; background-position: 100% 0; background-repeat: no-repeat;
    -webkit-background-clip: text; background-clip: text; color: transparent; -webkit-text-fill-color: transparent;
  }
  .js .nm54-stat.is-in .nm54-n { animation: nm54sweep 1.2s var(--glide) .9s both; }
  .js .nm54-list.is-armed .nm54-u,
  .js .nm54-list.is-armed .nm54-stat > p { opacity: 0; transform: translate3d(0, 12px, 0); }
  .js .nm54-list.is-armed .nm54-stat.is-in .nm54-u {
    opacity: 1; transform: none;
    transition: opacity .3s var(--glide) .78s, transform .3s cubic-bezier(.16, 1, .3, 1) .78s;
  }
  .js .nm54-list.is-armed .nm54-stat.is-in > p {
    opacity: 1; transform: none;
    transition: opacity .3s var(--glide) .9s, transform .3s cubic-bezier(.16, 1, .3, 1) .9s;
  }
}
@keyframes nm54sweep { from { background-position: 100% 0; } to { background-position: 0% 0; } }

/* ---- item 8: callouts drawn onto the kitchen ticket --------------------- */
.kc54 { position: absolute; inset: 16px; pointer-events: none; z-index: 5; }
.kc54-lines { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; display: block; }
.kc54-lines path {
  fill: none; stroke: var(--o-500); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 1 1; stroke-dashoffset: 1; opacity: 0;
}
.kc54.is-on .kc54-lines path { opacity: 1; stroke-dashoffset: 0; transition: stroke-dashoffset .6s var(--glide), opacity .1s linear; transition-delay: var(--d, 0s), var(--d, 0s); }
.kc54-tag {
  position: absolute; left: 0; top: 0; display: inline-block; white-space: nowrap;
  padding: 7px 11px 8px; border-radius: 9px;
  font: 700 13px/1.15 var(--font-display); letter-spacing: -.01em;
  background: var(--o-500); color: var(--n-900);
  box-shadow: 0 0 0 3px #FFFFFF, var(--lift-2);
  opacity: 0; transform: rotate(var(--rot, 0deg)) scale(.7);
  transition: opacity .28s var(--glide), transform .45s var(--snap); transition-delay: calc(var(--d, 0s) + .5s);
}
.kc54-tag.ink { background: var(--n-900); color: var(--bone); }
.kc54.is-on .kc54-tag { opacity: 1; transform: rotate(var(--rot, 0deg)) scale(1); }
.kc54:not(.is-on) .kc54-tag, .kc54:not(.is-on) .kc54-lines { visibility: hidden; }
@media (max-width: 700px) {
  .kc54-desk { display: none; }
  .kc54-tag { font-size: 12px; padding: 6px 9px 7px; }
  .kc54-lines path { stroke-width: 2; }
}
@media (prefers-reduced-motion: reduce) {
  .kc54-lines path, .kc54-tag { transition: none; }
}

/* ---- item 9a: why run on delEat, the card rail -------------------------- */
.wy54 { overflow-x: clip; }
.wy54-wrap { position: relative; margin-top: var(--bento-top); }
.wy54-rail {
  display: flex; gap: 16px; overflow-x: auto; overscroll-behavior-inline: contain;
  scroll-snap-type: x mandatory; scrollbar-width: none;
  margin-inline: calc(-1 * var(--gutter)); padding: 6px var(--gutter) 10px; scroll-padding-inline: var(--gutter);
}
@media (min-width: 901px) { .wy54-rail { margin-right: calc(50% - 50vw); } }
.wy54-rail::-webkit-scrollbar { display: none; }
.wy54-card {
  position: relative; flex: 0 0 clamp(280px, 25vw, 340px); scroll-snap-align: start;
  display: flex; flex-direction: column;
  border-radius: var(--r-6); overflow: hidden; isolation: isolate;
  background: linear-gradient(160deg, var(--nt-surface) 0%, var(--nt-surface-2) 100%); border: 1px solid var(--nt-line);
}
.wy54-art {
  position: relative; aspect-ratio: 4 / 3; margin: 10px; border-radius: 20px; overflow: hidden; background: #F7F3EE;
  --ui-bg: #F7F3EE; --ui-card: #FFFFFF; --ui-sunk: #F0EDE8; --ui-line: #E4E0DA; --ui-ink: #000000;
  --ui-ink-2: #5C5A57; --ui-ink-3: #6E6D6B; --ui-acc: #FF6B3D; --ui-acc-sf: #FFF0E9; --ui-ph: #E9E2D8;
  --ink: #000000; --ink-2: #4D4D4D; --ink-3: #6E6D6B; color: #000000;
}
.wy54-body { flex: 1; display: flex; flex-direction: column; gap: 8px; padding: 10px 22px 24px; }
.wy54-card h3 { margin: 0; font-family: var(--font-display); font-weight: 600; font-size: 21px; line-height: 1.2; letter-spacing: var(--tr-head); color: var(--bone); }
.wy54-card p { margin: 0; font-size: 15px; line-height: 1.45; color: var(--nt-ink-2); }
.wy54-card .btn-link { margin-top: auto; padding-top: 10px; color: var(--o-400); }
.wy54-pad { margin-top: 18px; }
@media (max-width: 900px) { .wy54-card { flex-basis: 78vw; } .wy54-rail { gap: 12px; } .wy54-pad { display: none; } }
/* the small product visuals, each from the product-UI components */
.wy54-art .chip { font-size: 11px; padding: 5px 9px; }
.wy54-mig { display: grid; grid-template-rows: auto 1fr auto; gap: 10px; padding: 16px; }
.wy54-src { display: flex; flex-wrap: wrap; gap: 6px; }
.wy54-flow { display: flex; align-items: center; justify-content: center; gap: 12px; }
.wy54-flow i { display: block; width: 44%; height: 2px; border-radius: 1px; background: linear-gradient(90deg, #E4E0DA, #FF6B3D); }
.wy54-to { background: #000000 !important; color: #F7F3EE !important; border-color: #000000 !important; }
.wy54-steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; }
.wy54-steps i { font-style: normal; font-size: 10.5px; font-weight: 600; text-align: center; padding: 6px 2px; border-radius: 7px; background: var(--ui-sunk); color: var(--ui-ink-2); }
.wy54-steps i.on { background: var(--o-50); color: var(--o-800); box-shadow: inset 0 0 0 1px var(--o-300); }
.wy54-arui { position: absolute; inset: 14px; display: flex; flex-direction: column; gap: 6px; padding: 12px 14px; border-radius: 14px; background: #FFFFFF; border: 1px solid #E4E0DA;
  font-family: var(--font-ui); font-size: 12px; color: #000000; }
.wy54-aroh { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; padding-bottom: 6px; border-bottom: 1px dashed #E4E0DA; }
.wy54-aroh b { font-size: 14px; font-weight: 700; } .wy54-aroh small { font-size: 11px; color: #6E6D6B; }
.wy54-arl { display: flex; justify-content: space-between; gap: 8px; }
.wy54-arl span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wy54-arl em { font-style: normal; font-family: var(--font-mono); font-variant-numeric: tabular-nums; direction: ltr; unicode-bidi: isolate; }
.wy54-arsub { margin-top: auto; padding-top: 6px; border-top: 1px dashed #E4E0DA; color: #5C5A57; }
.wy54-artot { font-weight: 700; font-size: 13px; }
.wy54-arbtns { display: grid; grid-template-columns: 1.4fr 1fr; gap: 6px; margin-top: 4px; }
.wy54-arpb { text-align: center; font-size: 12px; font-weight: 700; padding: 8px; border-radius: 9px; background: #FF6B3D; color: #000000; }
.wy54-arpb.sec { background: #FFFFFF; border: 1px solid #E4E0DA; color: #5C5A57; font-weight: 600; }
.wy54-supui { position: absolute; inset: 14px; display: flex; flex-direction: column; gap: 8px; padding: 12px 14px; border-radius: 14px; background: #FFFFFF; border: 1px solid #E4E0DA; font-size: 12px; color: #000000; }
.wy54-suphd { display: flex; align-items: center; gap: 8px; padding-bottom: 8px; border-bottom: 1px solid #F0EDE8; }
.wy54-suphd b { font-size: 13px; font-weight: 700; } .wy54-suphd small { font-size: 11px; color: #6E6D6B; margin-left: auto; }
.wy54-dot { width: 8px; height: 8px; border-radius: 50%; background: #1A7F5A; box-shadow: 0 0 0 3px #E7F4EE; }
.wy54-supmsg { align-self: flex-start; max-width: 82%; padding: 8px 11px; border-radius: 12px 12px 12px 4px; background: #F0EDE8; line-height: 1.35; }
.wy54-supmsg.is-us { align-self: flex-end; border-radius: 12px 12px 4px 12px; background: #000000; color: #F7F3EE; }
.wy54-supchk { display: flex; flex-wrap: wrap; gap: 6px; margin-top: auto; }
.wy54-supchk span { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600; padding: 5px 9px 5px 7px; border-radius: 8px; background: #E7F4EE; color: #0E5C40; }
.wy54-supchk span::before { content: ""; width: 8px; height: 5px; border-left: 1.8px solid currentColor; border-bottom: 1.8px solid currentColor; transform: rotate(-45deg) translateY(-1px); }
.wy54-free { display: grid; grid-template-rows: 1fr auto; gap: 10px; padding: 14px; }
.wy54-dishes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; align-content: start; }
.wy54-dishes .dish { border-radius: 10px; }
.wy54-dishes .dish .ph img { display: block; width: 100%; height: 100%; object-fit: cover; }
.wy54-dishes .dish .nm b { font-size: 10.5px; } .wy54-dishes .dish .nm span { font-size: 10.5px; }
.wy54-freechip { display: flex; gap: 6px; flex-wrap: wrap; }
.wy54-freechip .chip:first-child { background: #FFF0E9; border-color: #FFCEBD; color: #A13D20; }

/* ---- item 9b: the compact plan compare ---------------------------------- */
.pl54 .plans { margin-top: var(--bento-top); grid-template-columns: repeat(3, minmax(0, 1fr)); }
.pl54 .plan {
  --ink: #000000; --ink-2: #4D4D4D; --ink-3: #6E6D6B; --accent-text: #A13D20; --line: #DEDEDE; --line-soft: #EFEDEA;
  --hair: 1px solid #DEDEDE; --surface: #FFFFFF; --surface-2: #F6F4F2;
  color: var(--ink); background: #FFFFFF;
}
.pl54 .plan li em { font-style: normal; font-family: var(--font-mono); font-weight: 700; color: var(--ink); margin-left: 4px; }
.pl54-foot { margin-top: var(--s-6); font-size: var(--t-sm); color: var(--ink-2); display: flex; flex-wrap: wrap; align-items: center; gap: 6px 22px; }
.pl54-foot > a:not(.btn-link) { color: var(--ink); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, var(--ink) 25%, transparent); }
@media (max-width: 900px) { .pl54 .plans { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; } .pl54 .plan { padding: var(--s-5); } }
@media (max-width: 700px) {
  .pl54 .plans.pl54-rail {
    display: flex; gap: 12px; align-items: stretch;
    overflow-x: auto; overscroll-behavior-inline: contain;
    scroll-snap-type: x mandatory; scrollbar-width: none;
    width: 100vw; margin-inline: calc(50% - 50vw);
    padding: 16px var(--gutter) 10px; scroll-padding-inline: var(--gutter);
  }
  .pl54 .plans.pl54-rail::-webkit-scrollbar { display: none; }
  .pl54 .plans.pl54-rail .plan { flex: 0 0 84vw; scroll-snap-align: start; }
  .rv-armed .pl54 .plans.pl54-rail [data-reveal] { opacity: 1; transform: none; }
}

/* ---- item 9c: the FAQ, Apple's accordion --------------------------------
   Native <details> kept for assistive technology; the height animates
   through ::details-content where the engine has it (js/r54.js is the
   fallback), and the plus turns into a cross. The separators and the plus
   are css/site.css's. */
.faq { interpolate-size: allow-keywords; }
.faq details::details-content { block-size: 0; overflow: clip; transition: block-size var(--d-4) var(--glide), content-visibility var(--d-4) allow-discrete; }
.faq details[open]::details-content { block-size: auto; }
.faq summary .pm { transition: transform var(--d-3) var(--snap); }
.faq details[open] summary .pm { transform: rotate(45deg); }
.faq details[open] summary .pm::after { transform: rotate(90deg); }
.faq details > div { padding-top: 2px; }
.faq summary:hover { color: var(--ink); }
@media (prefers-reduced-motion: reduce) { .faq details::details-content { transition: none; } }

/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  Round 57, item 4: the chapters on a phone, held without pinning         ║
   ╚══════════════════════════════════════════════════════════════════════════╝
   On a desktop the till, dashboard and kitchen chapters are GSAP-pinned
   scrubs and stay so. On a phone nothing may be fixed or sticky, so a chapter
   holds its picture the way Apple's own pin-center does it, in flow: the
   section is tall, the picture sits at its top, and during the section's
   `contain` phase the picture is translated down by exactly the distance
   scrolled, so it stands still on screen while the captions scroll past it.

   Two drivers, one look (js/r57.js decides, and sets `html.r57-ch` only on a
   phone with motion allowed):
     - `html.r57-sd`, an engine with scroll-driven animations (Chrome, Safari
       26): the hold is a transform keyframe on the section's view timeline,
       which Safari 26.4 runs off the main thread, and `--p`, the section's
       progress through `contain`, is a registered number animated on the
       same timeline;
     - `html.r57-js`, anything older: the script writes the same transform
       and the same `--p` from scroll events.
   Everything else (the till's screens, the captions, the kitchen ticket's
   age, the dashboard's zoom) is opacity and transform computed from `--p`.
   No script, reduced motion or a desktop: the settled chapter, below. */
@property --p { syntax: '<number>'; inherits: true; initial-value: 0; }
.r57-steps, .r57-shots, .r57-age, .r57-ag { display: none; }

@media (max-width: 900px) {
  /* ---- the settled chapters (what shows with no script or reduced motion)
     the till's screen is the recording's last step, the split, as a still:
     the phone never loads the scrub film at all */
  #scrub-till .scrub-video { display: none; }
  #scrub-till .r57-shots { display: block; position: absolute; inset: 0; z-index: 2; background: #000; }
  #scrub-till .r57-shots img {
    position: absolute; inset: 0; display: block; width: 100%; height: 100%;
    object-fit: cover; object-position: top center; opacity: 0;
  }
  #scrub-till .r57-shots img:last-child { opacity: 1; }
  /* the steps are the story here, so the three desktop beats step aside */
  #scrub-till .scrub-beats, #scrub-kitchen .scrub-beats { display: none; }
  #scrub-till .r57-steps, #scrub-kitchen .r57-steps {
    display: grid; gap: 12px; list-style: none; margin: var(--s-5) 0 0; padding: 0 var(--gutter);
  }
  /* Round 58: the kitchen's stage is a flex row, so with the steps in flow
     (reduced motion, no script) they stood beside a display squeezed to a
     third of the phone; they go under it, as the till's do */
  html:not(.r57-ch) #scrub-kitchen .scrub-stage { flex-direction: column; align-items: stretch; }
  .r57-steps li {
    font: 700 clamp(22px, 6.2vw, 28px)/1.22 var(--font-display); letter-spacing: -.022em;
    color: var(--bone); text-wrap: balance;
  }
}

@media (max-width: 900px) and (prefers-reduced-motion: no-preference) {
  /* ---- the held chapter --------------------------------------------------- */
  html.r57-ch .r57-sec { position: relative; box-sizing: border-box; height: var(--ch-h, 240svh); padding-top: var(--hold-top, 10svh); overflow: visible; }
  html.r57-ch .r57-hold { position: relative; z-index: 2; will-change: transform; transform: translate3d(0, 0, 0); }
  /* important: the till tablet's own entrance writes an inline transform on
     this box (js/apple.js motion(), part c); the hold replaces it here, as
     the timeline animation replaces it in r57-sd */
  html.r57-js .r57-hold { transform: translate3d(0, calc(var(--ph, 0) * var(--hold-d, 0px)), 0) !important; }
  html.r57-sd .r57-sec { view-timeline: --r57 block; view-timeline-inset: 0px; animation: r57p linear both; animation-timeline: --r57; animation-range: contain 0% contain var(--cap-d, 100%); }
  html.r57-sd .r57-hold { animation: r57hold linear both; animation-timeline: --r57; animation-range: contain 0% contain var(--hold-d, 100%); }
  /* Round 58, item 2: the section is the captions' travel plus one viewport,
     no more (js/r57.js writes --ch-h, --cap-d and --hold-d). --p runs over
     the captions' travel (--cap-d, from the moment the section's top reaches
     the top of the screen), so every caption and every step on the screen
     has come and gone by then; the picture is held a little longer
     (--hold-d), while the next block rises into the space under it, and lets
     go with that block 24px beneath it: no empty screen after the story.
     And an opaque plate in the page's own ground, 24px larger than the
     picture on every side, so no caption passing behind it shows round it. */
  html.r57-ch .r57-hold { box-shadow: 0 0 0 24px var(--g-bg, #000); border-radius: 24px; }

  /* the captions: laid along the section so caption i is at the caption
     line (--cap-y down the screen) when the section is (i + .5) / n through,
     and visible only while it is near that line */
  html.r57-ch .r57-sec > .r57-steps {
    display: block; position: absolute; inset: 0; margin: 0; padding: 0; list-style: none; pointer-events: none; z-index: 1;
  }
  html.r57-ch .r57-sec > .r57-steps li {
    position: absolute; left: var(--gutter); right: var(--gutter);
    /* Round 58: the captions are laid along the first 86 percent of the
       travel (--p reaches 1 there and runs on to 1/.86 at its end), so the
       last one is read in full before the story ends, and all of them fade
       out over the last 12 percent of the travel */
    top: calc((var(--i) + .5) / var(--n) * .86 * var(--cap-d, 140svh) + var(--cap-y, 72svh) - .6em);
    text-align: center;
    --c: calc(var(--p) * var(--n) - var(--i) - .5);
    opacity: calc(clamp(0, (.62 - max(var(--c), calc(-1 * var(--c)))) * 4, 1) * clamp(0, (1.1628 - var(--p)) / .1395, 1));
    transform: translate3d(0, calc(var(--c) * -14px), 0);
  }

  /* ---- the till: the order builds on the screen, one still per caption -- */
  html.r57-ch #scrub-till .scrub-stage { --travel: 1.5; --hold-top: 12svh; --cap-y: 60svh; }
  html.r57-ch #scrub-till .r57-shots img { opacity: clamp(0, (var(--p) * 5 - var(--k0)) * 5 + .5, 1); }
  html.r57-ch #scrub-till .r57-shots img:nth-child(1) { opacity: 1; }
  html.r57-ch #scrub-till .r57-shots img:nth-child(2) { --k0: 1; }
  html.r57-ch #scrub-till .r57-shots img:nth-child(3) { --k0: 2; }
  html.r57-ch #scrub-till .r57-shots img:nth-child(4) { --k0: 3; }
  html.r57-ch #scrub-till .r57-shots img:nth-child(5) { --k0: 4; }
  /* the tablet faces you while it works; its glow is carried with it */
  html.r57-ch #scrub-till .scrub-stage .pad { --sry: 0deg !important; --srx: 0deg !important; }
  html.r57-ch #scrub-till .tk35-glow { display: none; }
  html.r57-ch #scrub-till .scrub-sticky, html.r57-ch #scrub-kitchen .scrub-sticky { overflow-x: clip; }
  /* inside the stage's own width: a glow wider than the phone made the page
     scroll sideways even under a clipping parent */
  html.r57-ch #scrub-till .r57-hold::before {
    content: ""; position: absolute; z-index: -1; left: 0; right: 0; top: -38%; bottom: -38%;
    border-radius: 50%; pointer-events: none;
    background: radial-gradient(closest-side, rgba(255,107,61,.46), rgba(255,122,72,.2) 55%, rgba(255,107,61,0));
  }

  /* ---- the kitchen: the delivery ticket ages, then Bump clears it -------- */
  html.r57-ch #scrub-kitchen .scrub-stage { --travel: 1.3; --hold-top: 5svh; --cap-y: 83svh; }
  html.r57-ch #scrub-kitchen .kds2-foot { display: none; }
  /* the display at 82 percent, so the caption line has room under it; zoom,
     on the display and not on the held frame, so the hold's own distance is
     never scaled */
  html.r57-ch #scrub-kitchen .scrub-frame > .kds2 { zoom: .82; }
  /* the stage is a flex row; the frame keeps its own height in the tall one */
  html.r57-ch #scrub-kitchen .scrub-stage { align-items: flex-start; }
  html.r57-ch #scrub-kitchen .scrub-frame.r57-hold { box-shadow: 0 0 0 24px var(--g-bg, #000), inset 0 0 0 1px rgba(0,0,0,.07); border-radius: var(--r-lg); }
  /* the stripe: the ticket's own red, drawn inside its edge so the green and
     amber can lie over it and fade */
  html.r57-ch #scrub-kitchen .tkt.age-3 { border-left-width: 1px; padding-left: 14px; box-shadow: inset 4px 0 0 var(--k-red); position: relative; }
  html.r57-ch #scrub-kitchen[data-beat="1"] .tkt.age-3 { box-shadow: inset 4px 0 0 var(--k-red), 0 0 0 1px rgba(52,195,143,.28), 0 10px 26px rgba(0,0,0,.4); }
  html.r57-ch #scrub-kitchen .r57-age { display: block; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; z-index: 1; pointer-events: none; }
  html.r57-ch #scrub-kitchen .r57-age-g { background: var(--k-green); opacity: clamp(0, (1 - var(--p) * 4) * 8 + .5, 1); }
  html.r57-ch #scrub-kitchen .r57-age-a { background: var(--k-amber); opacity: clamp(0, (2 - var(--p) * 4) * 8 + .5, 1); }
  html.r57-ch #scrub-kitchen .tkt.age-3 .ag { position: relative; }
  html.r57-ch #scrub-kitchen .r57-ag { display: block; position: absolute; right: 0; top: 0; white-space: nowrap; }
  html.r57-ch #scrub-kitchen .r57-ag-g { color: var(--k-green); opacity: clamp(0, (1 - var(--p) * 4) * 8 + .5, 1); }
  html.r57-ch #scrub-kitchen .r57-ag-a { color: var(--k-amber); opacity: min(clamp(0, (var(--p) * 4 - 1) * 8 + .5, 1), clamp(0, (2 - var(--p) * 4) * 8 + .5, 1)); }
  html.r57-ch #scrub-kitchen .r57-ag-r { opacity: clamp(0, (var(--p) * 4 - 2) * 8 + .5, 1); }

  /* ---- the dashboard: the screen fills the frame, then the board fans out */
  html.r57-ch .db34.r57-sec { --travel: 1.5; --hold-top: 14svh; --cap-y: 74svh; overflow-x: clip; }
  html.r57-ch .db34 .db34-list { display: none; }
  html.r57-ch .db34 .db34-scene {
    transform-origin: var(--zx, 50%) var(--zy, 30%);
    /* 1 to 1.55 over the first third, held, and back by 55 percent */
    --z: min(clamp(0, var(--p) / .32, 1), clamp(0, (.56 - var(--p)) / .14, 1));
    transform: scale(calc(1 + .55 * var(--z)));
  }
}
/* Round 58, items 2 and 3: what follows a held picture follows it closely.
   The section ends 24px under the picture's resting place (js/r57.js); the
   till's proof cards and the kitchen's pill start 16px after that (40px from
   the picture), the dashboard's cards one --sec-y from the tablet, the
   page's own section rhythm. */
@media (max-width: 900px) and (prefers-reduced-motion: no-preference) {
  html.r57-ch #scrub-till .scrub-sticky { row-gap: 16px; }
  html.r57-ch #scrub-till .tac-head { margin-bottom: 18px; }
  html.r57-ch #scrub-kitchen .scrub-sticky { padding-bottom: 0; }
  html.r57-ch #chapter-kitchen > .wrap > .chapter-pill { margin-top: 16px; }
  html.r57-ch #dashboard .dbento { margin-top: calc(var(--sec-y) - 28px); }
}
@keyframes r57p { from { --p: 0; } to { --p: 1.1628; } }
@keyframes r57hold { from { transform: translate3d(0, 0, 0); } to { transform: translate3d(0, var(--hold-d, 0px), 0); } }
@media (max-width: 900px) and (prefers-reduced-motion: no-preference) {
  /* ---- the pocket: the phone turns to face you as it arrives -------------- */
  html.r57-sd #pocket .pk34-pc { animation: r57turn linear both; animation-timeline: view(); animation-range: entry 0% cover 42%; transform-origin: 50% 60%; }
  html.r57-js #pocket .pk34-pc { transform: perspective(900px) rotateY(calc(-24deg * (1 - var(--pt, 1)))); transform-origin: 50% 60%; }
}
@keyframes r57turn {
  from { transform: perspective(900px) rotateY(-24deg) translate3d(0, 24px, 0); }
  to   { transform: perspective(900px) rotateY(0deg) translate3d(0, 0, 0); }
}
/* the pocket's count: the figure on a patch of its own tile. The two stops
   are the picture's own pixels (img/devices/flat/pocket-phone@3x.webp,
   sampled either side of the figure), not a design colour. */
.r57-count { display: none; }
@media (max-width: 900px) and (prefers-reduced-motion: no-preference) {
  .r57-count {
    display: block; position: absolute; z-index: 3; pointer-events: none; opacity: 0;
    background: linear-gradient(90deg, rgb(253, 114, 70), rgb(254, 112, 67));
    transition: opacity .14s linear;
  }
  .r57-count.is-on { opacity: 1; transition-duration: .08s; }
  .r57-count > span {
    position: absolute; white-space: nowrap; color: #000;
    font-family: var(--font-mono); font-weight: 700; font-variant-numeric: tabular-nums;
    letter-spacing: -.04em; line-height: 1.05;
  }
}

/* Round 57: at 320 the three service chips and the play button ran 27px past
   the phone's edge, and the page scrolled sideways (which also threw the held
   chapters' timelines off by the zoomed-out viewport). Under 361px they keep
   their first word. */
@media (max-width: 360px) { .sv57-long { display: none; } }
/* Round 57: at 320 the till's tablet sat at the clamp's .4 floor, 296px in a
   280px column, and ran past the edge; it takes the column's width there. And
   on a short phone the kitchen display is drawn smaller still, so the caption
   line keeps its room under the held frame. */
@media (max-width: 360px) { #scrub-till .scrub-sticky .pad-box { --s: tan(atan2(calc(100vw - 2 * var(--gutter)), 740px)); } }
@media (max-width: 900px) and (max-height: 740px) and (prefers-reduced-motion: no-preference) {
  html.r57-ch #scrub-kitchen .scrub-frame > .kds2 { zoom: .66; }
}
/* the held kitchen on a phone draws its display smaller, and under 361px it
   is one tight column: in both the two phone stickers land on each other, so
   the one about Bump stays (the amber caption has already said the other) */
@media (max-width: 360px) { .kc54-tag[data-for$=".ag"] { display: none; } }
@media (max-width: 900px) and (prefers-reduced-motion: no-preference) {
  html.r57-ch .kc54-tag[data-for$=".ag"] { display: none; }
}

/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  Round 58, item 1: the hero is the owner's phone                          ║
   ╚══════════════════════════════════════════════════════════════════════════╝
   On the owner's word the laptop and its film are gone. The hero's product
   is the pocket section's own phone (the same face and board markup, one
   component), large, with the live board on its screen, and it arrives in
   the pocket section's language: turned away and low, it turns and rises to
   rest (1.4s), the screen lights from dark glass at .9s with one glare, and
   the night's numbers count up (js/r57.js heroPhone). It is on screen from
   the first frame (transform only, no opacity), and still once it lands. As
   the hero scrolls away it recedes a little, on the hero's own view timeline
   (a scroll-written --h59x where there is none); nothing is pinned.
   The face carries no 3D shell: nothing in it is preserve-3d, so its live
   board never sits in the context Safari drops (Rounds 41 and 48).
     desktop (1024px and up)  copy left, the phone right at 78vh, whole
     under 1024px             the copy, then the phone at 72vw (380px at most)
   Reduced motion: the phone at rest with its numbers. */
.h59-stage { position: relative; z-index: 2; display: flex; justify-content: center; pointer-events: none; }
.h59-recede, .h59-arrive { transform-origin: 50% 62%; }
.ph-box.h59-ph { --s: .7; perspective: none; }
@supports (width: calc(100vw / 1px * 1px)) {
  .ph-box.h59-ph { --s: calc(min(72vw, 380px) / 393px); }
}
.phone.h59-face { --ry: 0deg; --rx: 0deg; }
.ph-view.h59-view { transition: none; }
.h59-dark {
  position: absolute; inset: 0; z-index: 6; display: block; pointer-events: none; opacity: 0;
  background: linear-gradient(122deg, rgba(255,255,255,.07) 0%, rgba(255,255,255,.015) 34%, rgba(255,255,255,0) 58%), #070708;
}
.h59-glare { position: absolute; inset: 0; z-index: 7; display: block; overflow: hidden; pointer-events: none; }
.h59-glare > i {
  position: absolute; top: -30%; bottom: -30%; left: 0; width: 46%; display: block; opacity: 0;
  background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.3) 50%, rgba(255,255,255,0));
  transform: translateX(-140%) skewX(-16deg);
}
/* the board keeps its desktop layout at every width (the Round 10 phone
   rules that stretch a single view to fill a close-up screen are for the
   pocket's own views, not this two-part board) */
@media (max-width: 900px) {
  .ph-view.h59-view { display: block; padding-bottom: 30px; }
  .ph-view.h59-view .ph-tiles { flex: none; grid-template-rows: none; gap: 10px; }
  .ph-view.h59-view .ph-tiles > .tile { display: block; }
  .ph-view.h59-view .ph-tiles > .tile > .fig { margin-top: 9px; }
  .ph-view.h59-view .ph-tiles > .tile > .bars { margin-top: 10px; height: 84px; }
  .ph-view.h59-view .ph-tiles > .tile > .spark { margin-top: 10px; height: 64px; }
  .ph-view.h59-view .ph-tiles > .tile > .rank { margin-top: 12px; }
}
/* under 1024px: the copy, then the phone */
@media (max-width: 1023px) {
  .hero13.h59 { height: auto; min-height: 0; padding-bottom: var(--sec-y); }
  .h59-stage { margin-top: clamp(28px, 5vw, 48px); }
}
@media (min-width: 901px) and (max-width: 1023px) {
  .hero13.h59 { min-height: 0; }
}
/* a short phone (the 667px-high SE class): less air over the eyebrow and
   under the fine print, so a third of the phone is still on the first
   screen (27 percent at 375x667 before, 33 after) */
@media (max-width: 700px) and (max-height: 700px) {
  .hero13.h59 { padding-top: calc(var(--nav-h) + 26px); }
  .h59-stage { margin-top: 18px; }
}
/* 1024px and up: two columns inside the fold at every size */
@media (min-width: 1024px) {
  .hero13.h59 {
    --h13-f: clamp(56px, min(5.9vw, 11.5vh), 150px);
    height: 100vh; min-height: 620px;
    /* the copy and the phone as one centred pair: each column as wide as
       what it holds, the headline on its own two lines at every size */
    /* the copy's column is sized from the type, not from the text in it,
       so the pair does not move when Inter replaces the fallback face: the
       headline's longer line is 5.95em of Inter, the lede 30em of its own */
    display: grid; justify-content: center; align-items: center; align-content: center;
    grid-template-columns: max(calc(clamp(16px, 1.1vw, 20px) * 30), calc(var(--h13-f) * 6.05)) auto;
    column-gap: clamp(56px, 7vw, 200px);
    padding: var(--nav-h) clamp(32px, 5vw, 120px) 0;
  }
  .h59 .h13-stack { align-items: flex-start; text-align: left; justify-self: stretch; width: auto; max-width: none; padding: 0 0 clamp(8px, 2vh, 24px); }
  .h59 .h13-head { white-space: nowrap; }
  .h59 .h13-eyebrow { margin-bottom: clamp(10px, 1.4vh, 16px); }
  .h59 .h13-sub { margin: clamp(14px, 2.2vh, 26px) 0 0; max-width: 30em; font-size: clamp(16px, 1.1vw, 20px); }
  .h59 .h13-ctas { margin-top: clamp(20px, 3.2vh, 40px); justify-content: flex-start; }
  .h59 .h13-fine { margin: clamp(10px, 1.6vh, 20px) 0 0; }
  .h59-stage { justify-self: start; }
  .ph-box.h59-ph { --s: .82; }
  @supports (width: calc(100vw / 1px * 1px)) {
    .ph-box.h59-ph { --s: calc(min(78vh, 44vw * 852 / 393) / 852px); }
  }
}
@media (prefers-reduced-motion: no-preference) {
  .h59-arrive { animation: h59in 1.4s cubic-bezier(.16, 1, .3, 1) 1.1s both; }
  /* the screen lights at .9s when js/r57.js is there to count the board up
     (it moves these two to that moment); without it they run at 2.2s, on
     the numbers as they stand */
  .h59-dark { opacity: 1; animation: h59lit .55s cubic-bezier(.4, 0, .2, 1) 3.2s both; }
  .h59-glare > i { animation: h59glare 1s cubic-bezier(.35, .1, .3, 1) 3.3s both; }
  .hero13.h59 { view-timeline: --h59 block; }
  @supports (animation-timeline: view()) {
    .h59-recede { animation: h59recede linear both; animation-timeline: --h59; animation-range: exit 0% exit 100%; }
  }
  html.h59-js .h59-recede { transform: perspective(1600px) rotateY(calc(6deg * var(--h59x, 0))) scale(calc(1 - .04 * var(--h59x, 0))); }
}
@keyframes h59in {
  from { transform: perspective(1600px) translate3d(0, 60px, 0) rotateX(6deg) rotateY(-28deg) scale(.92); }
  to   { transform: perspective(1600px) translate3d(0, 0, 0) rotateX(0deg) rotateY(0deg) scale(1); }
}
@keyframes h59lit { from { opacity: 1; } to { opacity: 0; } }
@keyframes h59glare {
  0%   { opacity: 0; transform: translateX(-140%) skewX(-16deg); }
  25%  { opacity: 1; }
  100% { opacity: 0; transform: translateX(320%) skewX(-16deg); }
}
@keyframes h59recede {
  from { transform: perspective(1600px) rotateY(0deg) scale(1); }
  to   { transform: perspective(1600px) rotateY(6deg) scale(.96); }
}

/* ---- Round 59: rolling lines anywhere ([data-roll]) ------------------------
   The pocket's giant line, generalised: a full-bleed band that clips, the
   line in the .pk34-giant style, travelling right to left with the scroll
   (js/scroll.js rolls()). Reduced motion: wrapped and still. */
.roll-band { overflow: clip; padding: clamp(40px, 10vh, 120px) 0; }
.roll-band .pk34-giant { margin: 0 auto; font-size: clamp(44px, 9vw, 140px); }
@media (prefers-reduced-motion: reduce) { .roll-band .pk34-giant { width: auto; white-space: normal; text-align: center; font-size: clamp(40px, 8vw, 120px); padding-inline: var(--gutter); } }

/* ===========================================================================
   Round 60: five desktop points.
   ======================================================================== */

/* ---- item 2: a scrubbed recording is a frame sequence on a canvas ---------
   js/seq.js draws the frame for the runway's progress; the first frame is an
   <img> under it, so the screen is never blank (before the script, before
   the frames, and for good under reduced motion or Save-Data). The canvas
   shows only once it has drawn. Home: inside the till's own tablet screen. */
.seq { position: absolute; inset: 0; overflow: hidden; background: #000; }
.seq-first, .seq-cv { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.seq-first { object-fit: cover; }
.seq-cv { opacity: 0; }
.seq.is-live .seq-cv { opacity: 1; }
@media (max-width: 900px) { #scrub-till .scrub-seq { display: none; } }

/* ---- item 4: the numbers as Apple's stats band ------------------------------
   1024 and up: the four in one row, a column each with a hairline between
   them, left-aligned in the column: the figure (88px at most), its unit under
   it, the caption under that; the section no taller than 70vh. 700 to 1023:
   two by two, the hairline between the two columns. Under 700: stacked and
   centred, as before. As a column enters (js/r57.js adds .is-in, columns
   140ms apart): its hairline draws down its left edge (400ms), the figure
   counts up (900ms from 250ms), the unit rises in as the count lands, one
   band of light crosses the figure (1.2s) and the caption rises with it.
   Reduced motion, and no script: the settled band. */
.nm54-stat { position: relative; }
.nm54-stat::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 1px; display: none;
  background: color-mix(in srgb, var(--ink) 16%, transparent); transform-origin: 50% 0;
}
@media (min-width: 700px) {
  .nm54 { padding-block: clamp(56px, 8vh, 96px); }
  .nm54-list { justify-items: stretch; text-align: left; }
  .nm54-stat { max-width: none; align-items: flex-start; padding: 6px 0 6px clamp(24px, 2.8vw, 44px); }
  .nm54-v { align-items: flex-start; font-size: clamp(72px, 7.6vw, 88px); }
  .nm54-n { text-align: left; }
  .nm54-stat p { margin: 14px 0 0; max-width: 26ch; text-wrap: pretty; }
}
@media (min-width: 700px) and (max-width: 1023px) {
  .nm54-list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(40px, 6vw, 56px) 0; }
  .nm54-stat:nth-child(odd) { padding-left: 0; }
  .nm54-stat:nth-child(even)::before { display: block; }
}
@media (min-width: 1024px) {
  .nm54 { max-height: 70vh; box-sizing: border-box; }
  .nm54-list { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0; }
  .nm54-stat:first-child { padding-left: 0; }
  .nm54-stat:not(:first-child)::before { display: block; }
}
@media (min-width: 700px) and (prefers-reduced-motion: no-preference) {
  .js .nm54-list.is-armed .nm54-stat::before { transform: scaleY(0); }
  .js .nm54-list.is-armed .nm54-stat.is-in::before { transform: none; transition: transform .4s cubic-bezier(.16, 1, .3, 1); }
  .js .nm54-stat.is-in .nm54-n { animation-delay: 1.15s; }
  .js .nm54-list.is-armed .nm54-stat.is-in .nm54-u { transition-delay: 1s, 1s; }
  .js .nm54-list.is-armed .nm54-stat.is-in > p { transition-delay: 1.15s, 1.15s; }
}

/* ---- item 5: the thinking orb (js/orbs.js) ---------------------------------
   Ask delEat's mark, beside its label: 64px, bone dots with orange accents
   on the tile's black. The label keeps its line; the orb sits to the right,
   its box pulled into the tile's padding so the tile does not grow. */
.db-ask-hd { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* Round 63: the orb is the card's visual, centred above the exchange, not an icon */
.db-orb { display: block; width: clamp(120px, 11vw, 168px); height: clamp(120px, 11vw, 168px); margin: 6px auto 10px; }

/* ==== Round 66: the hero, rebuilt from comp/hero-proto.html (Parth, 30 Sep) ===================
   The headline arrives like Jitter's intro (every letter flickers through styles, then lands);
   a cursor presses Ctrl, which becomes the delEat key; a desk display rises under it and, on
   desktop, morphs into the owner's phone as the page scrolls (Jeton), ending on the two-column
   layout. Phones: in flow, nothing pinned, the morph plays once on its own. js/hero66.js. */
section.hero13.hx { height: 220vh !important; min-height: 0 !important; padding: 0 !important;
  display: block !important; overflow: clip !important; background: #000;
  /* an older .hero13 rule centres content; block containers honour align-content now */
  align-content: normal !important; }
.hx-stage { position: sticky; top: 0; height: 100vh; overflow: clip; }
/* the glow and the dots fade to the next chapter's black, so no seam shows */
.hx-stage::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 26vh; z-index: 1; pointer-events: none;
  background: linear-gradient(to bottom, rgba(0,0,0,0), #000 92%); }
.hx-glow { position: absolute; inset: auto 0 -20vh 0; height: 90vh; pointer-events: none; z-index: 1;
  background: radial-gradient(60% 55% at 50% 60%, rgba(255,107,61,.34), rgba(255,107,61,.08) 45%, transparent 70%); }
.hx-copy { position: absolute; top: 14vh; left: 0; width: 100%; z-index: 3; }
.hx-eyebrow { font: 600 12px/1 var(--font-mono); letter-spacing: .14em; text-transform: uppercase; color: var(--o-400); margin: 0 0 22px; }
.hx-h { margin: 0; font-family: var(--font-display); font-weight: 800; letter-spacing: -.045em; line-height: .98;
  font-size: clamp(52px, 7.4vw, 118px); color: var(--bone); }
.hx-ln { display: block; white-space: nowrap; }
#hx-l2 { margin-top: .12em; }
.hx-ch { display: inline-block; text-align: center; }
.hx-ch.hx-g0 { font-weight: 200; font-style: italic; }
.hx-ch.hx-g1 { font-family: var(--font-mono); font-weight: 700; letter-spacing: -.02em; }
.hx-ch.hx-g2 { color: transparent; -webkit-text-stroke: 1.6px var(--bone); }
.hx-ch.hx-g3 { color: var(--o-500); font-weight: 900; }
.hx-ch.hx-g4 { background: var(--bone); color: #111; border-radius: .12em; }
.hx-ch.hx-g5 { font-weight: 100; }
/* the key is the word's own padded box, trimmed to the capitals, so the legend sits centred */
.hx-ctrl { position: relative; z-index: 0; isolation: isolate; display: inline-block; margin: 0 .06em 0 .04em;
  padding: .2em .24em; line-height: 1; letter-spacing: 0; text-box: trim-both cap alphabetic; }
@supports not (text-box: trim-both cap alphabetic) { .hx-ctrl { padding: .05em .24em .21em; } }
.hx-ctrl { --d: 1; }
.hx-ctrl::before { content: ""; position: absolute; inset: 0; border-radius: .24em; background: linear-gradient(180deg, #fbf8f3, #efe8dd);
  box-shadow: 0 calc(.09em * var(--d)) 0 #c9bfb2, 0 calc(.2em * var(--d)) calc(.5em * var(--d)) rgba(0,0,0,.45); z-index: -1; }
.hx-ctrl.keyed::before { opacity: 1; transform: none; transition: transform .38s cubic-bezier(.2,1.4,.3,1), opacity .2s; }
.hx-ctrl, .hx-ctrl.keyed .hx-ch { color: #141414; -webkit-text-fill-color: #141414; }
/* the rolling line's shade on the headline: white, silver, grey */
.hx-shade { background-image: linear-gradient(180deg, #FFFFFF 0%, var(--hl-1, #E5E5EA) 55%, var(--hl-2, #8E8E93) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent; -webkit-text-fill-color: transparent; padding-bottom: .06em; }
.hx-ctrl.press { transform: translateY(.06em); transition: transform .08s; }
.hx-ctrl.press::before { box-shadow: 0 .03em 0 #c9bfb2, 0 .08em .2em rgba(0,0,0,.4); }
.hx-dot { font-style: normal; color: var(--o-500); display: inline-block; transform: scale(0); }
.hx-sub { position: absolute; top: 0; left: 0; width: 100%; }
.hx-lede { margin: 26px 0 0; font-size: clamp(16px, 1.3vw, 19px); line-height: 1.5; color: #bdb4aa; max-width: 36ch; }
.hx-cta { margin-top: 26px; display: flex; gap: 14px; align-items: center; }
.hx-fine { margin: 18px 0 0; font-size: 13px; color: #8f867c; }
.hx-fine a { color: var(--o-400); }
.hx-cur { position: absolute; z-index: 5; left: 0; top: 0; pointer-events: none; opacity: 0; }
.hx-cur b { display: inline-block; margin: 14px 0 0 12px; background: var(--o-500); color: #111; font: 600 12px/1 var(--font-display); padding: 5px 9px; border-radius: 999px; }
.hx-scr { position: absolute; z-index: 2; left: 0; top: 0; transform-origin: 0 0; opacity: 0; }
.hx-bez { position: relative; width: 100%; height: 100%; padding: var(--bz, 10px); border-radius: var(--rad, 22px);
  background: linear-gradient(180deg, #2a2a2d, #0a0a0b 60%, #000); box-shadow: inset 0 0 0 1px rgba(255,255,255,.1), 0 50px 90px -30px rgba(0,0,0,.8); }
.hx-glass { position: relative; width: 100%; height: 100%; border-radius: calc(var(--rad, 22px) - var(--bz, 10px)); overflow: hidden;
  background: #f6f1ea; color: #141414; font-family: var(--font-display); text-align: left; }
.hx-island { position: absolute; z-index: 4; left: 50%; top: 10px; width: 96px; height: 28px; margin-left: -48px; border-radius: 20px; background: #000; opacity: var(--pi, 0); }
.hx-stat { position: absolute; top: 14px; left: 22px; right: 22px; display: flex; justify-content: space-between; font: 600 13px/1 var(--font-display); opacity: var(--pi, 0); }
.hx-side { position: absolute; left: 0; top: 0; bottom: 0; width: 190px; background: #fff; border-right: 1px solid #eee; padding: 22px 18px; font-size: 13px; }
.hx-side i { display: block; font-style: normal; padding: 8px 10px; border-radius: 8px; color: #555; }
.hx-side i.on { background: #ffe9df; color: #a13d20; font-weight: 600; }
.hx-side .hx-lg { font-weight: 800; font-size: 17px; margin: 0 0 16px 10px; color: #111; }
.hx-hd { position: absolute; }
.hx-hd b { display: block; font-weight: 800; letter-spacing: -.02em; }
.hx-hd small { display: block; color: #777; font-size: 12px; margin-top: 4px; }
.hx-hd small::before { content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: #3fb07f; margin-right: 6px; }
.hx-t { position: absolute; border-radius: 18px; padding: 14px 16px; overflow: hidden; display: flex; flex-direction: column; justify-content: space-between; }
.hx-t h5 { margin: 0; font: 500 12px/1.2 var(--font-display); opacity: .8; }
.hx-fig { font-family: var(--font-mono); font-weight: 700; letter-spacing: -.03em; line-height: 1; }
.hx-t1 { background: var(--o-500); color: #111; }
.hx-t2 { background: #127a6b; color: #fff; }
.hx-t3, .hx-t4, .hx-t5 { background: #fff; }
.hx-t6, .hx-t7 { background: #151515; color: #eee; }
.hx-bars { display: flex; align-items: flex-end; gap: 5px; height: 60%; }
.hx-bars span { flex: 1; background: var(--o-500); border-radius: 4px 4px 2px 2px; }
.hx-row { display: flex; justify-content: space-between; font-size: 12.5px; padding: 6px 8px; border-radius: 8px; margin-top: 5px; background: #fff3ec; }
.hx-row b { font-family: var(--font-mono); }
@media (max-width: 700px) {
  section.hero13.hx { height: auto !important; }
  .hx-stage { position: relative; height: auto; min-height: 100vh; padding-bottom: 40px; }
  .hx-copy { position: relative; top: auto; padding: calc(var(--nav-h, 64px) + 28px) 20px 0; }
  .hx-sub { position: static; }
}

/* ==== Round 67: the keyboard footer on the home page (Parth, 30 Sep). comp/keyboard-proto.html,
   scoped to #kbf; js/keyboard67.js. ==== */
#kbf { position: relative; }
#kbf { position: relative; padding: 80px 16px 90px; overflow: clip;
  background: radial-gradient(60% 80% at 50% 62%, rgba(255,107,61,.26), rgba(255,107,61,.06) 45%, transparent 72%), #000; }
#kbf .kx-kf-head { text-align: center; margin: 0; font: 800 clamp(30px, 4vw, 52px)/1 var(--font-display); letter-spacing: -.04em; }
#kbf .kx-kf-head span { color: var(--o-500); }
#kbf .kx-line { margin: 34px auto 0; width: min(560px, 100%); height: 54px; border-radius: 27px; display: flex; align-items: center; gap: 12px; padding: 0 22px;
  background: rgba(247,243,238,.06); box-shadow: inset 0 0 0 1px rgba(247,243,238,.14); font: 500 17px/1 var(--font-display); color: var(--bone); }
#kbf .kx-line .kx-typed { white-space: pre; }
#kbf .kx-line .kx-caret { width: 2px; height: 22px; background: var(--o-500); margin-left: -10px; animation: kbf-blink 1s steps(1) infinite; }
#kbf .kx-line .kx-ph { color: #7d756c; }
#kbf .kx-line .kx-go { margin-left: auto; font: 600 12px/1 var(--font-mono); color: var(--o-400); letter-spacing: .04em; opacity: 0; transition: opacity .2s; }
#kbf .kx-line .kx-go.kx-on { opacity: 1; }
@keyframes kbf-blink { 50% { opacity: 0; } }
#kbf .kx-chips { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin: 14px auto 0; font: 500 12px/1 var(--font-mono); color: #8e857b; }
#kbf .kx-chips b { color: var(--bone); font-weight: 600; }
#kbf .kx-stage { position: relative; height: 560px; margin-top: 0; perspective: 1500px; perspective-origin: 50% 20%; display: grid; place-items: center; }
#kbf .kx-tilt { position: absolute; left: 50%; top: 50%; transform-style: preserve-3d; will-change: transform;
  transform: translate(-50%, -50%) rotateX(var(--rx, 42deg)) rotateZ(var(--rz, -6deg)); }
#kbf .kx-kbd { --u: 46px; --g: 6px; position: relative; transform-style: preserve-3d; padding: 16px 16px 18px; border-radius: 16px;
  transform: scale(var(--k, 1.18));
  background: linear-gradient(180deg, #3b3b3f 0%, #27272b 55%, #1d1d20 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.16), inset 0 -1px 0 rgba(0,0,0,.4); }
#kbf .kx-kbd::before { content: ""; position: absolute; left: 6px; right: 6px; bottom: 0; height: 13px; transform-origin: 50% 100%;
  transform: rotateX(-90deg); border-radius: 0 0 10px 10px; background: linear-gradient(180deg, #2c2c30, #0e0e10); height: 16px; }
#kbf .kx-shadow { position: absolute; left: 4%; right: 4%; top: 18%; bottom: -14%; transform: translateZ(-14px); border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255,107,61,.34), rgba(255,107,61,.08) 60%, rgba(0,0,0,0)); filter: blur(22px); }
#kbf .kx-row { display: flex; gap: var(--g); margin-top: var(--g); }
#kbf .kx-row:first-child { margin-top: 0; }
#kbf .kx-key { --w: 1; position: relative; width: calc(var(--u) * var(--w) + var(--g) * (var(--w) - 1)); height: var(--u); flex: none;
  border: 0; padding: 0; background: none; cursor: pointer; transform-style: preserve-3d; -webkit-tap-highlight-color: transparent; }
#kbf .kx-row.kx-fn .kx-key { height: calc(var(--u) * .56); }
#kbf .kx-key .kx-top { position: absolute; inset: 0; border-radius: 7px; display: flex; align-items: center; justify-content: center; flex-direction: column;
  background: linear-gradient(180deg, #fcf9f4 0%, #f5f0e8 60%, #e9e1d5 100%);
  box-shadow: 0 3.5px 0 #b9ab96, 0 4px 1px rgba(0,0,0,.2), 0 7px 9px rgba(0,0,0,.18), inset 0 -1px 0 rgba(0,0,0,.05);
  transform: translateZ(3.5px); transition: transform .08s cubic-bezier(.3,.7,.4,1), box-shadow .08s;
  color: #1d1b19; font: 500 13px/1 var(--font-display); }
#kbf .kx-key .kx-top .kx-s { font-size: 10px; margin-bottom: 4px; color: #6b645c; }
#kbf .kx-key.kx-mod .kx-top { align-items: flex-start; justify-content: space-between; padding: 7px 8px 6px; font-size: 9.5px; font-weight: 500; color: #3a3530; }
#kbf .kx-key.kx-mod .kx-top .kx-sym { align-self: flex-end; font-size: 12px; color: #3a3530; }
#kbf .kx-key.kx-mod.kx-left .kx-top { align-items: flex-start; }
#kbf .kx-row.kx-fn .kx-top { font-size: 9px; color: #7a7268; }
#kbf .kx-key.kx-down .kx-top, #kbf .kx-key:active .kx-top { transform: translateZ(.5px) translateY(1.5px);
  box-shadow: 0 .8px 0 #b9ab96, 0 1px 1px rgba(0,0,0,.18), 0 2px 3px rgba(0,0,0,.12), inset 0 -1px 0 rgba(0,0,0,.05); }
#kbf .kx-key:focus-visible .kx-top { outline: 2px solid var(--o-500); outline-offset: 2px; }
#kbf .kx-key.kx-cmd .kx-top::before { content: ""; position: absolute; top: 7px; left: 7px; width: 5px; height: 5px; border-radius: 50%;
  background: var(--o-500); box-shadow: 0 0 6px rgba(255,107,61,.9); }
#kbf .kx-key.kx-tid .kx-top { background: radial-gradient(circle, #2b2b2e 0 38%, #121214 40% 44%, #3a3a3e 46%); }
#kbf .kx-arrows { display: grid; grid-template-columns: repeat(3, var(--u)); grid-template-rows: calc(var(--u) / 2 - 1px) calc(var(--u) / 2 - 1px); column-gap: var(--g); row-gap: 2px; }
#kbf .kx-arrows .kx-key { width: auto; height: auto; }
#kbf .kx-arrows .kx-k-left { grid-column: 1; grid-row: 2; }
#kbf .kx-arrows .kx-k-up { grid-column: 2; grid-row: 1; }
#kbf .kx-arrows .kx-k-down { grid-column: 2; grid-row: 2; }
#kbf .kx-arrows .kx-k-right { grid-column: 3; grid-row: 2; }
#kbf .kx-arrows .kx-top { font-size: 9px; }
#kbf .kx-key.kx-deleat .kx-top { flex-direction: row; font: 500 15px/1 var(--font-display); letter-spacing: -.02em; color: #1d1b19; }
#kbf .kx-key.kx-deleat .kx-top b { font-weight: 800; color: var(--o-500); }
#kbf .kx-hint { text-align: center; margin: 6px 0 0; font: 500 12px/1.6 var(--font-mono); color: #6d665f; }
@media (max-width: 860px) {#kbf .kx-stage { height: 320px; perspective: 1100px; }
#kbf .kx-line { font-size: 15px; height: 48px; }

}
@media (prefers-reduced-motion: reduce) {#kbf .kx-line .kx-caret { animation: none; }
#kbf .kx-key .kx-top { transition: none; }
 }

@media (max-width: 860px) { #kbf .kx-tilt { --rx: 30deg !important; --rz: 0deg !important; } }

/* ==== Round 68: the ember shader behind the keyboard section (js/shader68.js) ==== */
#kbf .kbf-shader { position: absolute; inset: 0; width: 100%; height: 100%; display: block; z-index: 0; opacity: .9; }
#kbf > :not(.kbf-shader) { position: relative; z-index: 1; }

/* Round 69: nothing of the headline shows before its glide starts (no left-aligned flash) */
@media (prefers-reduced-motion: no-preference) {
  html.js .hero13.hx:not(.hx-static) .hx-ln, html.js .hero13.hx:not(.hx-static) #hx-eb, html.js .hero13.hx:not(.hx-static) #hx-sub { opacity: 0; }
}

/* ---- Round 73: the dust on the final band (js/dust.js) ----------------------
   The canvas is the section, in flow, under the words; while it runs, the
   orange web field and the drawn rings stand down, because the dust is the
   rings now. */
.uc35 > .uc-dust { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; display: block; }
.uc35.has-dust > .sec-web, .uc35.has-dust > .uc35-rings { display: none; }
/* the lines under the capsule keep a soft dark halo so a ring passing behind never takes them */
.uc35.dust-live .st34-sub, .uc35.dust-live .uc35-cta { position: relative; text-shadow: 0 0 14px #000, 0 0 4px #000; }
.uc35.dust-live .uc35-cta .btn { filter: drop-shadow(0 0 22px rgba(0,0,0,.9)); }   /* keeps the keycap edge */

/* ---- Round 73b: the local nav is the same Liquid Glass as the pill ----------
   css/site.css Round 71 is the recipe and the reasoning (Apple's regular
   variant: 6-9px with a light dimming, a specular rim and sheen, labels that
   follow the ground, the orange CTA the one tinted piece). js/site.js marks
   .over-dark from the ground under the bar's bottom edge and draws its own
   refraction map for the 28px corners (#lg-refract-ln, Chromium only). Off
   where touch devices up to 1020px have the in-flow bar, and while the phone
   sheet is open. */
@media (min-width: 1021px), not all and (any-pointer: coarse) {
  html .local-nav:not(.is-menu) .local-nav-in {
    isolation: isolate; border: 0;
    background:
      linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,.02) 46%, rgba(255,255,255,.05)),
      rgba(12,12,12,.46);
    -webkit-backdrop-filter: blur(11px) saturate(1.7) brightness(.78);
            backdrop-filter: blur(11px) saturate(1.7) brightness(.78);
    box-shadow:
      inset 0 1px 1px rgba(255,255,255,.55), inset 0 -1px 1px rgba(255,255,255,.16),
      inset 0 0 22px rgba(255,255,255,.07), 0 10px 30px -12px rgba(0,0,0,.50), 0 1px 2px rgba(0,0,0,.18);
  }
  html .local-nav.lg-refract:not(.is-menu) .local-nav-in {
    -webkit-backdrop-filter: url(#lg-refract-ln) blur(11px) saturate(1.7) brightness(.78);
            backdrop-filter: url(#lg-refract-ln) blur(11px) saturate(1.7) brightness(.78);
  }
  html .local-nav:not(.is-menu) .local-nav-in::before {
    content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; padding: 1px; pointer-events: none;
    background: linear-gradient(115deg,
      rgba(255,255,255,.85) 0%, rgba(255,255,255,.22) 14%, rgba(255,255,255,0) 32%,
      rgba(255,255,255,0) 68%, rgba(255,255,255,.22) 86%, rgba(255,255,255,.65) 100%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor; mask-composite: exclude;
  }
  html .local-nav:not(.is-menu) .local-nav-in::after {
    content: ""; position: absolute; inset: 1px 18px auto; height: 45%; z-index: -1; pointer-events: none;
    border-radius: var(--r-6) var(--r-6) 40% 40% / var(--r-6) var(--r-6) 100% 100%;
    background: linear-gradient(180deg, rgba(255,255,255,.16), rgba(255,255,255,0));
  }
  html .local-nav.over-dark:not(.is-menu) .ln-links a, html .local-nav.over-dark:not(.is-menu) .ln-more { color: rgba(247,243,238,.78); }
  html .local-nav.over-dark:not(.is-menu) .ln-links a:hover,
  html .local-nav.over-dark:not(.is-menu) .ln-links a.is-current { color: #FFFFFF; }

  html .local-nav:not(.over-dark):not(.is-menu) .local-nav-in {
    background: linear-gradient(180deg, rgba(255,255,255,.50), rgba(255,255,255,.22) 50%, rgba(255,255,255,.34));
    -webkit-backdrop-filter: blur(6px) saturate(1.8) brightness(1.06);
            backdrop-filter: blur(6px) saturate(1.8) brightness(1.06);
    box-shadow:
      inset 0 1px 1px rgba(255,255,255,.95), inset 0 -1px 1px rgba(255,255,255,.5),
      inset 0 0 0 .5px rgba(0,0,0,.06), 0 10px 30px -14px rgba(0,0,0,.28), 0 1px 2px rgba(0,0,0,.08);
  }
  html .local-nav.lg-refract:not(.over-dark):not(.is-menu) .local-nav-in {
    -webkit-backdrop-filter: url(#lg-refract-ln) blur(6px) saturate(1.8) brightness(1.06);
            backdrop-filter: url(#lg-refract-ln) blur(6px) saturate(1.8) brightness(1.06);
  }
  html .local-nav:not(.over-dark):not(.is-menu) .ln-links a, html .local-nav:not(.over-dark):not(.is-menu) .ln-more { color: var(--n-700); }
  html .local-nav:not(.over-dark):not(.is-menu) .ln-links a:hover,
  html .local-nav:not(.over-dark):not(.is-menu) .ln-links a.is-current { color: var(--n-900); }
  html .local-nav:not(.is-menu) .ln-cta.btn {
    box-shadow: inset 0 1px 0 rgba(255,255,255,.45), inset 0 -1px 0 rgba(0,0,0,.12), 0 6px 16px -8px rgba(255,107,61,.9);
  }
}
@media (min-width: 1021px) and (prefers-reduced-transparency: reduce), (min-width: 1021px) and (prefers-contrast: more),
       (pointer: fine) and (prefers-reduced-transparency: reduce), (pointer: fine) and (prefers-contrast: more) {
  html .local-nav:not(.is-menu) .local-nav-in, html .local-nav:not(.over-dark):not(.is-menu) .local-nav-in {
    background: var(--n-0); -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  html .local-nav:not(.is-menu) .local-nav-in::before, html .local-nav:not(.is-menu) .local-nav-in::after { display: none; }
  html .local-nav.over-dark:not(.is-menu) .ln-links a, html .local-nav.over-dark:not(.is-menu) .ln-more { color: var(--n-700); }
}

/* ---- Round 76: the phone pass (Parth, 8 Oct, from his iPhone) -------------- */
/* 3. the due list's rows had their words almost on the row's edge */
.bxa-due i { padding: 8px 12px; }
@media (max-width: 700px) {
  /* 2. the highlights cards: one idea each. A card that has a hairline figure
     keeps its eyebrow, the figure, the headline and the footer line; the
     corner orb and the card's own illustration go. The rail no longer forces
     every card to 4:5, so a card is as tall as what it holds. */
  /* Round 77 ("card is too empty"): the card keeps what it says (the four
     reasons, the cost stack, the transports, the due list) and drops only
     the corner orb and the decoration (the printer glyph, the stock line) */
  .bento-wall.phb .bx.has-fig .bx-orb, .bento-wall.phb .bx.has-fig .bxt-print, .bento-wall.phb .bx.has-fig .bxa-line { display: none; }
  .bento-wall.phb .bx, .bento-wall.phb .bx.w2, .bento-wall.phb .bx.tall { min-height: min(calc(84vw * .92), 380px); }
  .bento-wall.phb .bx.has-fig .copy > h3 { margin-bottom: 0; }
  .bento-wall.phb .bx.has-fig .bx-foot { margin-top: auto; padding-top: 14px; }
  /* 4. the Till and Kitchen chapter cards: a swipeable rail, not a tall stack */
  .mini-bento { display: flex; grid-template-columns: none; gap: 10px; overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none; width: 100vw; margin-inline: calc(50% - 50vw); padding: 2px var(--gutter) 8px; scroll-padding-inline: var(--gutter); }
  .mini-bento::-webkit-scrollbar { display: none; }
  .mini-bento .mini-card, .mini-bento .mini-card:last-child:nth-child(odd) { flex: 0 0 68vw; scroll-snap-align: start; grid-column: auto; padding: 14px 16px 16px; }
  .mini-card b { font-size: 16px; }
  .mini-card small { font-size: 13px; }
  /* 6. the till card: 4:5 left the order's total below the card's edge */
  .sv54-card { aspect-ratio: 3 / 4; }
  .sv54-olines { min-height: 56px; }
  /* 8. the numbers: two by two, not four screens of one number each */
  .nm54 { padding-block: 56px; }
  .nm54-list { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 14px; }
  .nm54-v { font-size: clamp(52px, 15vw, 64px); }
  .nm54-u { margin-top: 4px; }
  .nm54-stat p { margin-top: 8px; font-size: 13px; line-height: 1.4; }
}
/* 5. the Ask glow on a touch screen: inside its section, both sides only,
   fading out before the section's top and bottom (js/site.js siriGlow) */
.has-siri { position: relative; overflow: clip; }
.siri-glow.in-sec {
  position: absolute; inset: 0; height: auto; top: 0; bottom: 0; z-index: 0;
  -webkit-mask-image: linear-gradient(to right, #000 0, transparent 7%, transparent 93%, #000 100%), linear-gradient(to bottom, transparent 0, #000 18%, #000 82%, transparent 100%);
          mask-image: linear-gradient(to right, #000 0, transparent 7%, transparent 93%, #000 100%), linear-gradient(to bottom, transparent 0, #000 18%, #000 82%, transparent 100%);
  -webkit-mask-composite: source-in; mask-composite: intersect;
}

/* ---- Round 77: charcoal cards on the phone's dark ground (Parth, 8 Oct:
   "replace the white cards with the charcoal background"). The phone site is
   one dark ground, so the white plate and paper cards of the highlights rail
   and the chapters' small cards take the night surface (#1D1D1F, the bento
   night tile) with night inks; their figures read the card and switch to the
   night lines (js/figures.js). Desktop keeps its white cards on eggshell. */
@media (max-width: 700px) {
  /* Round 78 (Parth: "the charcoal we need is the one in the bento box
     sections"): the dashboard tile's own surface (.db: #161618, a 14% white
     hairline, a 6% top catch and a soft drop), now on every card of the
     highlights rail, the multi-outlet card included, and the chapters' cards */
  .bento-wall.phb .bx.plate, .bento-wall.phb .bx.paper, .bento-wall.phb .bx.masala, .bento-wall.phb .bx.ink, .mini-card {
    --ink: var(--bone); --ink-2: #A1A1A6; --ink-3: #8E8E93; --line: rgba(255,255,255,.12); --accent-text: #FF8A5B;
    background: #161618; border: 1px solid rgba(255,255,255,.14); color: var(--bone);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.06), 0 12px 40px rgba(0,0,0,.45);
  }
  .bento-wall.phb .bx.masala::before, .bento-wall.phb .bx.masala::after, .bento-wall.phb .bx.ink::after { opacity: 0; }
  .bento-wall.phb .bx.plate::before, .bento-wall.phb .bx.paper::before { box-shadow: none; }
  .bento-wall.phb .bx.plate::after, .bento-wall.phb .bx.paper::after { opacity: 0; }
  .bento-wall.phb .bxa-chips i, .bento-wall.phb .bxt-chips i { background: rgba(255,255,255,.08); color: var(--bone); }
  .bento-wall.phb .bxa-due i { background: rgba(255,255,255,.06); }
  .bento-wall.phb .bx-rows div { border-color: rgba(255,255,255,.1); }
  .mini-card b { color: var(--bone); }
  .mini-card small { color: #A1A1A6; }
}
@media (max-width: 700px) {
  /* the orange eyebrow chip, on charcoal: a faint orange wash, orange words */
  .bento-wall.phb .bx.plate .kicker.tchip, .bento-wall.phb .bx.paper .kicker.tchip { background: rgba(255,107,61,.14); color: #FF8A5B; }
  .bento-wall.phb .bx.plate .kicker, .bento-wall.phb .bx.paper .kicker { color: #A1A1A6; }
}
@media (max-width: 700px) {
  /* the due list's dates in a lighter orange that holds on charcoal */
  .bento-wall.phb .bx.plate .bxa-due em { color: #FF8A5B; }
  .bento-wall.phb .bx.plate .bxa-due i { padding: 9px 12px; }
}


/* ---- Round 78c (Parth, 8 Oct: "why are the edges getting cut off ... why
   isn't it edge to edge"): on phones the dashboard tour zoomed the board 1.55x
   toward the net sales tile, which pushed both sides off the screen. The zoom
   is gone (the caption and the count-up stay), and the board runs edge to
   edge, an 8px margin a side, so the whole screen shows and shows larger. */
@media (max-width: 900px) {
  html.r57-ch .db34 .db34-scene { transform: none; }
  #dashboard .db34-tilt { width: calc(100vw - 16px); max-width: none; margin-inline: calc(50% - 50vw + 8px); }
  #dashboard .db34-card { border-width: 3px; padding: 5px; border-radius: 18px; }
}

/* ---- Round 79 (Parth, 8 Oct, on desktop: "why do the animating orbs still
   show up on the bento box cards ... even the printing card has the icon, I
   had asked you to remove it"): what Round 77 did on phones, everywhere. The
   highlights cards carry no corner orb at any width, and a card with a
   hairline figure drops its own small drawing (the printer glyph, the stock
   line): one figure, the words, the facts. */
.bento-wall .bx .bx-orb { display: none; }
.bento-wall .bx.has-fig .bxt-print, .bento-wall .bx.has-fig .bxa-line { display: none; }

/* Round 79: a pinned roll band (js/scroll.js __rollLine). The band is as tall
   as the crossing; its inner box sticks at the screen's centre and carries
   the padding the band used to have. */
.roll-band.is-pinroll { padding: 0; overflow: visible; }
.roll-band.is-pinroll .roll-sticky { position: sticky; overflow: clip; padding: clamp(28px, 6vh, 72px) 0; }

/* ---- Round 80: "Not just the till. Everything around it." (#jobs) ---------
   The everyday jobs as one bento, straight after the hero: charcoal cards in
   the dashboard tile's own surface, a hairline figure each (js/figures.js),
   the problem in a line and the answer in another. */
.jobs .section-head { text-align: left; }
.jobs-grid { display: grid; gap: 12px; grid-template-columns: repeat(4, minmax(0, 1fr)); margin-top: var(--bento-top, 40px); }
.job { position: relative; display: flex; flex-direction: column; min-width: 0; padding: 18px 20px 20px; border-radius: 24px; text-decoration: none;
  background: #161618; border: 1px solid rgba(255,255,255,.14); color: var(--bone, #F7F3EE);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06), 0 12px 40px rgba(0,0,0,.45);
  transition: transform .3s cubic-bezier(.2,.8,.2,1), border-color .3s; }
.job.w2 { grid-column: span 2; }
@media (hover: hover) and (pointer: fine) { .job:hover { transform: translateY(-2px); border-color: rgba(255,255,255,.22); } }
.job-fig { display: block; width: 132px; margin: -6px 0 6px -10px; }
.job.w2 .job-fig { width: 170px; }
.job-k { font: 600 11px/1 var(--font-mono, ui-monospace, monospace); letter-spacing: .12em; text-transform: uppercase; color: #FF8A5B; }
.job b { display: block; margin-top: 10px; font-size: 19px; line-height: 1.2; font-weight: 600; letter-spacing: -.015em; }
.job.w2 b { font-size: 24px; }
.job-l { display: block; margin-top: 8px; font-size: 14px; line-height: 1.45; color: #A1A1A6; }
.job [data-hlf], .job [data-hairline-figure] { max-width: none; margin: 0; }
@media (max-width: 1000px) { .jobs-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) {
  .jobs-grid { gap: 10px; }
  .job { padding: 14px 14px 16px; border-radius: 20px; }
  .job-fig { width: 96px; margin: -8px 0 2px -8px; }
  .job.w2 .job-fig { width: 120px; }
  .job b { font-size: 16px; margin-top: 8px; }
  .job.w2 b { font-size: 19px; }
  .job-l { font-size: 12.5px; }
  .job-k { font-size: 10px; letter-spacing: .1em; }
}
/* the wide cards: words on the left, the figure on the right */
@media (min-width: 621px) {
  .job.w2 { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-rows: 1fr auto auto auto; column-gap: 20px; }
  .job.w2 .job-fig { grid-column: 2; grid-row: 1 / span 4; align-self: center; width: 220px; margin: 0 -6px 0 0; }
  .job.w2 .job-k { grid-row: 2; align-self: end; }
  .job.w2 b { grid-row: 3; } .job.w2 .job-l { grid-row: 4; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Round 81: "What's new", Apple's Get to know rail. The cards, paddles and
   More + sheet are the .rl34 rail's; this block is only the section and the
   six working models inside the cards (js/wn.js runs them while on screen;
   reduced motion shows each one settled). The till screens swap with no
   fade on purpose: the card is about screens that open at once.
   ═══════════════════════════════════════════════════════════════════════ */
.wn81 { overflow-x: clip; }
.wn81-rl { margin-top: var(--s-6); }
.wn-card .rl34-art { display: flex; flex-direction: column; gap: 10px; }
.wn-card .rl34-art { bottom: 50%; }
@media (max-width: 900px) { .wn-card .rl34-art { bottom: 47%; } }
.wn-card .rl34-l { max-width: 24ch; }

/* 1. instant till screens */
.wn-seg { position: relative; flex: none; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); height: 30px; padding: 3px;
  border-radius: 999px; background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.10); }
.wn-seg span { position: relative; z-index: 1; display: grid; place-items: center; font: 600 11px/1 var(--font-ui); color: var(--nt-ink-2); transition: color .2s ease; }
.wn-seg span.on { color: #000; }
.wn-thumb { position: absolute; top: 3px; bottom: 3px; left: 3px; width: calc((100% - 6px) / 5); border-radius: 999px; background: #F7F3EE;
  transform: translateX(calc(var(--s, 0) * 100%)); transition: transform .42s cubic-bezier(.3, 1.3, .5, 1); }
.wn-scr { position: relative; flex: 1; min-height: 0; border-radius: 12px; background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08); overflow: hidden; }
.wn-v { position: absolute; inset: 10px; display: none; gap: 6px; }
.wn-v.on { display: grid; }
.wn-v0 { grid-template-columns: repeat(3, minmax(0, 1fr)) 34%; grid-auto-rows: 1fr; }
.wn-v0 i { border-radius: 7px; background: rgba(255,255,255,.09); }
.wn-v0 i:nth-child(2) { background: rgba(255,107,61,.55); }
.wn-v0 b { grid-column: 4; grid-row: 1 / span 3; border-radius: 7px; background: rgba(255,255,255,.05);
  background-image: repeating-linear-gradient(180deg, transparent 0 9px, rgba(255,255,255,.14) 9px 13px); background-size: 70% 100%; background-repeat: no-repeat; background-position: 8px 8px; }
.wn-v1 { grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-rows: 1fr 1fr; place-items: center; }
.wn-v1 i { width: min(70%, 38px); aspect-ratio: 1; border-radius: 50%; border: 1.5px solid rgba(255,255,255,.22); }
.wn-v1 i:nth-child(3n) { border-radius: 8px; }
.wn-v1 i.on { border-color: #FF6B3D; background: rgba(255,107,61,.22); }
.wn-v2 { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: start; }
.wn-v2 p { margin: 0; display: flex; flex-direction: column; gap: 6px; padding: 9px 8px; border-radius: 8px; background: rgba(255,255,255,.07); border-top: 3px solid #F7F3EE; }
.wn-v2 p.late { border-top-color: #FF6B3D; }
.wn-v2 i { height: 4px; border-radius: 2px; background: rgba(255,255,255,.24); }
.wn-v2 i:nth-child(even) { width: 64%; }
.wn-v3 { grid-template-rows: repeat(4, minmax(0, 1fr)); }
.wn-v3 i { position: relative; border-radius: 7px; background: rgba(255,255,255,.07); }
.wn-v3 i::before, .wn-v3 i::after { content: ""; position: absolute; top: 50%; height: 5px; margin-top: -2.5px; border-radius: 3px; }
.wn-v3 i::before { left: 10px; width: 30%; background: rgba(255,255,255,.26); }
.wn-v3 i::after { right: 10px; width: 16%; background: rgba(255,255,255,.5); }
.wn-v4 { grid-template-rows: repeat(4, minmax(0, 1fr)); }
.wn-v4 i { position: relative; border-radius: 7px; background: rgba(255,255,255,.06); overflow: hidden; }
.wn-v4 i::after { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: var(--w); background: rgba(255,107,61,.34); }

/* 2. Live and Analyse */
.wn-sw { position: relative; flex: none; display: grid; grid-template-columns: 1fr 1fr; width: 158px; height: 32px; padding: 3px;
  border-radius: 999px; background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.12); }
.wn-sw span { position: relative; z-index: 1; display: grid; place-items: center; font: 600 12px/1 var(--font-ui); color: #FFFFFF; }
.wn-glass { position: absolute; top: 3px; bottom: 3px; left: 3px; width: calc(50% - 3px); border-radius: 999px;
  background: linear-gradient(180deg, rgba(255,255,255,.30), rgba(255,255,255,.09));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.55), inset 0 -1px 0 rgba(255,255,255,.10), 0 4px 14px rgba(0,0,0,.35);
  -webkit-backdrop-filter: blur(6px) saturate(1.6); backdrop-filter: blur(6px) saturate(1.6);
  transition: transform .55s cubic-bezier(.3, 1.35, .45, 1); }
.wn-an.b .wn-glass { transform: translateX(100%); }
.wn-an.press .wn-glass { transform: scale(1.14, 1.22); }
.wn-an.b.press .wn-glass { transform: translateX(100%) scale(1.14, 1.22); }
.wn-chart { flex: 1; width: 100%; min-height: 0; display: block; overflow: visible; }
.wn-chart .gd { stroke: rgba(255,255,255,.10); stroke-width: 1; fill: none; vector-effect: non-scaling-stroke; }
.wn-chart .ln { fill: none; stroke: #FF6B3D; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.wn-chart .ar { fill: rgba(255,107,61,.13); stroke: none; }
.wn-per { margin: 0; flex: none; display: flex; gap: 6px; }
.wn-per span { font: 600 10px/1 var(--font-mono); padding: 5px 8px; border-radius: 999px; background: rgba(255,255,255,.06); color: var(--nt-ink-2);
  transition: background-color .25s ease, color .25s ease; }
.wn-per span.on { background: #F7F3EE; color: #000; }

/* 3. supervisor PIN */
.wn-card .wn-pin { align-items: center; justify-content: center; gap: 12px; }
.wn-ask { margin: 0; display: flex; align-items: center; gap: 8px; font: 600 13px/1 var(--font-ui); color: #FFFFFF; }
.wn-ask b { font: 600 10px/1 var(--font-mono); letter-spacing: .06em; text-transform: uppercase; padding: 5px 7px; border-radius: 6px; background: rgba(255,107,61,.2); color: #FF9A75; }
.wn-who { margin: 0; font: 500 12px/1 var(--font-ui); color: var(--nt-ink-2); }
.wn-dots { margin: 0; display: flex; gap: 12px; }
.wn-dots i { width: 12px; height: 12px; border-radius: 50%; border: 1.5px solid rgba(255,255,255,.42); transition: background-color .12s ease, border-color .12s ease, transform .25s cubic-bezier(.3, 1.4, .5, 1); }
.wn-dots i.on { background: #FFFFFF; border-color: #FFFFFF; transform: scale(1.1); }
.wn-ok { margin: 0; display: inline-flex; align-items: center; gap: 7px; height: 30px; padding: 0 13px; border-radius: 999px;
  background: rgba(255,107,61,.16); color: #FF9A75; font: 600 13px/1 var(--font-ui);
  opacity: 0; transform: translateY(6px) scale(.96); transition: opacity .3s ease, transform .45s cubic-bezier(.3, 1.35, .45, 1); }
.wn-ok svg { width: 15px; height: 15px; }
.wn-ok path { stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.wn-pin.ok .wn-ok { opacity: 1; transform: none; }

/* 4. the calendar */
.wn-mon { margin: 0; flex: none; display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.wn-mon b { font: 600 14px/1 var(--font-ui); color: #FFFFFF; }
.wn-mon span { font: 500 10px/1 var(--font-ui); color: var(--nt-ink-2); white-space: nowrap; }
.wn-mon span i { display: inline-block; width: 6px; height: 6px; border-radius: 50%; margin: 0 3px 0 6px; vertical-align: 1px; }
.wn-cal .l1 { background: #F7F3EE; } .wn-cal .l2 { background: #8E8E93; } .wn-cal .l3 { background: #FF6B3D; }
.wn-grid { flex: 1; min-height: 0; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); grid-auto-rows: minmax(0, 1fr); gap: 4px; }
.wn-grid > i { position: relative; border-radius: 5px; background: rgba(255,255,255,.05); }
.wn-grid > i.x { background: none; }
.wn-grid > i em { position: absolute; left: 4px; top: 3px; font: 600 8px/1 var(--font-mono); font-style: normal; color: rgba(255,255,255,.38); }
.wn-grid > i span { position: absolute; right: 4px; bottom: 4px; display: flex; gap: 2px; }
.wn-grid s { width: 4px; height: 4px; border-radius: 50%; opacity: 0; transform: scale(0); transition: opacity .2s ease, transform .3s cubic-bezier(.3, 1.6, .5, 1); transition-delay: var(--d, 0ms); }
.wn-cal.in .wn-grid s { opacity: 1; transform: none; }
.wn-grid > i.due { transition: box-shadow .3s ease, background-color .3s ease; }
.wn-cal.ok .wn-grid > i.due { box-shadow: inset 0 0 0 1.5px #FF6B3D; background: rgba(255,107,61,.16); }
.wn-due { margin: 0; flex: none; align-self: flex-start; display: inline-flex; align-items: center; gap: 7px; height: 26px; padding: 0 11px; border-radius: 999px;
  background: rgba(255,107,61,.16); color: #FF9A75; font: 600 11.5px/1 var(--font-ui);
  opacity: 0; transform: translateY(6px); transition: opacity .3s ease, transform .45s cubic-bezier(.3, 1.35, .45, 1); }
.wn-due i { width: 6px; height: 6px; border-radius: 50%; background: #FF6B3D; }
.wn-cal.ok .wn-due { opacity: 1; transform: none; }

/* 5. the order book */
.wn-search { margin: 0; flex: none; display: flex; align-items: center; gap: 7px; height: 30px; padding: 0 11px; border-radius: 9px;
  background: rgba(255,255,255,.07); color: var(--nt-ink-2); font: 500 12px/1 var(--font-ui); }
.wn-search svg { width: 13px; height: 13px; }
.wn-search circle, .wn-search path { stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }
.wn-rows { list-style: none; margin: 0; padding: 0; flex: 1; min-height: 0; display: grid; grid-auto-rows: minmax(0, 1fr); gap: 5px; }
.wn-rows li { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 10px; padding: 0 10px; border-radius: 8px;
  background: rgba(255,255,255,.04); border: 1px solid transparent; font: 500 12px/1 var(--font-ui); color: var(--nt-ink-2);
  transition: background-color .25s ease, border-color .25s ease; }
.wn-rows b { font: 600 11px/1 var(--font-mono); color: #FFFFFF; }
.wn-rows em { font: 600 11px/1 var(--font-mono); font-style: normal; color: #FFFFFF; font-variant-numeric: tabular-nums; }
.wn-rows li.on { background: rgba(255,255,255,.10); border-color: rgba(255,255,255,.18); }
.wn-acts { margin: 0; flex: none; display: flex; gap: 6px; }
.wn-acts span { flex: 1; display: grid; place-items: center; height: 28px; border-radius: 999px; background: rgba(255,255,255,.06); color: var(--nt-ink-2);
  font: 600 12px/1 var(--font-ui); transition: background-color .25s ease, color .25s ease, transform .35s cubic-bezier(.3, 1.4, .5, 1); }
.wn-acts span.on { background: #F7F3EE; color: #000; transform: scale(1.05); }

@media (prefers-reduced-motion: reduce) {
  .wn-thumb, .wn-glass, .wn-dots i, .wn-ok, .wn-grid s, .wn-due, .wn-rows li, .wn-acts span, .wn-per span { transition: none; }
}

/* Round 81b: the twelve-module release on the What's new rail (eight cards,
   one sequence model in js/wn.js: an element with data-at gets .on at that
   moment of the card's beat and loses it at data-off; a number with
   data-steps counts to each value in turn). */
.wn-card .rl34-v.wn-word { font-size: clamp(36px, 3.1vw, 46px); letter-spacing: -0.04em; white-space: nowrap; }
.wn-safe .wn-line { height: 25px; }
.wn-safe .wn-lines { gap: 4px; }
.wn-pop { opacity: 0; transform: translateY(6px); transition: opacity .3s ease, transform .45s cubic-bezier(.3, 1.35, .45, 1); }
.wn-pop.on { opacity: 1; transform: none; }
.wn-chips { margin: 0; flex: none; display: flex; gap: 6px; align-items: center; }
.wn-chips.wn-wrap { flex-wrap: wrap; }
.wn-chips.wn-even > * { flex: 1; }
.wn-chip { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 26px; padding: 0 10px; border-radius: 999px; white-space: nowrap;
  background: rgba(255,255,255,.06); color: var(--nt-ink-2); font: 600 11.5px/1 var(--font-ui);
  transition: background-color .25s ease, color .25s ease, opacity .3s ease, transform .4s cubic-bezier(.3, 1.4, .5, 1); }
.wn-chip[data-at]:not(.wn-pop).on { background: #F7F3EE; color: #000; transform: scale(1.05); }
.wn-chip.acc { background: rgba(255,107,61,.16); color: #FF9A75; }
.wn-chip svg, .wn-jf svg { width: 13px; height: 13px; }
.wn-chip path, .wn-jf path { stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.wn-lines { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }
.wn-line { margin: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 10px; height: 28px; padding: 0 10px; border-radius: 8px;
  background: rgba(255,255,255,.05); font: 500 12px/1 var(--font-ui); color: var(--nt-ink-2); }
.wn-line b { color: #FFFFFF; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wn-line em { font: 600 11px/1 var(--font-mono); font-style: normal; color: #FFFFFF; font-variant-numeric: tabular-nums; }
.wn-notes { margin: 0; flex: none; display: grid; }
.wn-notes > * { grid-area: 1 / 1; justify-self: start; }
.wn-note { font: 500 12px/1.3 var(--font-ui); color: #FF9A75; }

/* reopen it */
.wn-fix .wn-line { grid-template-columns: minmax(0, 1fr) auto auto; }
.wn-sel { background: rgba(255,255,255,.10); box-shadow: inset 0 0 0 1px rgba(255,255,255,.16); }
.wn-st { display: grid; }
.wn-st i { grid-area: 1 / 1; font: 600 9.5px/1 var(--font-mono); font-style: normal; letter-spacing: .05em; text-transform: uppercase; padding: 4px 6px; border-radius: 5px; justify-self: end; transition: opacity .2s ease; }
.wn-paid { background: rgba(255,255,255,.08); color: var(--nt-ink-2); }
.wn-open { background: rgba(255,107,61,.22); color: #FF9A75; opacity: 0; }
.wn-open.on { opacity: 1; }
.wn-sel:has(.wn-open.on) .wn-paid { opacity: 0; }

/* gift cards */
.wn-gc { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; justify-content: space-between; padding: 14px 16px; border-radius: 14px; overflow: hidden;
  background: linear-gradient(135deg, #2E2E33 0%, #1A1A1D 55%, #141416 100%); box-shadow: inset 0 1px 0 rgba(255,255,255,.12), inset 0 0 0 1px rgba(255,255,255,.08), 0 10px 30px rgba(0,0,0,.4); }
.wn-gc::after { content: ""; position: absolute; right: -30%; top: -60%; width: 80%; height: 160%; background: radial-gradient(closest-side, rgba(255,107,61,.22), rgba(255,107,61,0)); pointer-events: none; }
.wn-gc p { margin: 0; position: relative; z-index: 1; }
.wn-gc-t { display: flex; justify-content: space-between; align-items: baseline; }
.wn-gc-t b { font: 700 14px/1 var(--font-ui); color: #FFFFFF; }
.wn-gc-t span { font: 500 10.5px/1 var(--font-ui); color: var(--nt-ink-2); }
.wn-gc-n { font: 600 12px/1 var(--font-mono); letter-spacing: .08em; color: rgba(255,255,255,.62); }
.wn-gc-b { display: flex; justify-content: space-between; align-items: baseline; }
.wn-gc-b span { font: 500 11px/1 var(--font-ui); color: var(--nt-ink-2); }
.wn-gc-b b { font: 700 24px/1 var(--font-ui); color: #FFFFFF; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }

/* the accounting hand-off */
.wn-jr { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 4px; padding: 10px 12px; border-radius: 12px; background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08); }
.wn-jh, .wn-jl { margin: 0; display: grid; grid-template-columns: minmax(0, 1fr) 62px 62px; align-items: center; gap: 6px; }
.wn-jh b { font: 600 11px/1 var(--font-ui); color: var(--nt-ink-2); }
.wn-jh span { font: 600 9.5px/1 var(--font-mono); letter-spacing: .06em; color: var(--nt-ink-2); text-align: right; }
.wn-jl { height: 22px; font: 500 12px/1 var(--font-ui); }
.wn-jl b { color: #FFFFFF; font-weight: 600; }
.wn-jl em { font: 600 11px/1 var(--font-mono); font-style: normal; color: #FFFFFF; text-align: right; font-variant-numeric: tabular-nums; }
.wn-jf { margin: auto 0 0; display: inline-flex; align-items: center; gap: 6px; align-self: flex-end; font: 600 11.5px/1 var(--font-ui); color: #FF9A75; }

/* own riders */
.wn-cols { flex: 1; min-height: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.wn-cols > div { display: flex; flex-direction: column; gap: 8px; padding: 9px 8px; border-radius: 10px; background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.07); }
.wn-cols p { margin: 0; font: 600 10px/1 var(--font-ui); color: var(--nt-ink-2); white-space: nowrap; }
.wn-ord { display: flex; flex-direction: column; gap: 4px; padding: 8px; border-radius: 8px; background: #F7F3EE; color: #000; font: 700 11px/1 var(--font-mono);
  opacity: 0; transform: scale(.9); transition: opacity .25s ease, transform .4s cubic-bezier(.3, 1.4, .5, 1); }
.wn-ord small { font: 600 9.5px/1 var(--font-ui); color: #6E6D6B; }
.wn-ord.acc { background: #FF6B3D; }
.wn-ord.acc small { color: #000; opacity: .7; }
.wn-ord.on { opacity: 1; transform: none; }

/* safe and bank */
.wn-tot { margin: 0; flex: none; display: flex; justify-content: space-between; align-items: baseline; padding: 0 2px; }
.wn-tot span { font: 500 12px/1 var(--font-ui); color: var(--nt-ink-2); }
.wn-tot b { font: 700 20px/1 var(--font-ui); color: #FFFFFF; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.wn-ok2 { background: rgba(255,255,255,.10); color: #FFFFFF; }

/* allergens */
.wn-dish { margin: 0; flex: none; display: flex; justify-content: space-between; align-items: baseline; }
.wn-dish > b { font: 700 14px/1 var(--font-ui); color: #FFFFFF; }
.wn-dish span { font: 500 12px/1 var(--font-ui); color: var(--nt-ink-2); }
.wn-dish span b { font: 700 16px/1 var(--font-ui); color: #FFFFFF; font-variant-numeric: tabular-nums; }
.wn-tag { font: 600 9.5px/1 var(--font-mono); font-style: normal; letter-spacing: .05em; text-transform: uppercase; padding: 4px 6px; border-radius: 5px; background: rgba(255,107,61,.22); color: #FF9A75; }
.wn-tag.none { background: rgba(255,255,255,.06); color: var(--nt-ink-2); }

/* customer display */
.wn-dsp { position: relative; flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 12px 14px; border-radius: 12px;
  background: #F7F3EE; color: #000; box-shadow: 0 0 0 5px #0B0B0C, 0 0 0 6px rgba(255,255,255,.12), 0 12px 30px rgba(0,0,0,.45); margin: 6px; }
.wn-code { grid-area: 1 / 1 / 2 / 3; display: grid; place-items: center; gap: 6px; text-align: center; }
.wn-code span { font: 600 11px/1 var(--font-ui); color: #6E6D6B; }
.wn-code b { font: 700 26px/1 var(--font-mono); letter-spacing: .08em; }
.wn-ordr { grid-area: 1 / 1; display: grid; gap: 6px; align-content: center; }
.wn-dl, .wn-dt { margin: 0; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 8px; align-items: baseline; font: 500 12px/1.1 var(--font-ui); }
.wn-dl span { color: #6E6D6B; } .wn-dl b { font-weight: 600; } .wn-dl em { font: 600 11px/1 var(--font-mono); font-style: normal; }
.wn-dt { grid-template-columns: minmax(0, 1fr) auto; margin-top: 4px; padding-top: 7px; border-top: 1px solid rgba(0,0,0,.12); }
.wn-dt span { font-size: 10.5px; color: #6E6D6B; } .wn-dt b { font: 800 17px/1 var(--font-ui); letter-spacing: -.02em; }
.wn-qr { grid-area: 1 / 2; display: block; width: 58px; height: 58px; }
.wn-cds .wn-dsp { margin: 6px 6px 16px; }
.wn-qr svg { display: block; width: 100%; height: 100%; }

/* menu engineering */
.wn-mx { position: relative; flex: 1; min-height: 0; display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 4px; }
.wn-q { display: flex; align-items: flex-start; padding: 7px 8px; border-radius: 8px; background: rgba(255,255,255,.05); font: 600 10px/1 var(--font-ui); color: var(--nt-ink-2); }
.wn-q.q2 { background: rgba(255,107,61,.12); color: #FF9A75; }
.wn-d { position: absolute; left: 50%; top: 50%; width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; border-radius: 50%; background: #F7F3EE; opacity: 0;
  transition: left .7s cubic-bezier(.3, 1.2, .5, 1), top .7s cubic-bezier(.3, 1.2, .5, 1), opacity .2s ease; }
.wn-d.acc { background: #FF6B3D; box-shadow: 0 0 0 4px rgba(255,107,61,.22); }
.wn-d.on { left: var(--x); top: var(--y); opacity: 1; }
.wn-axes { margin: 0; flex: none; display: flex; justify-content: space-between; font: 500 10px/1 var(--font-ui); color: var(--nt-ink-2); }

@media (prefers-reduced-motion: reduce) {
  .wn-pop, .wn-chip, .wn-ord, .wn-d, .wn-st i { transition: none; }
}

/* Round 82c: on the home plan cards a module the plan does not include is an
   add-on, not a refusal: a plus, the ink of the list, and the word add-on */
.plan li.addon svg { color: var(--o-700, #C14D2A); }
.plan li.addon em { font-style: normal; color: var(--n-500); }

/* Round 83: delEat v2 on the What's new rail (pickup board, food truck,
   attendance with no hardware). Same sequence runner as Round 81b. */
.wn-ns { margin: 0; flex: none; font: 700 12px/1 var(--font-ui); letter-spacing: .08em; text-transform: uppercase; color: #FF9A75; }
.wn-pk { flex: 1; min-height: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.wn-pk > div { display: flex; flex-direction: column; gap: 6px; padding: 9px; border-radius: 10px; background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08); }
.wn-pk > .rdy { background: rgba(255,107,61,.08); border-color: rgba(255,107,61,.25); }
.wn-pk p { margin: 0 0 2px; font: 600 10px/1 var(--font-ui); color: var(--nt-ink-2); }
.wn-tk { display: flex; align-items: baseline; gap: 8px; padding: 6px 8px; border-radius: 7px; background: rgba(255,255,255,.07); font: 600 12px/1 var(--font-ui); color: #FFFFFF; }
.wn-tk b { font: 700 13px/1 var(--font-mono); }
.wn-tk.acc { background: #FF6B3D; color: #000; }
.wn-tk:not(.wn-pop) { opacity: 1; }

.wn-spot { margin: 0; flex: none; display: flex; gap: 10px; align-items: center; padding: 10px 12px; border-radius: 12px; background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.08); }
.wn-spot svg { flex: none; width: 22px; height: 22px; color: #FF6B3D; }
.wn-spot path, .wn-spot circle { stroke: currentColor; stroke-width: 1.5; }
.wn-spot span { display: flex; flex-direction: column; gap: 5px; font: 500 11.5px/1.2 var(--font-ui); color: var(--nt-ink-2); }
.wn-spot b { font: 600 13px/1 var(--font-ui); color: #FFFFFF; }
.wn-week { margin: 0; flex: 1; min-height: 0; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; align-items: stretch; }
.wn-week span { display: grid; place-items: end center; padding-bottom: 7px; border-radius: 8px; background: rgba(255,255,255,.05); font: 600 10px/1 var(--font-ui); color: var(--nt-ink-2);
  background-image: radial-gradient(circle at 50% 38%, rgba(255,255,255,.35) 0 3px, transparent 3.5px); }
.wn-week span.on:nth-child(3) { background-color: rgba(255,107,61,.18); color: #FF9A75; background-image: radial-gradient(circle at 50% 38%, #FF6B3D 0 4px, transparent 4.5px); }

.wn-card .wn-clock { flex-direction: row; align-items: stretch; gap: 12px; }
.wn-qrw { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; border-radius: 12px; background: #F7F3EE; padding: 10px; }
.wn-qrw .wn-qr { width: 74px; height: 74px; }
.wn-ttl { width: 74px; height: 3px; border-radius: 2px; background: rgba(0,0,0,.12); overflow: hidden; }
.wn-ttl i { display: block; height: 100%; background: #C14D2A; transform-origin: 0 50%; animation: wnTtl 6s linear infinite; }
@keyframes wnTtl { from { transform: scaleX(1); } to { transform: scaleX(0); } }
.wn-qrw small { font: 600 10px/1 var(--font-ui); color: #6E6D6B; }
.wn-phn { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: 8px; padding: 12px; border-radius: 16px; background: #0B0B0C; box-shadow: 0 0 0 1.5px rgba(255,255,255,.16); }
.wn-phn p { margin: 0; font: 500 11.5px/1.2 var(--font-ui); color: var(--nt-ink-2); }
.wn-phn p b { display: block; font: 700 20px/1 var(--font-ui); color: #FFFFFF; margin-bottom: 4px; font-variant-numeric: tabular-nums; }
.wn-okc { display: inline-flex; align-items: center; gap: 6px; color: #FF9A75 !important; font-weight: 600 !important; }
.wn-okc svg { width: 14px; height: 14px; }
.wn-okc path { stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
@media (prefers-reduced-motion: reduce) { .wn-ttl i { animation: none; } }
.wn-pk .wn-tk.wn-pop:not(.on) { display: none; }

/* Round 84: v3 (venue hire, event costing) and v4 (receipt QR codes) on the
   What's new rail */
.wn-hall { position: relative; flex: 1; min-height: 0; border-radius: 12px; background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08); padding: 12px; }
.wn-tbls { height: 100%; display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: 1fr 1fr; gap: 10px; place-items: center; }
.wn-tbls i { width: 70%; max-width: 38px; aspect-ratio: 1; border-radius: 50%; border: 1.5px solid rgba(255,255,255,.25); }
.wn-tbls i:nth-child(odd) { border-radius: 8px; }
.wn-pe { position: absolute; inset: 8px; margin: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px; border-radius: 9px;
  background: rgba(255,107,61,.18); border: 1.5px dashed rgba(255,107,61,.7); font: 500 11px/1 var(--font-ui); color: #FF9A75; -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); }
.wn-pe b { font: 700 15px/1 var(--font-ui); color: #FFFFFF; }
.wn-eh, .wn-el { margin: 0; display: grid; grid-template-columns: minmax(0, 1fr) 58px 58px; gap: 6px; align-items: center; }
.wn-eh b { font: 600 11px/1 var(--font-ui); color: var(--nt-ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wn-eh span { font: 600 9px/1 var(--font-mono); letter-spacing: .05em; color: var(--nt-ink-2); text-align: right; text-transform: uppercase; }
.wn-el { height: 20px; font: 500 11.5px/1 var(--font-ui); }
.wn-el b { color: #FFFFFF; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wn-el em { font: 600 10.5px/1 var(--font-mono); font-style: normal; color: #FFFFFF; text-align: right; font-variant-numeric: tabular-nums; }
.wn-mg { margin-top: auto; display: grid; grid-template-columns: auto 1fr auto; gap: 8px; align-items: center; font: 600 11px/1 var(--font-ui); color: var(--nt-ink-2); }
.wn-mg i { position: relative; height: 6px; border-radius: 3px; background: rgba(255,255,255,.1); }
.wn-mg s { position: absolute; left: 0; top: 0; bottom: 0; width: 34%; border-radius: 3px; background: #FF6B3D; }
.wn-mg u { position: absolute; left: 30%; top: -3px; bottom: -3px; width: 2px; background: #F7F3EE; }
.wn-mg b { color: #FFFFFF; font: 700 13px/1 var(--font-ui); }
.wn-slip { flex: 1; min-height: 0; margin: 0 auto; width: min(100%, 220px); display: flex; flex-direction: column; gap: 5px; padding: 10px 12px; border-radius: 4px 4px 0 0;
  background: #F7F3EE; color: #000; font: 500 10.5px/1.2 var(--font-mono); box-shadow: 0 10px 24px rgba(0,0,0,.45);
  -webkit-mask: linear-gradient(#000 calc(100% - 6px), transparent 0), radial-gradient(circle at 5px 100%, transparent 4px, #000 4.5px) 0 100% / 10px 6px repeat-x;
  mask: linear-gradient(#000 calc(100% - 6px), transparent 0), radial-gradient(circle at 5px 100%, transparent 4px, #000 4.5px) 0 100% / 10px 6px repeat-x; }
.wn-logo { margin: 0 0 3px; text-align: center; font: 800 12px/1 var(--font-ui); letter-spacing: .18em; }
.wn-sl { margin: 0; display: flex; justify-content: space-between; }
.wn-qrs { margin-top: auto; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; padding-top: 6px; border-top: 1px dashed rgba(0,0,0,.3); }
.wn-qrs figure { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.wn-qrs .wn-qr, .wn-qrs .wn-qr2 { display: block; width: 46px; height: 46px; }
.wn-qrs svg { display: block; width: 100%; height: 100%; }
.wn-qrs figcaption { display: flex; flex-direction: column; align-items: center; gap: 2px; font: 600 8.5px/1.1 var(--font-ui); text-align: center; }
.wn-qrs small { font: 500 7.5px/1 var(--font-mono); color: #444; }

/* Round 85: the business tax invoice card (v4.1) */
.wn-a4 { flex: 1; min-height: 0; margin: 0 auto; width: min(100%, 236px); display: flex; flex-direction: column; gap: 5px; padding: 11px 13px; border-radius: 4px;
  background: #F7F3EE; color: #000; box-shadow: 0 10px 24px rgba(0,0,0,.45); }
.wn-a4h { margin: 0 0 2px; display: flex; justify-content: space-between; align-items: baseline; }
.wn-a4h b { font: 800 10px/1 var(--font-ui); letter-spacing: .12em; }
.wn-a4h span { font: 500 8.5px/1 var(--font-mono); color: #6E6D6B; }
.wn-buyer { position: relative; display: flex; flex-direction: column; gap: 3px; padding: 7px 8px; border-radius: 5px; background: rgba(0,0,0,.05); }
.wn-buyer span { font: 600 8px/1 var(--font-ui); text-transform: uppercase; letter-spacing: .08em; color: #6E6D6B; }
.wn-buyer b { font: 700 11px/1.1 var(--font-ui); }
.wn-buyer small { font: 500 8.5px/1.2 var(--font-mono); color: #444; }
.wn-lock { position: absolute; right: 6px; top: 6px; display: inline-flex; align-items: center; gap: 3px; padding: 3px 6px; border-radius: 999px; background: #C14D2A; color: #FFFFFF; font: 700 8.5px/1 var(--font-ui); font-style: normal; }
.wn-lock svg { width: 10px; height: 10px; }
.wn-lock rect, .wn-lock path { stroke: currentColor; stroke-width: 1.6; }
.wn-a4l { margin: 0; display: flex; justify-content: space-between; font: 500 9.5px/1.2 var(--font-ui); }
.wn-a4l em { font: 600 9.5px/1 var(--font-mono); font-style: normal; }
.wn-a4l.tot { margin-top: auto; padding-top: 4px; border-top: 1px solid rgba(0,0,0,.2); font-weight: 700; }
@media (min-width: 901px) {
  .wn-a4 { gap: 3px; padding: 8px 12px; }
  .wn-buyer { padding: 5px 7px; gap: 2px; }
  .wn-buyer small { font-size: 8px; }
}

/* Round 86: the receiving card (v4.2, Purchasing) */
.wn-ph, .wn-pl { margin: 0; display: grid; grid-template-columns: minmax(0, 1fr) 40px 32px; gap: 6px; align-items: center; }
.wn-ph b { font: 600 10.5px/1 var(--font-ui); color: var(--nt-ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wn-ph span { font: 600 9px/1 var(--font-mono); letter-spacing: .05em; text-transform: uppercase; color: var(--nt-ink-2); text-align: right; }
.wn-pl { row-gap: 3px; font: 500 11.5px/1 var(--font-ui); }
.wn-pl b { color: #FFFFFF; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wn-pl em { font: 600 11px/1 var(--font-mono); font-style: normal; color: #FFFFFF; text-align: right; }
.wn-pl .wn-tag { grid-column: 1 / -1; justify-self: start; }
.wn-po .wn-jr { gap: 6px; }
.wn-po .wn-jr { gap: 4px; padding: 8px 10px; }
.wn-po .wn-pl .wn-tag { padding: 3px 5px; font-size: 8.5px; }

/* Round 88: a mini card on a black band takes the dashboard tile's charcoal
   at every width, not only on phones (Parth, 23 Oct, /start), and its icon
   reads bone on the charcoal rather than ink */
[data-ground="black"] .mini-card {
  --ink: var(--bone); --ink-2: #A1A1A6; --ink-3: #8E8E93; --line: rgba(255,255,255,.12);
  background: #161618; border: 1px solid rgba(255,255,255,.14); color: var(--bone);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.06), 0 12px 40px rgba(0,0,0,.45);
}
[data-ground="black"] .mini-card b { color: var(--bone); }
[data-ground="black"] .mini-card small { color: #A1A1A6; }
[data-ground="black"] .mini-card .ic-tile, [data-ground="black"] .mini-card .ic-tile .ic { color: var(--bone); }


/* Round 89: the whole outlet as six chapters (index.html #jobs; js/jobs2.js).
   One stage, one idea at a time: a photograph (the stand-in for a Higgsfield
   loop) that slowly pushes in, a glass card of the real screen floating on it,
   three big numbers and the modules behind the chapter. Apple's highlights
   pill runs the tabs: the active one fills over the chapter's time and the
   next one takes over, until somebody chooses. */
.jobs2 { overflow-x: clip; }
.jobs2 .jx-head h2 { max-width: 14ch; }
.jx-dim { background-image: linear-gradient(180deg, #E5E5EA 0%, #8E8E93 100%); -webkit-background-clip: text; background-clip: text; color: transparent; -webkit-text-fill-color: transparent; }

.jx { margin-top: clamp(28px, 4vw, 48px); }
.jx-tabs { display: flex; gap: 6px; padding: 5px; border-radius: 999px; width: max-content; max-width: 100%;
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.10); overflow-x: auto; scrollbar-width: none; }
.jx-tabs::-webkit-scrollbar { display: none; }
.jx-tab { position: relative; flex: none; height: 40px; padding: 0 18px; border: 0; border-radius: 999px; cursor: pointer; overflow: hidden;
  background: transparent; color: #A1A1A6; font: 600 14px/1 var(--font-ui); letter-spacing: -.005em; transition: color .25s ease, background-color .25s ease; }
.jx-tab span { position: relative; z-index: 1; }
.jx-tab:hover { color: #FFFFFF; }
.jx-tab[aria-selected="true"] { color: #000; background: #F7F3EE; }
.jx-tab:focus-visible { outline: 2px solid #FF6B3D; outline-offset: 2px; }
.jx-prog { position: absolute; inset: auto 14px 6px; height: 2px; border-radius: 2px; background: rgba(0,0,0,.12); opacity: 0; }
.jx-prog::after { content: ""; position: absolute; inset: 0; border-radius: inherit; background: #FF6B3D; transform-origin: 0 50%; transform: scaleX(0); }
.jx.is-auto .jx-tab[aria-selected="true"] .jx-prog { opacity: 1; }
.jx.is-auto .jx-tab[aria-selected="true"] .jx-prog::after { animation: jxFill var(--jx-dur, 7s) linear forwards; }
.jx.is-paused .jx-tab[aria-selected="true"] .jx-prog::after { animation-play-state: paused; }
@keyframes jxFill { to { transform: scaleX(1); } }

.jx-stage { position: relative; margin-top: 20px; }
.jx-p { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(24px, 4vw, 56px); align-items: center; }
.jx-p[hidden] { display: none; }
.jx-copy > * { opacity: 0; transform: translateY(14px); transition: opacity .5s ease, transform .7s cubic-bezier(.2, .8, .2, 1); }
.jx-p.is-on .jx-copy > * { opacity: 1; transform: none; }
.jx-p.is-on .jx-copy > :nth-child(2) { transition-delay: .06s; }
.jx-p.is-on .jx-copy > :nth-child(3) { transition-delay: .12s; }
.jx-p.is-on .jx-copy > :nth-child(4) { transition-delay: .18s; }
.jx-p.is-on .jx-copy > :nth-child(5) { transition-delay: .24s; }
.jx-k { margin: 0; font: 600 12px/1.2 var(--font-mono); letter-spacing: .06em; text-transform: uppercase; color: #FF8A5B; }
.jx-copy h3 { margin: 14px 0 0; font-family: var(--font-display); font-weight: 800; font-size: clamp(36px, 4.2vw, 60px); line-height: 1.02; letter-spacing: -.045em;
  background-image: linear-gradient(180deg, #FFFFFF 0%, #E5E5EA 60%, #A1A1A6 100%); -webkit-background-clip: text; background-clip: text; color: transparent; -webkit-text-fill-color: transparent; }
.jx-l { margin: 16px 0 0; max-width: 40ch; font-size: clamp(16px, 1.25vw, 18px); line-height: 1.5; color: #A1A1A6; }
.jx-stats { margin: 26px 0 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,.12); }
.jx-stats dt { font-family: var(--font-display); font-weight: 800; font-size: clamp(28px, 2.6vw, 40px); letter-spacing: -.04em; line-height: 1; color: #FFFFFF; }
.jx-stats dt small { font-size: .45em; font-weight: 700; margin-left: .15em; letter-spacing: -.01em; }
.jx-stats dd { margin: 8px 0 0; font-size: 13px; line-height: 1.35; color: #A1A1A6; }
.jx-mods { margin: 22px 0 0; display: flex; flex-wrap: wrap; gap: 6px; }
.jx-mods a { display: inline-flex; align-items: center; height: 30px; padding: 0 12px; border-radius: 999px; background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.10);
  color: #E5E5EA; font: 500 12.5px/1 var(--font-ui); text-decoration: none; transition: background-color .2s ease, border-color .2s ease; }
.jx-mods a:hover { background: rgba(255,255,255,.12); border-color: rgba(255,255,255,.22); }

/* the cinematic frame */
.jx-media { position: relative; margin: 0; aspect-ratio: 7 / 6; border-radius: 28px; overflow: hidden; isolation: isolate; background: #111;
  box-shadow: 0 30px 80px rgba(0,0,0,.55), inset 0 0 0 1px rgba(255,255,255,.08); }
.jx-media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transform: scale(1.08); transition: transform 9s cubic-bezier(.2, .6, .2, 1); z-index: -2; }
.jx-p.is-on .jx-media img { transform: scale(1); }
.jx-media::after { content: ""; position: absolute; inset: 0; z-index: -1; background:
  linear-gradient(180deg, rgba(0,0,0,0) 35%, rgba(0,0,0,.55) 100%), radial-gradient(120% 80% at 100% 0%, rgba(0,0,0,.35), rgba(0,0,0,0) 60%); }

/* the screen, floating on the frame: Liquid-Glass dark, the site's own */
.jx-ui { position: absolute; left: 6%; bottom: 7%; width: min(62%, 360px); padding: 16px 18px; border-radius: 20px;
  background: rgba(20,20,22,.62); -webkit-backdrop-filter: blur(18px) saturate(1.6); backdrop-filter: blur(18px) saturate(1.6);
  border: 1px solid rgba(255,255,255,.16); box-shadow: inset 0 1px 0 rgba(255,255,255,.12), 0 20px 50px rgba(0,0,0,.45);
  display: grid; gap: 8px; transform: translateY(18px); opacity: 0; transition: opacity .5s ease .15s, transform .8s cubic-bezier(.2, .9, .2, 1) .15s; }
.jx-p.is-on .jx-ui { transform: none; opacity: 1; }
.jx-ui-k { margin: 0; font: 600 11px/1 var(--font-mono); letter-spacing: .04em; color: #A1A1A6; }
.jx-ui-big { margin: 2px 0 0; display: flex; align-items: baseline; gap: 10px; }
.jx-ui-big b { font: 800 30px/1 var(--font-display); letter-spacing: -.03em; color: #FFFFFF; }
.jx-ui-big span { font: 600 13px/1 var(--font-ui); color: #FF9A75; }
.jx-ui-row { margin: 0; display: flex; align-items: center; gap: 8px; font: 500 12.5px/1.25 var(--font-ui); color: #E5E5EA; }
.jx-ui-row i { flex: none; width: 16px; height: 16px; border-radius: 50%; background: rgba(255,107,61,.2); position: relative; }
.jx-ui-row i.ok::after { content: ""; position: absolute; left: 5px; top: 3.5px; width: 4px; height: 7px; border: solid #FF9A75; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.jx-ui-row i.dot::after { content: ""; position: absolute; inset: 5px; border-radius: 50%; background: #FF6B3D; }
.jx-ui-line { margin: 0; display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 10px; align-items: center; padding: 8px 10px; border-radius: 10px; background: rgba(255,255,255,.06); font: 500 12px/1.2 var(--font-ui); color: #A1A1A6; }
.jx-ui-line b { color: #FFFFFF; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.jx-ui-line em { font: 600 11px/1 var(--font-mono); font-style: normal; color: #FFFFFF; font-variant-numeric: tabular-nums; }
.jx-ui-line .tag { font: 600 9.5px/1 var(--font-mono); font-style: normal; letter-spacing: .05em; text-transform: uppercase; padding: 4px 6px; border-radius: 5px; background: rgba(255,107,61,.24); color: #FF9A75; }
.jx-ui-line .tag.soft { background: rgba(255,255,255,.10); color: #E5E5EA; }
.jx-float { position: absolute; right: 5%; top: 6%; margin: 0; padding: 9px 14px; border-radius: 999px; background: rgba(247,243,238,.92); color: #111;
  font: 500 12.5px/1 var(--font-ui); box-shadow: 0 10px 30px rgba(0,0,0,.35); }
.jx-float b { font-weight: 700; color: #C14D2A; }
/* the lines of each screen arrive in order (comp/jobs2.js sets .on) */
.jx-media [data-at] { opacity: 0; transform: translateY(8px); transition: opacity .35s ease, transform .5s cubic-bezier(.3, 1.3, .5, 1); }
.jx-media [data-at].on { opacity: 1; transform: none; }

@media (max-width: 900px) {
  .jx-tabs { width: auto; margin-inline: calc(-1 * var(--gutter)); border-radius: 0; border-inline: 0; padding-inline: var(--gutter); scroll-padding-inline: var(--gutter); background: none; border: 0; gap: 8px; }
  .jx-tab { background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.10); height: 38px; padding: 0 16px; font-size: 13.5px; }
  .jx-p { grid-template-columns: 1fr; gap: 22px; }
  .jx-media { order: -1; aspect-ratio: 4 / 4.2; border-radius: 22px; }
  .jx-ui { width: auto; right: 5%; left: 5%; bottom: 5%; padding: 14px; }
  .jx-float { right: 4%; top: 4%; font-size: 11.5px; padding: 8px 12px; }
  .jx-copy h3 { font-size: clamp(32px, 9vw, 44px); }
  .jx-stats { gap: 10px; }
  .jx-stats dd { font-size: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .jx-copy > *, .jx-ui, .jx-media img, .jx-media [data-at] { transition: none; }
  .jx-media img { transform: none; }
}
