/* ═══════════════════════════════════════════════════════════════════════════
   MonerMonkeys — מונר מאנקיז
   70s/80s diner: harvest gold ground, burgundy as the structural colour,
   mustard and teal as accents, and a heavy Hebrew display face with slab
   character. Authentic diner, not retro pastiche — the palette and the motifs
   are period, the structure stays editorial: generous spacing, strong
   hierarchy, restraint. Checkerboard appears once, as a band, never as
   wallpaper.

   What keeps harvest gold from reading like the rejected banana-yellow build
   is the surrounding language, not the hue: burgundy rather than black as the
   structural colour, an arched frame and a checkered band rather than hard
   outlines, and NO BLACK KEYLINES AND NO OFFSET SHADOWS anywhere. If the page
   ever starts to feel neobrutalist again, look for outlines first.

   Prohibitions from the brief: no gradients anywhere (the checkerboard is an
   inline SVG tile, not repeating-conic-gradient), no italics anywhere.
   Hebrew, RTL, logical properties throughout.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Fonts ─────────────────────────────────────────────────────────────────
   Self-hosted: a demo that opens from a site selling speed must not block on
   a third-party CDN. Suez One is the display face — heavy, slabbed, and it
   ships a single weight and no italic, so there is nothing to misuse. */
@font-face {
  font-family: 'Suez';
  src: url('fonts/suez-hebrew.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face {
  font-family: 'Suez';
  src: url('fonts/suez-latin.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+2000-206F, U+20AC, U+2122, U+2212;
}
@font-face {
  font-family: 'Rubik';
  src: url('fonts/rubik-hebrew.woff2') format('woff2');
  font-weight: 300 900; font-style: normal; font-display: swap;
  unicode-range: U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face {
  font-family: 'Rubik';
  src: url('fonts/rubik-latin.woff2') format('woff2');
  font-weight: 300 900; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+2000-206F, U+20AC, U+2122, U+2212;
}

/* ── Tokens ───────────────────────────────────────────────────────────────
   Measured against the ground: ink 12.0:1, ink-2 10.5:1, burgundy 8.2:1. The
   lighter ground lifted every pairing, so burgundy now clears the body bar too
   and is safe anywhere. Cream on burgundy is 9.2:1, ink on the panel 15.1:1. */
:root {
  --gold:     #FAD784;   /* the ground — never swap this for #FFC800 */
  /* The panel has to read as a distinct surface on that ground, and the old
     #F0D79B lands within 1.02:1 of this lighter gold — invisible. So it goes
     the other way: a warm pale cream, 1.26:1 against the ground. */
  --panel:    #FDF3D9;   /* cards, stat tiles, the arched frame, "the place" */
  --burg:     #6E1A2B;   /* structural colour: actions, the band, headings */
  --mustard:  #E4A32B;
  --teal:     #2A6060;   /* white on it is 7.1:1 — the order section is body
                            copy, so it has to clear the 7:1 bar, not 5:1 */
  --ink:      #2A1A16;   /* 12.0:1 on gold  ·  15.1:1 on panel */
  --ink-2:    #3A241D;   /* 10.5:1 on gold — body copy */
  --cream:    #F3E7D0;   /* 9.2:1 on burgundy · the light checker square */
  --on-dark:  #F3E7D0;
  --on-dark-2:#E0CDB0;

  --rule:      color-mix(in srgb, var(--burg) 26%, transparent);
  --rule-dark: color-mix(in srgb, var(--cream) 28%, transparent);

  --wrap: 1240px;
  --pad: clamp(1.15rem, 4vw, 3.5rem);
  --r: 12px;             /* enamel-panel radius: rounded, never outlined */

  --t-display: clamp(2.35rem, 6.4vw, 5rem);
  --t-h2:      clamp(1.8rem, 4vw, 3.1rem);
  --t-h3:      clamp(1.3rem, 2.2vw, 1.7rem);
  --t-lede:    clamp(1.08rem, 1.5vw, 1.3rem);
  --t-body:    clamp(1rem, 1.2vw, 1.075rem);
  --t-sm:      0.9375rem;
  --t-micro:   0.8rem;

  --ease: cubic-bezier(.22, .61, .36, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
}

/* ── Reset ────────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--gold);
  color: var(--ink);
  font-family: 'Rubik', system-ui, sans-serif;
  font-weight: 400;
  font-size: var(--t-body);
  line-height: 1.7;
  overflow-x: hidden;
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
}

img, svg, canvas, video { display: block; max-width: 100%; }
img { height: auto; }
button { font: inherit; color: inherit; }
a { color: inherit; }

/* Suez One ships one weight. Asking for 700 would invite a synthesised face,
   which font-synthesis: none correctly refuses — so ask for 400. */
h1, h2, h3, h4 {
  font-family: 'Suez', Georgia, serif;
  font-weight: 400;
  color: var(--ink);
  line-height: 1.08;
  letter-spacing: -0.012em;
  margin: 0;
  text-wrap: balance;
}

p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }

/* The brief forbids italics outright. <i> is used here only as a shape — the
   marquee's checker segments and the dissection's step counter — but its UA
   default is italic, so take the whole family out of the running rather than
   patch each use. */
i, em, cite, address, dfn, var { font-style: normal; }

/* Bidi isolation. Hebrew running text around Latin names and numeric ranges
   reorders into nonsense without this; <bdi> alone is not enough for ranges. */
.ltr { direction: ltr; unicode-bidi: isolate; display: inline-block; }

.wrap { width: min(100% - var(--pad) * 2, var(--wrap)); margin-inline: auto; }

.skip {
  position: absolute; inset-block-start: -100vh; inset-inline-start: 0;
  background: var(--burg); color: var(--cream);
  padding: 1rem 1.5rem; z-index: 200; font-weight: 600;
}
.skip:focus { inset-block-start: 0; }

:where(a, button, [tabindex]):focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* ═══ Chips ═══════════════════════════════════════════════════════════════
   The diner replacement for the editorial small-cap kicker: a filled enamel
   chip. Teal on the gold ground, burgundy on the panel tint. */
.kicker, .marker {
  display: inline-block;
  font-size: var(--t-micro); font-weight: 700;
  letter-spacing: .12em;
  background: var(--teal); color: #fff;
  padding: .4rem .85rem; border-radius: 999px;
  margin-block-end: 1.2rem;
}
.marker--burg { background: var(--burg); }
.layer__n, .card__tag, .ticks li {
  font-size: var(--t-micro); font-weight: 700;
  letter-spacing: .1em; color: var(--burg);
}

/* ═══ Buttons ═════════════════════════════════════════════════════════════ */
.btn {
  display: inline-flex; align-items: center; gap: .55rem;
  padding: .92rem 1.7rem; border-radius: 999px;
  background: var(--burg); color: #fff;
  border: 1px solid transparent;
  font-weight: 600; font-size: 1rem;
  text-decoration: none; cursor: pointer;
  transition: background .2s var(--ease), color .2s var(--ease);
}
.btn:hover { background: var(--ink); color: #fff; }
.btn svg { width: 1.15em; height: 1.15em; flex: none; }

.btn--go { background: var(--burg); color: #fff; }
.btn--go:hover { background: var(--ink); }

/* Quiet secondary: a rule, not a box. */
.btn--ghost {
  background: transparent; color: var(--ink);
  border-radius: 0; padding-inline: 0; padding-block: .6rem .5rem;
  border-block-end: 2px solid var(--burg);
}
.btn--ghost:hover { background: transparent; color: var(--burg); }

.btn--lg { padding: 1.05rem 2.1rem; font-size: 1.05rem; }

/* ═══ Nav ═════════════════════════════════════════════════════════════════ */
.nav {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 100;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding: .8rem var(--pad);
  /* Opaque first: without a fallback, a browser that cannot parse color-mix
     drops the declaration entirely and the bar goes transparent over content. */
  background: var(--gold);
  background: color-mix(in srgb, var(--gold) 90%, transparent);
  backdrop-filter: blur(10px);
  border-block-end: 1px solid var(--rule);
  transition: transform .35s var(--ease);
}
.nav.is-hidden { transform: translateY(-102%); }

.brand { display: flex; align-items: center; gap: .6rem; text-decoration: none; }
/* The mascot, promoted: it was an awkward guest in an editorial system and is
   at home in a diner. Here it rides a burgundy medallion. */
.brand__badge {
  width: 42px; height: 42px; flex: none; border-radius: 50%;
  background: var(--burg); display: grid; place-items: center;
}
.brand__badge img { width: 30px; height: 30px; }
.brand b {
  font-family: 'Suez', serif; font-weight: 400; color: var(--ink);
  font-size: 1.15rem; line-height: 1.15; letter-spacing: -.01em;
}
.brand span span, .brand > span > span:last-child {
  font-family: 'Rubik', sans-serif; font-size: .58rem; font-weight: 700;
  letter-spacing: .2em; text-transform: uppercase; color: var(--burg);
}

.nav__links { display: flex; gap: 1.5rem; }
.nav__links a {
  text-decoration: none; font-size: var(--t-sm); font-weight: 500; color: var(--ink);
  padding-block: .25rem; border-block-end: 2px solid transparent;
}
.nav__links a:hover { border-block-end-color: var(--burg); }

.nav__end { display: flex; align-items: center; gap: .75rem; }
.nav .btn { padding: .6rem 1.2rem; font-size: var(--t-sm); }

.burger-btn {
  display: none; width: 42px; height: 42px; padding: 0;
  background: var(--panel); border: none; border-radius: 999px;
  cursor: pointer; align-items: center; justify-content: center;
}
.burger-btn i, .burger-btn i::before, .burger-btn i::after {
  content: ''; display: block; width: 18px; height: 2px; background: var(--ink);
  border-radius: 2px;
}
.burger-btn i { position: relative; }
.burger-btn i::before { position: absolute; inset-block-start: -6px; }
.burger-btn i::after  { position: absolute; inset-block-start: 6px; }

@media (max-width: 940px) {
  .nav__links { display: none; }
  .burger-btn { display: inline-flex; }
  .nav .btn--go { display: none; }
}

.sheet {
  position: fixed; inset: 0; z-index: 150;
  background: var(--gold);
  padding: 6rem var(--pad) var(--pad);
  display: flex; flex-direction: column;
  transform: translateY(-100%); visibility: hidden;
  transition: transform .45s var(--ease-out), visibility .45s;
}
.sheet.is-open { transform: translateY(0); visibility: visible; }
.sheet a {
  font-family: 'Suez', serif; font-weight: 400; color: var(--ink);
  font-size: 1.8rem; text-decoration: none;
  padding-block: .8rem; border-block-end: 1px solid var(--rule);
}
.sheet .btn { margin-block-start: 2rem; justify-content: center; }
.sheet__x {
  position: absolute; inset-block-start: 1.1rem; inset-inline-end: var(--pad);
  width: 42px; height: 42px; font-size: 1.6rem; line-height: 1;
  background: var(--panel); border: none; border-radius: 999px; cursor: pointer;
}

/* ═══ Hero ════════════════════════════════════════════════════════════════ */
.hero { position: relative; padding-block: clamp(6.5rem, 14vh, 10rem) clamp(3rem, 8vh, 5rem); }
.hero__grid {
  display: grid; grid-template-columns: 1.05fr .95fr;
  gap: clamp(2rem, 5vw, 4.5rem); align-items: center;
}

/* The diner sign: an arched enamel panel behind the food. This, and the
   checkered band, are the two motifs doing the period work — no outlines. */
.arch {
  position: relative;
  background: var(--panel);
  border-radius: 999px 999px var(--r) var(--r);
  padding: clamp(1.5rem, 4vw, 2.75rem) clamp(1.5rem, 4vw, 3rem) clamp(1rem, 2vw, 1.5rem);
}
.hero__burger img { width: 100%; max-width: 560px; margin-inline: auto; }
.hero__burger.is-float img { animation: bob 7s var(--ease) infinite; }
@keyframes bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }

.hero h1 { font-size: var(--t-display); margin-block-end: 1.4rem; }
.hero__lede {
  font-size: var(--t-lede); max-width: 40ch; margin-block-end: 2rem;
  padding-block-start: 1.4rem; border-block-start: 2px solid var(--rule);
  color: var(--ink-2);
}
.hero__cta { display: flex; flex-wrap: wrap; align-items: center; gap: 1.5rem; margin-block-end: 2rem; }

.ticks { display: flex; flex-wrap: wrap; gap: 1.5rem; }
.ticks li { display: flex; align-items: center; gap: .45rem; }
.ticks li::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%;
  background: var(--burg); flex: none;
}

@media (max-width: 900px) {
  .hero__grid { grid-template-columns: 1fr; }
  .hero__burger { order: -1; max-width: 440px; margin-inline: auto; }
}

/* ═══ Section furniture ═══════════════════════════════════════════════════ */
.slab { padding-block: clamp(4rem, 10vh, 7.5rem); }
.slab--gold  { background: var(--gold); }
.slab--panel { background: var(--panel); }
.slab--burg  { background: var(--burg); color: var(--on-dark-2); }
.slab--teal  { background: var(--teal); color: #fff; }
.slab--burg h2, .slab--burg h3, .slab--teal h2, .slab--teal h3 { color: var(--cream); }
.slab--burg .marker { background: var(--mustard); color: var(--ink); }
.slab--teal .marker { background: var(--mustard); color: var(--ink); }
.slab--burg .lede, .slab--teal .lede { color: var(--on-dark-2); }
.slab--teal .lede, .slab--teal p { color: #fff; }

.sechead { margin-block-end: clamp(2.25rem, 5vh, 4rem); max-width: 60ch; }
.h2 { font-size: var(--t-h2); max-width: 17ch; }
.lede {
  font-size: var(--t-lede); max-width: 54ch; margin-block-start: 1.3rem;
  color: var(--ink-2);
}

/* ═══ Checkered marquee ═══════════════════════════════════════════════════
   §3.2. One square is --check. The SVG tile is 2×2 squares, so the tile
   measures 2×--check and the strip is exactly one tile tall — EXACTLY TWO
   ROWS. Never set the strip height independently of the tile size, and never
   pad inside the strip: that is what produced the stray half row. The band
   around it is padded instead, and carries no background of its own — the
   checkerboard runs straight across the page's ground.

   The checkerboard is an inline SVG tile rather than repeating-conic-gradient
   so there is no argument about the no-gradients rule.

   Truly endless: the track is 400 tiles wide and travels exactly 200 tiles, so
   the pattern lands back on itself every cycle with nothing to reset. It holds
   any viewport up to 400 squares wide. Physical LTR because it is a moving
   pattern with no text in it, and the translate is a physical axis. */
.checks {
  /* §9.1 — twice as thick. Everything else here is derived from this one
     number, so the strip is still exactly two rows and the loop is still
     seamless by construction; nothing below had to be touched. */
  --check: 32px;          /* one square; the strip is two of them tall */
  direction: ltr;
  overflow: hidden;
  padding-block: clamp(1.6rem, 4vw, 2.75rem);
}
.checks__t {
  height: calc(var(--check) * 2);                                     /* 2 rows */
  width: calc(var(--check) * 800);
  background-size: calc(var(--check) * 2) calc(var(--check) * 2);     /* 1 tile */
  background-repeat: repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Crect width='24' height='24' fill='%236E1A2B'/%3E%3Crect width='12' height='12' fill='%23F3E7D0'/%3E%3Crect x='12' y='12' width='12' height='12' fill='%23F3E7D0'/%3E%3C/svg%3E");
  /* §9.1/§9.5-A1 — a fifth of the old pace. The travel is 400 squares, so at
     32px that is 12800px: 12800 / 440s = 29 px/s, and a square takes about a
     second to cross its own width. Change --check and this duration has to be
     re-derived, or the pace moves with the thickness. */
  animation: roll 440s linear infinite;
  will-change: transform;
}
@keyframes roll {
  from { transform: translateX(0); }
  to   { transform: translateX(calc(var(--check) * -400)); }
}
@media (prefers-reduced-motion: reduce) { .checks__t { animation: none; } }

/* ═══ The dissection ══════════════════════════════════════════════════════
   The centrepiece. Seven high-resolution layer cut-outs, not a frame
   sequence: scroll drives a playhead that pulls them apart and puts them back
   together, and each copy block brings the camera in on its own component.
   That magnification is the reason for the rebuild — no encoding setting
   recovers detail a 620px frame never captured.

   Base state, which is what you get with JS off or under reduced motion, is a
   plain two-column section: the burger fully exploded, all six blocks
   readable, nothing pinned. */
.dsx { background: var(--gold); }
.dsx__stage {
  width: min(100% - var(--pad) * 2, var(--wrap)); margin-inline: auto;
  padding-block: clamp(3.5rem, 8vh, 5.5rem);
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 4rem); align-items: center;
}
/* RTL: grid column 1 is the RIGHT-hand column. The brief asks for the burger
   on the right and the copy on the left, so the visual takes column 1 while
   the copy keeps its natural first position in the DOM for reading order. */
.dsx__vis  { grid-column: 1; grid-row: 1; }
.dsx__copy { grid-column: 2; grid-row: 1; }

/* The picture is a coordinate space, not a text layout: it holds no running
   text, and mirroring it under RTL would flip the photograph. Declaring it
   LTR lets the logical properties inside resolve to the physical axes the
   camera transform is written against. */
.dsx__vis { direction: ltr; }
.dsx__cam { width: min(100%, 400px); margin-inline: auto; }
.dsx__frame { position: relative; aspect-ratio: 2071 / 3550; }

/* Every layer was cropped to the same width, so its place in the frame is
   purely vertical and its height follows from its own aspect ratio. --dy is
   how far it sits when the burger is assembled, as a share of its own height;
   --k is the playhead, 0 apart and 1 together. */
.dsx__l {
  position: absolute; inset-inline: 0; inset-block-start: var(--y);
  inline-size: 100%; block-size: auto;
  /* --k is the playhead; --sh is the extra push a layer takes while a
     different component is being explained, in frame units, so that nothing
     but the focused component is left in the shot. */
  transform: translateY(calc(var(--dy, 0%) * var(--k, 0) + var(--sh, 0px)));
}
/* An ingredient resting on another occludes it where they meet, so the stack
   paints bottom-up: the base bun furthest back, the top bun in front. Without
   this the bun would be painted over the cheddar and cut its drip off flat. */
.dsx__l[data-l="0"] { z-index: 7; }
.dsx__l[data-l="1"] { z-index: 6; }
.dsx__l[data-l="2"] { z-index: 5; }
.dsx__l[data-l="3"] { z-index: 4; }
.dsx__l[data-l="4"] { z-index: 3; }
.dsx__l[data-l="5"] { z-index: 2; }
.dsx__l[data-l="6"] { z-index: 1; }

.dsx__count { display: flex; align-items: center; gap: .4rem; margin-block-end: 1.4rem; }
.dsx__count i { width: 1.5rem; height: 3px; border-radius: 2px; background: var(--rule); transition: background .35s var(--ease); }
.dsx__count i.is-on { background: var(--burg); }
:where(html:not(.scenes)) .dsx__count { display: none; }

.layer { padding-block: 1.3rem; border-block-start: 2px solid var(--rule); }
/* Beats `.layer p` below, which would otherwise take the step label's colour
   with it and leave the only wayfinding on the section reading as body copy. */
.layer .layer__n {
  display: block; margin-block-end: .6rem;
  font-size: .84rem; color: var(--burg);
}
.layer h3 { font-size: var(--t-h3); margin-block-end: .6rem; }
.layer p { max-width: 44ch; color: var(--ink-2); }

/* The live presentation: the section grows tall, the stage pins, the copy
   sits over the ground on the left and the burger fills the stage on the
   right. Gated on .is-live, which JS adds only once the layers have actually
   decoded — otherwise this would pin a dead zone for six viewports. */
.scenes .dsx.is-live { position: relative; height: 720vh; }
.scenes .dsx.is-live .dsx__stage {
  position: sticky; inset-block-start: 0;
  display: block; width: 100%; max-width: none;
  height: 100vh; padding: 0; overflow: hidden;
}
/* Both children are positioned, so without this the later one in the DOM —
   the picture — would paint over the copy. It does not overlap on a wide
   screen, but on a narrow one the copy's band sits right across the burger. */
.scenes .dsx.is-live .dsx__vis { position: absolute; inset: 0; z-index: 0; }
.scenes .dsx.is-live .dsx__copy { z-index: 1; }
/* The width is set by JS, to the widest the frame is ever painted at this
   viewport — NOT to the cut-outs' own 2071px. This element is a promoted
   compositor layer, and laying it out at the source width made its texture
   exceed the 4096px-a-side cap phones commonly have: the raster scale was
   clamped and the burger came back blurry and pixelated. Never hard-code a
   width here, and never restore the source width. */
.scenes .dsx.is-live .dsx__cam {
  position: absolute; inset-block-start: 0; inset-inline-start: 0;
  max-width: none; margin: 0;
  transform-origin: 0 0; will-change: transform;
}
/* Bare ground, no panel. The enamel panel existed only because at §8.3's fill
   framing the burger ran behind the copy and needed a surface to disappear
   behind. §9.2 scales every component to FIT the free area instead, so the
   frame never reaches the copy and there is nothing to hide — the text sits on
   the page's own ground. */
.scenes .dsx.is-live .dsx__copy {
  position: absolute; inset-block: 0; inset-inline-end: 0;
  width: min(46%, 31rem); padding-inline: var(--pad);
  display: flex; flex-direction: column; justify-content: center;
}
/* The blocks are absolutely positioned on top of one another, so this reserves
   the height of the tallest. It came down with §9.2's one-sentence
   descriptions — at the old 16rem the shortened copy left 78px of dead space
   below it, which pushed the whole column off centre. */
.scenes .dsx.is-live .dsx__stack { position: relative; min-height: 10rem; }
.scenes .dsx.is-live .layer {
  position: absolute; inset-inline: 0; inset-block-start: 0;
  border-block-start: none; padding-block: 0;
  opacity: 0; transform: translateY(1.1rem);
  transition: opacity .5s var(--ease), transform .5s var(--ease);
  pointer-events: none;
}
.scenes .dsx.is-live .layer.is-on { opacity: 1; transform: none; pointer-events: auto; }

/* ── Annotation leader ────────────────────────────────────────────────────
   §9.2. A thin rule from the text block across to the component it names,
   with a dot where it lands on the food's leading edge.

   THIS IS THE ONE NAMED EXCEPTION to §6's "no black keylines" rule, and it is
   recorded there by name so it never reads as a regression. That rule is aimed
   at outlines AROUND BLOCKS — the device that made the rejected neobrutalist
   build read the way it did. An annotation pointing at a photograph is a
   different thing, and it is drawn in --ink (#2A1A16), not black.

   Every number here comes from JS on the same frame as the camera, so the
   leader tracks the component rather than trailing it. It lives inside
   .dsx__vis, which is direction: ltr, so inset-inline-start is the physical
   left the camera transform is written against. Absent entirely with JS off
   and under reduced motion, like everything else camera-driven here. */
.dsx__lead { display: none; }
.scenes .dsx.is-live .dsx__lead {
  display: block; position: absolute; z-index: 8; pointer-events: none;
  inset-inline-start: var(--lx, 0);
  inset-block-start: var(--ly, 0);
  width: var(--lw, 0); height: 2px; margin-block-start: -1px;
  background: var(--ink); opacity: var(--lo, 0);
}
/* The dot sits centred on the far end of the rule, so it lands ON the edge it
   is pointing at rather than beside it. */
.dsx__lead::after {
  content: ''; position: absolute;
  inset-inline-end: 0; inset-block-start: 50%;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--ink); transform: translate(50%, -50%);
}

@media (max-width: 900px) {
  /* No leader on a narrow screen: the copy is a band directly under the
     picture there, so a horizontal rule from it would have nothing to cross
     and nothing to disambiguate. */
  .scenes .dsx.is-live .dsx__lead { display: none; }
  .dsx__stage { grid-template-columns: 1fr; gap: 1.5rem; }
  .dsx__vis, .dsx__copy { grid-column: 1; }
  .dsx__vis { grid-row: 1; }
  .dsx__copy { grid-row: 2; }
  .dsx__cam { width: min(100%, 260px); }
  .scenes .dsx.is-live { height: 620vh; }
  .scenes .dsx.is-live .dsx__stage { height: 100svh; }
  /* The burger sits high and the copy takes a solid band at the foot, so
     text never lands on the photograph. A flat block, not a fade. */
  .scenes .dsx.is-live .dsx__copy {
    inset-block: auto 0; width: 100%; padding-block: 1.25rem 1.5rem;
    background: var(--gold); border-block-start: 2px solid var(--rule);
    justify-content: flex-end;
  }
  /* Below 760px the dock is pinned to the foot of the window and this is the
     one section whose copy runs down to meet it, so reserve its height. The
     ribbon would need another 5rem on top of that, which would push the
     picture into the top of the viewport — it steps aside instead (see
     .dsx-live below); it is available on every other screen of the page. */
  @media (max-width: 760px) {
    .scenes .dsx.is-live .dsx__copy { padding-block-end: 4.75rem; }
  }
  /* §9.3 — the band shrinks with the one-sentence descriptions, which is what
     lets the copy sit lower on the screen and leaves the picture more height
     above it. JS reads this back off the live element, so it does not need to
     know the number. */
  .scenes .dsx.is-live .dsx__stack { min-height: 9.5rem; }
}

/* ═══ Menu rail ═══════════════════════════════════════════════════════════ */
.railwrap { position: relative; }
.rail {
  display: flex; gap: clamp(1.25rem, 2.5vw, 2rem);
  overflow-x: auto; scroll-snap-type: x mandatory;
  padding: .5rem var(--pad) 2rem;
  margin-inline: calc(var(--pad) * -1);
  scrollbar-width: none; cursor: grab;
}
.rail::-webkit-scrollbar { display: none; }
.rail.is-drag { cursor: grabbing; scroll-snap-type: none; }

.card {
  flex: 0 0 clamp(230px, 68vw, 300px); scroll-snap-align: start;
  background: var(--panel); border-radius: var(--r); overflow: hidden;
}
.card img {
  width: 100%; aspect-ratio: 1; object-fit: contain;
  padding: 1rem;
  transition: transform .4s var(--ease);
}
.card:hover img { transform: scale(1.04); }
.card__b { padding: 0 1.15rem 1.25rem; }
.card__top { display: flex; justify-content: space-between; align-items: baseline; gap: .75rem; }
.card h3 { font-size: 1.3rem; }
.card__price { font-weight: 700; font-size: 1.05rem; white-space: nowrap; color: var(--burg); }
.card p { font-size: var(--t-sm); margin-block-start: .55rem; color: var(--ink-2); }
.card__tag {
  display: inline-block; margin-block-start: .85rem;
  background: var(--gold); border-radius: 999px; padding: .3rem .7rem;
}

.railctl { display: flex; gap: .5rem; }
.arw {
  width: 46px; height: 46px; background: var(--panel);
  border: none; border-radius: 999px;
  cursor: pointer; display: grid; place-items: center; color: var(--ink);
  transition: background .2s var(--ease), color .2s var(--ease);
}
.arw:hover { background: var(--burg); color: #fff; }
.arw svg { width: 18px; height: 18px; }
.arw[disabled] { opacity: .35; cursor: default; }
.arw[disabled]:hover { background: var(--panel); color: var(--ink); }

/* ═══ Sides ═══════════════════════════════════════════════════════════════ */
.sides { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(1.25rem, 3vw, 2rem); }
.side {
  display: flex; align-items: center; gap: 1.25rem;
  background: var(--panel); border-radius: var(--r); padding: 1rem 1.25rem;
}
.side img {
  width: clamp(90px, 14vw, 130px); aspect-ratio: 1; object-fit: contain; flex: none;
}
.side h3 { font-size: 1.25rem; margin-block-end: .3rem; }
.side p { font-size: var(--t-sm); color: var(--ink-2); }
.side b { color: var(--burg); font-weight: 700; }
@media (max-width: 760px) { .sides { grid-template-columns: 1fr; } }

/* ═══ Proof ═══════════════════════════════════════════════════════════════
   §3.3 — the stat label was 11px, tracked out to .18em and set in a muted
   tone on near-black, three ways of being hard to read at once. It is now
   15px, barely tracked, semibold and at full contrast on a panel tile, with a
   larger numeral above it. */
.stats {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2.5vw, 1.75rem); margin-block-end: clamp(2.5rem, 6vh, 4rem);
}
.stat {
  background: var(--panel); border-radius: var(--r);
  padding: clamp(1.25rem, 3vw, 1.9rem);
}
/* The three tiles arrive one after another rather than together, and the
   figures count up to their values — see main.js. Both are gated on .scenes,
   so under reduced motion or with JS off the tiles are simply there with the
   final numbers already set. */
.scenes .stats .stat { transform: translateY(1.4rem) scale(.97); }
.scenes .stats .stat.is-in {
  transform: none;
  transition: opacity .7s var(--ease-out), transform .7s var(--ease-out);
  transition-delay: calc(var(--i, 0) * 110ms);
}
.stat > b { font-variant-numeric: tabular-nums; }
/* Direct children only: every numeral here wraps its digits in .ltr for bidi
   isolation, and a bare `.stat span` would capture that inner span too and
   set the figure at label size. */
.stat > b {
  display: block; font-family: 'Suez', serif; font-weight: 400; color: var(--burg);
  font-size: clamp(2.4rem, 5.5vw, 3.6rem); line-height: 1;
  margin-block-end: .45rem;
}
.stat > span {
  display: block; font-size: .9375rem; font-weight: 600;
  letter-spacing: .01em; color: var(--ink);
}

.quotes { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.5rem, 3.5vw, 3rem); }
.quote p {
  font-family: 'Suez', serif; font-weight: 400; color: var(--cream);
  font-size: 1.2rem; line-height: 1.5; letter-spacing: -.005em;
}
.quote footer { margin-block-start: 1rem; font-size: var(--t-sm); font-weight: 600; color: var(--on-dark-2); }
.quote__s { color: var(--mustard); font-size: .95rem; letter-spacing: .2em; margin-block-end: .85rem; font-family: 'Rubik', sans-serif !important; }

@media (max-width: 900px) {
  .stats { grid-template-columns: 1fr; }
  .quotes { grid-template-columns: 1fr; }
}

/* ═══ Place ═══════════════════════════════════════════════════════════════ */
.place { display: grid; grid-template-columns: 1.2fr .8fr; gap: clamp(1rem, 2.5vw, 1.75rem); align-items: start; }
.place img { width: 100%; border-radius: var(--r); }
.place__pair { display: grid; gap: clamp(1rem, 2.5vw, 1.75rem); }
@media (max-width: 900px) { .place { grid-template-columns: 1fr; } }

/* ═══ Order ═══════════════════════════════════════════════════════════════ */
.order { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2rem, 5vw, 4rem); }
.hours { border-block-start: 1px solid var(--rule-dark); }
.hours li {
  display: flex; justify-content: space-between; gap: 1rem;
  padding-block: .9rem; border-block-end: 1px solid var(--rule-dark);
  color: #fff;
}
.hours b { font-weight: 600; }
.slab--teal .btn { background: var(--cream); color: var(--ink); }
.slab--teal .btn:hover { background: var(--burg); color: #fff; }
.slab--teal .btn--ghost {
  background: transparent; color: #fff; border-block-end-color: var(--cream);
}
.slab--teal .btn--ghost:hover { background: transparent; color: var(--cream); }
@media (max-width: 900px) { .order { grid-template-columns: 1fr; } }

/* ═══ Footer ══════════════════════════════════════════════════════════════ */
.foot { background: var(--ink); color: var(--on-dark-2); padding-block: clamp(3rem, 7vh, 4.5rem) 2rem; }
.foot__t { display: flex; flex-wrap: wrap; gap: 1.5rem; justify-content: space-between; align-items: center; }
.foot .brand b { color: var(--cream); }
.foot .brand span span { color: var(--mustard); }
.foot__n { display: flex; flex-wrap: wrap; gap: 1.5rem; }
.foot__n a { text-decoration: none; font-size: var(--t-sm); }
.foot__n a:hover { color: var(--cream); }

.demo-note {
  margin-block: 2.5rem; padding-block: 1.4rem;
  border-block: 1px solid var(--rule-dark);
  font-size: var(--t-sm);
}
.demo-note b { color: var(--cream); font-weight: 600; }
.foot__b { display: flex; flex-wrap: wrap; gap: .75rem; justify-content: space-between; font-size: var(--t-sm); }
.foot__b a { color: var(--mustard); }

/* Back to the parent site. */
.ribbon {
  position: fixed; inset-block-end: 1.15rem; inset-inline-start: 1.15rem; z-index: 90;
  display: inline-flex; align-items: center; gap: .5rem;
  background: var(--panel); color: var(--ink);
  border-radius: 999px;
  padding: .6rem 1rem; text-decoration: none; font-size: var(--t-sm); font-weight: 500;
  white-space: nowrap;
  transition: background .2s var(--ease), color .2s var(--ease);
}
.ribbon:hover { background: var(--burg); color: #fff; }
.ribbon svg { width: 15px; height: 15px; }
/* On a narrow screen the dissection's copy occupies the foot of the window for
   six viewports of scrolling, and the ribbon would sit on top of it. It
   retires while that section holds the screen and comes back after. */
@media (max-width: 900px) {
  .dsx-live .ribbon { transform: translateY(200%); pointer-events: none; }
}

.dock {
  position: fixed; inset-block-end: 0; inset-inline: 0; z-index: 95;
  display: none; gap: .6rem; padding: .7rem;
  background: var(--gold);
  background: color-mix(in srgb, var(--gold) 94%, transparent);
  backdrop-filter: blur(10px);
  border-block-start: 1px solid var(--rule);
  transform: translateY(110%); transition: transform .35s var(--ease);
}
.dock.is-on { transform: none; }
.dock .btn { flex: 1; justify-content: center; }
@media (max-width: 760px) {
  .dock { display: flex; }
  .ribbon { inset-block-end: 5.2rem; }
}

/* ═══ Motion ══════════════════════════════════════════════════════════════
   Everything below only ever runs behind .scenes, which JS adds when motion
   is allowed. Without it every element sits at its finished value. */
.scenes .reveal { opacity: 0; transform: translateY(1.4rem); }
.scenes .reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity .8s var(--ease-out), transform .8s var(--ease-out);
}
.scenes [data-split] .w { display: inline-block; opacity: 0; transform: translateY(.5em); }
.scenes [data-split].is-in .w {
  opacity: 1; transform: none;
  transition: opacity .6s var(--ease-out), transform .6s var(--ease-out);
  transition-delay: calc(var(--i) * 40ms);
}

@media (prefers-reduced-motion: reduce) {
  .hero__burger.is-float img { animation: none; }
  *, *::before, *::after {
    animation-duration: .01ms !important; animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}
