/* ==========================================================================
   MARROW — brand layer. RiNo, Denver. Wood-fire cooking.
   Register: dense, ruled, editorial — a printed menu, not a poster.
   Warm cream ground (light-first), green + gold, Cardo over Hanken Grotesk.
   Signature element: "the fire rule" (.rule-head) — a 1px gold hairline the
   full content measure, an 11px +0.22em eyebrow sitting ON the rule (ground
   behind it so the rule breaks around it), and a 10px gold tick standing at
   the rule's left end. Six or more per page. Built once, here, only.

   Hairlines carry all elevation. Shadows exist ONLY on the drawer and the
   reserve dialog. Zero filter: on any photograph. No pure #000/#FFF.
   Breakpoints: min-width only — 640 / 768 / 1024 / 1280. Never 100vh.

   CONTRAST — computed numerically (scratch script: OKLCH→sRGB, WCAG 2.x),
   both themes. Every pair verified before ship:

   LIGHT (cream)                                ratio    needs
     fg on bg                                   15.64    4.5   PASS
     fg on surface                              16.48    4.5   PASS
     fg on surface-2                            14.38    4.5   PASS
     muted (fg 70%) on bg                        6.12    4.5   PASS
     muted (fg 70%) on surface                   6.27    4.5   PASS
     accent as ink on bg                         8.57    4.5   PASS
     accent-fg (surface) on accent fill          9.03    4.5   PASS
     accent hover fill vs accent-fg             10.06    4.5   PASS
     on-deep fg (cream) on deep                 12.93    4.5   PASS
     on-deep muted (cream 80%) on deep           8.81    4.5   PASS
     accent-text on deep (dark-accent value)     6.45    4.5   PASS
     gold on bg (rules/ticks — non-text)         3.84    3.0   PASS
     gold-text (gold 60% + fg) on bg             7.07    3.0   PASS
     danger on bg / on surface             7.85 / 8.27    4.5   PASS
     border-strong (fg 52%) vs surface           3.51    3.0   PASS
     focus (accent) vs bg                        8.57    3.0   PASS
   DARK (a room after service)
     fg on bg / surface / surface-2  14.99 / 13.86 / 12.57  4.5  PASS
     muted (fg 72%) on bg                        8.15    4.5   PASS
     accent as ink on bg                         8.22    4.5   PASS
     accent-fg (bg) on accent fill               8.22    4.5   PASS
     accent hover fill vs accent-fg              9.04    4.5   PASS
     fg on deep                                 15.97    4.5   PASS
     gold on bg (may carry large text)           7.42    3.0   PASS
     danger on bg / on surface             6.99 / 6.46    4.5   PASS
     border-strong (fg 50%) vs surface           4.42    3.0   PASS
     focus (accent) vs bg                        8.22    3.0   PASS

   Raw gold (L 58%) is 3.84:1 on cream — rules and ticks only; where gold must
   carry text in the light theme, use --gold-text (7.07:1, large text per
   §C.1: ≥24px only). theme-color: light #F7F2E5 · dark #0F1610.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS — OKLCH, light authored first; dark is a second designed palette
   -------------------------------------------------------------------------- */
:root {
  color-scheme: light dark;

  /* Six brand colours, no more */
  --bg: oklch(96.2% 0.018 92);         /* cream */
  --surface: oklch(98% 0.012 92);      /* warm paper */
  --surface-2: oklch(93.4% 0.021 90);  /* deeper cream */
  --fg: oklch(21.5% 0.016 145);        /* green-black ink */
  --deep: oklch(28% 0.03 152);         /* pine ground — dark sections */
  --accent: oklch(38.5% 0.055 150);    /* deep pine — the one action colour */
  --gold: oklch(58% 0.07 88);          /* rules, ticks, non-text */

  /* Derivations — alpha ramp on --fg, never separate greys */
  --muted: color-mix(in oklab, var(--fg) 70%, transparent);
  --fg-soft: color-mix(in oklab, var(--fg) 85%, transparent);
  --border: color-mix(in oklab, var(--fg) 16%, transparent);
  --border-strong: color-mix(in oklab, var(--fg) 52%, transparent);
  --accent-fg: var(--surface);
  --accent-text: var(--accent);
  --btn-bg-hover: color-mix(in oklch, var(--accent) 85%, var(--fg));
  --gold-text: color-mix(in oklch, var(--gold) 60%, var(--fg)); /* large text only */
  --focus: var(--accent);
  --danger: oklch(43% 0.15 27);
  --on-deep-fg: oklch(96.2% 0.018 92);
  --ground: var(--bg);                 /* what .rule-head labels mask against */

  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' fill='none'%3E%3Cpath d='M1 1l6 6 6-6' stroke='%23595c53' stroke-width='1' stroke-linecap='round'/%3E%3C/svg%3E");

  /* Hairline site: card shadows off; the two permitted shadows are local */
  --shadow-card: none;
  --shadow-pop: none;
  --shadow-modal: 0 24px 64px -16px oklch(21.5% 0.016 145 / 0.4);

  /* Chrome — 64px mobile header / 72px desktop (§J); bar 64px + 10px + inset */
  --header-h: 4rem;
  --header-h-sm: 3.5rem;
  --cta-h: 4.25rem;
  --jump-nav-h: 3rem;

  /* Type — the restrained register. Hero 34px → 56px. Nothing exceeds 64px. */
  --t-eyebrow: 0.6875rem;                                    /* 11px */
  --t-h1: clamp(2.125rem, 1.667rem + 2.037vw, 3.5rem);       /* 34 → 56 */
  --t-display: var(--t-h1);
  --t-h2: clamp(1.5rem, 1.292rem + 0.926vw, 2.125rem);       /* 24 → 34 */
  --t-h3: clamp(1.1875rem, 1.125rem + 0.278vw, 1.375rem);    /* 19 → 22 */
  --lh-body: 1.62;                                           /* editorial */
  --lh-h1: 1.02;
  --lh-h2: 1.12;
  --lh-h3: 1.25;
  --tr-h1: -0.022em;                                         /* Cardo display */
  --tr-h2: -0.022em;
  --tr-h3: -0.01em;
  --tr-eyebrow: 0.22em;                                      /* 11px caps */
  --tr-caps: 0.08em;                                         /* course headers */

  /* Desktop container (§K): 1440 cap */
  --w-wide: 90rem;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: oklch(19% 0.014 150);
    --surface: oklch(22.5% 0.016 150);
    --surface-2: oklch(26% 0.018 150);
    --fg: oklch(93% 0.014 92);
    --deep: oklch(15% 0.022 152);
    --accent: oklch(74% 0.075 148);
    --gold: oklch(72% 0.07 88);
    --muted: color-mix(in oklab, var(--fg) 72%, transparent);
    --border: color-mix(in oklab, var(--fg) 18%, transparent);
    --border-strong: color-mix(in oklab, var(--fg) 50%, transparent);
    --accent-fg: oklch(19% 0.014 150);
    --gold-text: var(--gold);
    --danger: oklch(72% 0.14 25);
    --on-deep-fg: oklch(93% 0.014 92);
    --shadow-modal: 0 24px 64px -12px oklch(0% 0 0 / 0.55);
    --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' fill='none'%3E%3Cpath d='M1 1l6 6 6-6' stroke='%23aeada4' stroke-width='1' stroke-linecap='round'/%3E%3C/svg%3E");
  }
}
[data-theme="dark"] {
  --bg: oklch(19% 0.014 150);
  --surface: oklch(22.5% 0.016 150);
  --surface-2: oklch(26% 0.018 150);
  --fg: oklch(93% 0.014 92);
  --deep: oklch(15% 0.022 152);
  --accent: oklch(74% 0.075 148);
  --gold: oklch(72% 0.07 88);
  --muted: color-mix(in oklab, var(--fg) 72%, transparent);
  --border: color-mix(in oklab, var(--fg) 18%, transparent);
  --border-strong: color-mix(in oklab, var(--fg) 50%, transparent);
  --accent-fg: oklch(19% 0.014 150);
  --gold-text: var(--gold);
  --danger: oklch(72% 0.14 25);
  --on-deep-fg: oklch(93% 0.014 92);
  --shadow-modal: 0 24px 64px -12px oklch(0% 0 0 / 0.55);
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' fill='none'%3E%3Cpath d='M1 1l6 6 6-6' stroke='%23aeada4' stroke-width='1' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   2. TYPE — Cardo 400 (+ italic) for display and dish names; Hanken for
   everything read, priced, or pressed. Tabular numerals on every figure.
   -------------------------------------------------------------------------- */
body {
  font-weight: 400;
  letter-spacing: 0.02em;       /* Hanken body */
  background: var(--bg);
}
h1, h2, h3 {
  font-family: var(--font-display, Georgia, serif);
  font-weight: 400;
}
h1 { letter-spacing: var(--tr-h1); }
h2 { letter-spacing: var(--tr-h2); }
strong { font-weight: 600; }

.eyebrow {
  font-size: var(--t-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tr-eyebrow);
  color: var(--muted);
}

/* Content links: class-less anchors inside main read as editorial links */
main a:not([class]) {
  color: var(--accent-text);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
@media (hover: hover) and (pointer: fine) {
  main a:not([class]):hover { text-decoration-thickness: 2px; }
}

/* Tabular numerals — every price, hours figure, capacity, pay range */
.price, .variant, .supplement, .pay-range, .stat, .figure,
.hours, .open-badge, time { font-variant-numeric: tabular-nums; }

/* 42–44ch measure inside the wide container — cap the measure, not the box */
@media (min-width: 768px) { .measure { max-width: 44ch; } }

/* --------------------------------------------------------------------------
   3. THE FIRE RULE — .rule-head. The identity. Six or more per page.
   -------------------------------------------------------------------------- */
.rule-head {
  position: relative;
  margin-block-end: var(--sp-6);
}
.rule-head::before {                 /* the hairline, full content measure */
  content: "";
  position: absolute;
  inset-inline: 0;
  top: calc(50% - 0.5px);
  border-block-start: 1px solid var(--gold);
}
.rule-head::after {                  /* the tick, standing at the left end */
  content: "";
  position: absolute;
  left: 0;
  bottom: 50%;
  width: 2px;
  height: 10px;
  background: var(--gold);
}
.rule-head > * {                     /* the eyebrow, sitting ON the rule */
  position: relative;
  z-index: 1;
  display: inline-block;
  margin: 0 0 0 1.75rem;
  padding-inline: 0.625rem;
  background: var(--ground);
  font-family: var(--font-body, system-ui, sans-serif);
  font-size: var(--t-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tr-eyebrow);
  line-height: 1.7;
  text-transform: uppercase;
  text-wrap: nowrap;
  color: var(--fg);
}
/* Course variant: the label is the course <h2> itself, caps at +0.08em.
   The eyebrow's nowrap is right for a one-word label but wrong here — a course
   title like "From the hearth, at the bar" is 303px of caps at +0.08em and
   overflowed a 280px column by 23px. It wraps; the hairline still breaks around
   it because the label paints its own ground. */
.rule-head--course > * {
  font-size: 0.9375rem;
  letter-spacing: var(--tr-caps);
  text-wrap: balance;
  max-inline-size: calc(100% - 1.75rem);
}

/* --------------------------------------------------------------------------
   4. HEADER — 64px mobile / 72px desktop, wordmark · badge · Book · Menu
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) { :root { --header-h: 4.5rem; } }

.wordmark {
  font-family: var(--font-display, Georgia, serif);
  font-size: 1.4375rem;
  font-weight: 400;
  letter-spacing: 0.01em;
}

.open-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--muted);
}
.open-badge::before {
  content: "";
  flex: none;
  inline-size: 6px;
  block-size: 6px;
  border-radius: 50%;
  background: var(--border-strong);
}
.open-badge[data-state="open"] { color: var(--accent-text); }
.open-badge[data-state="open"]::before { background: var(--accent); }
.open-badge a {
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
  color: inherit;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The badge sits beside the wordmark; it takes over the auto-margin the
   base header puts on the logo, and shrinks (ellipsis) before anything else */
.header-inner .logo { margin-inline-end: 0; flex: 0 0 auto; }

/* base.css ships a second header nav (.nav-visible) for the mid breakpoint.
   Marrow does not use it: the header already carries the wordmark, the open-now
   badge, Book and the hamburger, and two more links overflowed the row by
   ~104px at 360 and 390, the two commonest phone widths. It also duplicated
   aria-label="Primary" with .nav-desktop — two Primary landmarks per page. The
   markup is removed from all 13 pages; the long tail lives in the drawer and
   the high-frequency jobs in the bottom bar, per the hybrid nav in §J. This
   rule stays as a guard in case the shared chrome reintroduces it. */
.nav-visible { display: none; }

/* Two-row header below 1024px. Four items cannot share one 320px row: the
   wordmark, the badge, Book and the hamburger need ~372px, so flex-shrink was
   crushing the open-now badge to 0 and squeezing the hamburger below its own
   content. §J allows the badge "under or beside the wordmark" — under it is,
   at the 64px mobile / 72px desktop height §J actually specifies (base.css
   ships 56px, so that number had never been applied).

   Row 1: wordmark | Book | hamburger.   Row 2: the badge, full width. */
:root { --header-h: 4.5rem; --header-h-sm: 4.5rem; }

.header-inner {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  grid-template-rows: auto auto;
  align-items: center;
  column-gap: var(--sp-2);
  row-gap: 2px;
}
/* SC 2.4.11. ui.js hides the sticky header on scroll-down. If the user then
   Shift-Tabs back up into it, the focused control sits off the top of the
   viewport and cannot be scrolled into view, because a sticky element does not
   move. Focus inside the header always brings it back. */
.site-header:focus-within[data-hidden] { transform: none; }

.header-inner .logo      { grid-area: 1 / 1 / 2 / 3; min-height: 2.75rem; }
.header-inner .open-badge{ grid-area: 2 / 1 / 3 / 5; margin: 0; min-inline-size: 0; overflow: hidden; }
.header-inner .btn       { grid-area: 1 / 3 / 2 / 4; min-height: 2.75rem; }
.header-inner .menu-btn  { grid-area: 1 / 4 / 2 / 5; }

/* The badge's link is 24px tall — SC 2.5.8's floor, not the house 44px. It
   qualifies under the criterion's *equivalent control* exception: the drawer's
   "Visit" link reaches the same /location/rino/#hours destination at full size
   on the same page. Growing it to 44px would push the mobile header past 90px,
   which costs more than it buys on a 667px-tall phone. */
.header-inner .open-badge a { min-block-size: 24px; }

@media (min-width: 1024px) {
  /* Desktop returns to a single row; the badge sits beside the wordmark. */
  .header-inner {
    display: flex;
    align-items: center;
    column-gap: var(--sp-3);
  }
  .header-inner .open-badge { margin-inline-end: auto; flex: 0 1 auto; }
  .header-inner .open-badge a { min-block-size: 44px; }
  .header-inner .btn { min-height: 3rem; }
  /* base.css sizes .nav-visible links to 44px but not .nav-desktop, which is
     the nav that actually renders here. The 72px header has room for it. */
  .nav-desktop a {
    display: inline-flex;
    align-items: center;
    min-block-size: 2.75rem;
    min-inline-size: 2.75rem;
    justify-content: center;
    padding-inline: var(--sp-3);   /* "Visit" is only 36px of text on its own */
  }
}

.header-inner .btn { min-height: 3rem; padding-inline: var(--sp-4); }

.theme-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 48px;
  min-height: 48px;
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  color: var(--muted);
  touch-action: manipulation;
}
/* nth-of-type, not first/last-child: the drawer variant carries a text label
   after the two icons, which would otherwise steal :last-child. */
.theme-btn svg:nth-of-type(2) { display: none; }
[data-theme="dark"] .theme-btn svg:nth-of-type(1) { display: none; }
[data-theme="dark"] .theme-btn svg:nth-of-type(2) { display: block; }

/* The toggle lives in the drawer, not the header row — it is the lowest
   frequency control in the chrome, and the header cannot seat five items at
   320px without crushing the open-now badge. In the drawer it has room for a
   real label. */
.theme-btn--drawer {
  inline-size: 100%;
  justify-content: flex-start;
  gap: var(--sp-3);
  padding-inline: var(--sp-4);
  min-block-size: 3rem;
  color: var(--fg);
  font-size: 1rem;
  font-weight: 650;
}
.theme-btn__label { flex: 1 1 auto; text-align: start; }
@media (hover: hover) and (pointer: fine) {
  .theme-btn:hover { color: var(--fg); background: var(--surface-2); }
}

/* --------------------------------------------------------------------------
   5. BUTTONS — rectangular, ruled, restrained
   -------------------------------------------------------------------------- */
.btn {
  border-radius: var(--r-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
}
.btn--outline { border-width: 1px; }

/* --------------------------------------------------------------------------
   6. BOTTOM ACTION BAR (§J) — Book · Menu · Directions. Opaque. 64px.
   Ships hidden (data-hidden IN THE MARKUP) so first paint never covers the
   hero and costs no CLS; js/ui.js reveals it after ~1 viewport. display:none
   at ≥1024px — but present between 768–1023, so body padding is restored
   there against base.css's 768 reset.
   -------------------------------------------------------------------------- */
.cta-bar {
  min-block-size: 4rem;                      /* 64px */
  padding-block-start: var(--sp-2);
  padding-block-end: calc(10px + env(safe-area-inset-bottom, 0px));
  padding-inline: max(var(--sp-4), env(safe-area-inset-left))
                  max(var(--sp-4), env(safe-area-inset-right));
  background: var(--surface);                /* opaque — never blur over food */
  border-top: 1px solid var(--border);
  /* base.css sets grid-auto-columns: 1fr, which is really minmax(auto, 1fr) —
     the auto floor is min-content, so "Directions" refuses to shrink and pushes
     the third action 19px past the viewport at 320px. minmax(0, 1fr) removes the
     floor; the label then scales instead of overflowing. */
  grid-auto-columns: minmax(0, 1fr);
}
.cta-bar .btn {
  min-inline-size: 0;
  padding-inline: var(--sp-2);
  font-size: clamp(0.8125rem, 3.2vw, 1rem);
  white-space: nowrap;
}
@media (min-width: 768px) {
  .cta-bar { display: grid; }
  body { padding-bottom: calc(var(--cta-h) + env(safe-area-inset-bottom)); }
  html { scroll-padding-bottom: calc(var(--cta-h) + env(safe-area-inset-bottom) + var(--sp-4)); }
}
@media (min-width: 1024px) {
  .cta-bar { display: none; }
  body { padding-bottom: 0; }
  html { scroll-padding-bottom: var(--sp-8); }
}

/* Anchor offsets: base.css's html scroll-padding-top (§M, SC 2.4.11) stays
   in force — it tracks --header-h, which this file resizes. Course headings
   additionally carry the §G.5 scroll-margin formula (see the menu system). */

/* --------------------------------------------------------------------------
   7. HERO — §M scrim, sized to the worst-case pixel behind the text
   -------------------------------------------------------------------------- */
.hero::after {
  background: linear-gradient(to top, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0.25) 60%, transparent);
}
.hero__content { color: var(--on-deep-fg); }
.hero__content h1 { text-shadow: none; }
.hero .eyebrow { color: color-mix(in oklab, var(--on-deep-fg) 85%, transparent); }

/* Controls over the hero photograph.
   .btn--outline inherits --fg (green-black ink) and a dark hairline, which is
   correct on cream and invisible on the hero: "See the dinner menu" shipped as
   black-on-black over a dark scrim. Over photography every control carries the
   light ink, and the border is derived from it so the 3:1 non-text minimum
   holds against the worst-case pixel the scrim is sized for. */
.hero .btn--outline {
  --btn-fg: var(--on-deep-fg);
  color: var(--on-deep-fg);
  border-color: color-mix(in oklab, var(--on-deep-fg) 62%, transparent);
}
@media (hover: hover) and (pointer: fine) {
  .hero .btn--outline:hover {
    background: color-mix(in oklab, var(--on-deep-fg) 14%, transparent);
    border-color: var(--on-deep-fg);
  }
}

/* Utility scrim for any other text-over-photo case */
.media-scrim { position: relative; isolation: isolate; }
.media-scrim::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0.25) 60%, transparent);
}
.media-scrim > * { position: relative; z-index: 1; }

/* --------------------------------------------------------------------------
   8. DEEP SECTIONS — pine ground. Local token remap keeps every derived
   colour honest on the dark ground (verified in the table above).
   -------------------------------------------------------------------------- */
.section--deep {
  background: var(--deep);
  color: var(--on-deep-fg);
  --ground: var(--deep);
  --fg: var(--on-deep-fg);
  --muted: color-mix(in oklab, var(--on-deep-fg) 80%, transparent);
  --fg-soft: color-mix(in oklab, var(--on-deep-fg) 88%, transparent);
  --border: color-mix(in oklab, var(--on-deep-fg) 22%, transparent);
  --border-strong: color-mix(in oklab, var(--on-deep-fg) 55%, transparent);
  --accent-text: oklch(74% 0.075 148);
  --gold-text: oklch(72% 0.07 88);
  --focus: var(--on-deep-fg);
  --surface: color-mix(in oklab, var(--on-deep-fg) 6%, var(--deep));
  --surface-2: color-mix(in oklab, var(--on-deep-fg) 10%, var(--deep));
}

/* Ground crossfade (motion idea 5). Static pine by default and under
   reduced motion / JS failure; js/site-motion.js flips .is-dynamic and
   drives the underlay's opacity — compositor-only.

   The underlay lives INSIDE the band and the band keeps a 70% pine floor
   while dynamic. Two reasons, both measured on a 390px phone:
   - a viewport-wide underlay darkened the ground under the neighbouring
     sections, whose dark ink then sat on pine while they shared the screen
     with the band (the essay sign-off, for ~600px of scroll);
   - a fully transparent band put its cream quote on the cream page at the
     moment of entry. On the floor the cream text never drops below 7.1:1
     (sRGB composite of 70% pine over cream), and the crossfade reads as the
     band deepening from that floor to full pine as it travels. */
.ground-shift {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--deep);
  opacity: 0;
  pointer-events: none;
}
[data-motion="ground"].is-dynamic {
  position: relative;
  isolation: isolate;           /* keeps the z-index:-1 underlay above the floor, below the content */
  background: color-mix(in oklab, var(--deep) 70%, transparent);
}

/* --------------------------------------------------------------------------
   9. MENU SYSTEM — the reason this site exists
   -------------------------------------------------------------------------- */
.menu-doc { max-width: 780px; margin-inline: auto; }

/* §G.5 permits two SECTIONS side by side on desktop (never two items — that
   breaks the vertical price scan, and each course below keeps one column of
   items). From 1024 the courses pair up like a printed menu's facing pages,
   and the notices box shares its row with the legend. */
@media (min-width: 1024px) {
  .menu-doc {
    max-width: none;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(3rem, 5vw, 5rem);
    align-items: start;
  }
  /* The preamble spans both course columns and runs its own two-column grid.
     The cadence line and the pairing drop into the LEFT column beneath the
     notices box, so the legend column no longer runs on alone beside an empty
     half. Source order is untouched — this is placement only. */
  .menu-doc > .menu-preamble {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(3rem, 5vw, 5rem);
    row-gap: var(--sp-5);
    align-items: start;
  }
  .menu-doc .menu-preamble > * + * { margin-block-start: 0; }
  .menu-preamble > .menu-notices { grid-area: 1 / 1; }
  .menu-preamble > .menu-updated { grid-area: 2 / 1; }
  .menu-preamble > .pairing      { grid-area: 3 / 1; }
  .menu-preamble > .menu-legend  { grid-area: 1 / 2 / span 3 / 3; }
}

/* The preamble owns its own spacing so the four blocks are predictable in both
   layouts. The top padding is what keeps the legend clear of the sticky course
   rail sitting directly above it. */
.menu-preamble {
  padding-block-start: var(--sp-6);
  margin-block-end: var(--sp-10);
}
/* Two classes deep so it beats the blocks' own margins, which are declared
   later in this file and would otherwise add slack the grid cannot see. */
.menu-doc .menu-preamble > * { margin-block: 0; }
.menu-doc .menu-preamble > * + * { margin-block-start: var(--sp-5); }

/* Notices sit adjacent to the prices, at the top — never in the footer */
.menu-notices {
  display: grid;
  gap: var(--sp-2);
  padding: var(--sp-4) var(--sp-5);
  border: 1px solid var(--border);
  border-left: 2px solid var(--gold);
  border-radius: var(--r-xs);
  background: var(--surface);
  margin-block-end: var(--sp-6);
}
.notice { font-size: var(--t-sm); }

.menu-legend { display: grid; gap: var(--sp-3); margin-block-end: var(--sp-10); }
.menu-legend__title { font-size: var(--t-sm); color: var(--muted); }
.legend-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.chip {
  display: inline-block;
  padding: 0.1875rem 0.5rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-xs);
  font-family: var(--font-body, system-ui, sans-serif);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--muted);
  white-space: nowrap;
}
.capability { font-size: var(--t-sm); color: var(--muted); max-width: 62ch; }
.menu-updated, .pairing { font-size: var(--t-sm); color: var(--muted); }
.menu-note { font-size: var(--t-sm); font-style: italic; color: var(--muted); margin-block-end: var(--sp-6); }

/* Courses. Sticky headers on mobile; static from 1024. */
.course { padding-block-end: var(--sp-10); }
.course-head {
  position: sticky;
  top: calc(var(--header-h) + var(--jump-nav-h));
  z-index: 20;
  background: var(--ground);
  padding-block: var(--sp-3);
  margin-block-end: var(--sp-4);
}
/* `relative`, NOT `static`: .rule-head::before/::after are absolutely
   positioned, so a static course header sends its hairline to the initial
   containing block. All five then stacked into one stray gold line across the
   middle of the viewport, and every course lost its rule. Un-sticking the
   header only needs the position value to stop being `sticky`. */
/* `top: auto` as well: a relative element still honours the sticky offset's
   `top: 120px` and every course header rendered 120px down, over its own
   items. Un-sticking needs both declarations. */
@media (min-width: 1024px) { .course-head { position: relative; top: auto; padding-block: 0 var(--sp-2); } }
.course, .course-title {
  scroll-margin-top: calc(var(--header-h) + var(--jump-nav-h) + 16px);
}

/* Items: ONE column at every width. Name+price share a flex row; the
   description is a full-width sibling below. No dot leaders anywhere. */
.menu-items { display: grid; gap: var(--sp-6); }
.menu-item { container-type: inline-size; }        /* CQ component 1 of 3 */
.menu-item__row {
  display: flex;
  align-items: baseline;
  gap: var(--sp-4);
}
.menu-item__name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--t-h3);
  line-height: var(--lh-h3);
  letter-spacing: var(--tr-h3);
}
.price {
  flex: none;
  margin: 0;
  text-align: right;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.price--variants {
  display: grid;
  gap: 2px;
  justify-items: end;
  white-space: normal;
}
.price--variants .price-sep { display: none; }
.currency { font-size: 0.85em; color: var(--muted); margin-inline-end: 1px; }
.per-unit { font-weight: 400; color: var(--muted); }
.price--market, .price--included {
  font-size: 0.8125rem;
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--muted);
}
.variant { display: inline-block; }
.variant__label { font-weight: 400; color: var(--muted); margin-inline-end: 0.25rem; }
.variant__qual { font-size: 0.8125rem; color: var(--muted); }

.menu-item__desc {
  max-width: 62ch;
  margin-block-start: var(--sp-1);
  font-size: var(--t-sm);
  color: var(--muted);
}
.supplement {
  margin-block-start: var(--sp-1);
  font-size: var(--t-sm);
  color: var(--muted);
}
.menu-item__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  margin-block-start: var(--sp-2);
  font-size: 0.8125rem;
  color: var(--muted);
}
.sourcing { font-family: var(--font-display, Georgia, serif); font-style: italic; font-size: 0.875rem; }
.allergens { letter-spacing: 0.01em; }
.menu-item__note { margin-block-start: var(--sp-1); font-size: 0.8125rem; color: var(--muted); max-width: 62ch; }

/* Wine rows: stacked card in a narrow container, single line when the
   container affords it. Never horizontal scroll. */
.wine-attrs {
  display: grid;
  gap: 2px;
  margin-block-start: var(--sp-1);
  font-size: var(--t-sm);
  color: var(--muted);
}
.wine-attr--producer { color: var(--fg-soft); font-weight: 600; }
@container (min-width: 30rem) {
  .wine-attrs { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-2); }
  .wine-attr:not(:first-child)::before { content: "· " / ""; color: var(--gold); }
}

/* Course-jump rail: 48px, pinned under the header, snap x, no accordions */
.course-rail {
  position: sticky;
  top: var(--header-h);
  z-index: 25;
  display: flex;
  align-items: center;
  gap: var(--sp-2);              /* 8px between adjacent targets, not 4 */
  block-size: var(--jump-nav-h);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: var(--gutter);
  padding-inline: var(--gutter);
  margin-inline: calc(var(--gutter) * -1);
  background: var(--bg);
  border-block-end: 1px solid var(--border);
  scrollbar-width: none;
}
.course-rail::-webkit-scrollbar { display: none; }

/* js/ui.js hides the sticky header on scroll-down. The rail stayed pinned at
   var(--header-h), so a 72px band opened above it where dishes from the course
   ABOVE scrolled past in the clear — you could read the end of one course over
   the heading of the next. When the header is away the rail takes its place at
   the top of the viewport, and the sticky course heading follows it up, so
   nothing is ever visible above the rail. */
body:has(.site-header[data-hidden]) .course-rail { top: 0; }
body:has(.site-header[data-hidden]) .course-head { top: var(--jump-nav-h); }
.course-rail__chip {
  flex: none;
  scroll-snap-align: start;
  display: inline-flex;
  align-items: center;
  min-block-size: 2.75rem;
  padding-inline: var(--sp-3);
  border-block-end: 2px solid transparent;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--muted);
  white-space: nowrap;
  touch-action: manipulation;
}
.course-rail__chip[aria-current="true"] {
  color: var(--fg);
  border-block-end-color: var(--gold);
}
@media (hover: hover) and (pointer: fine) {
  .course-rail__chip:hover { color: var(--fg); }
}

/* Menu hub tabs — real <a href>s that also switch panels client-side */
/* 8px between adjacent tap targets, not 4. At 320px the three tabs filled the
   row exactly, so the extra gap is paid for out of the chip padding rather
   than by overflowing; overflow-x is the safety net for a longer menu name. */
.menu-tabs {
  display: flex;
  gap: var(--sp-2);
  border-block-end: 1px solid var(--border);
  margin-block-end: var(--sp-8);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.menu-tabs::-webkit-scrollbar { display: none; }
.menu-tabs a {
  display: inline-flex;
  align-items: center;
  flex: none;
  min-block-size: 48px;
  padding-inline: var(--sp-3);
  border-block-end: 2px solid transparent;
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  text-decoration: none;
  color: var(--muted);
  touch-action: manipulation;
}
.menu-tabs a[aria-current="true"],
.menu-tabs a[aria-current="page"] {
  color: var(--fg);
  border-block-end-color: var(--gold);
}
@media (hover: hover) and (pointer: fine) {
  .menu-tabs a:hover { color: var(--fg); }
}

/* --------------------------------------------------------------------------
   10. HOURS — CQ component 2 of 3. Real <table>, compact when embedded,
   roomy when it owns the column. Today's row is marked by js/marrow.js.
   -------------------------------------------------------------------------- */
.hours { container-type: inline-size; }
.hours table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); }
.hours caption { text-align: left; }
.hours th[scope="row"] {
  text-align: left;
  font-weight: 500;
  padding-block: var(--sp-2);
}
.hours td { text-align: right; padding-block: var(--sp-2); }
.hours tbody tr { border-block-end: 1px solid var(--border); }
.hours tr[data-today] th, .hours tr[data-today] td {
  color: var(--accent-text);
  font-weight: 600;
}
.hours__note { margin-block-start: var(--sp-3); font-size: 0.8125rem; color: var(--muted); max-width: 62ch; }
@container (min-width: 30rem) {
  .hours table { font-size: var(--t-body); }
  .hours th[scope="row"], .hours td { padding-block: var(--sp-3); }
}

/* --------------------------------------------------------------------------
   11. LOCATION CARD — CQ component 3 of 3. Footer, Visit block, /location/.
   -------------------------------------------------------------------------- */
.loc-card {
  container-type: inline-size;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  padding: var(--sp-6);
}
.loc-card__grid { display: grid; gap: var(--sp-6); }
@container (min-width: 34rem) {
  .loc-card__grid { grid-template-columns: 1fr 1fr; gap: var(--sp-8); }
}
.loc-card address { font-style: normal; }
.loc-card__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-block-start: var(--sp-4); }

/* --------------------------------------------------------------------------
   12. RESERVE DIALOG (Layer 1, built by js/reserve.js) + NEWSLETTER
   The reserve dialog is one of the two elements allowed a shadow.
   -------------------------------------------------------------------------- */
.reserve-dialog {
  width: min(26rem, 92%);
  border: none;
  border-radius: var(--r-md);
  padding: 0;
  background: var(--surface);
  color: var(--fg);
  box-shadow: var(--shadow-modal);
}
.reserve-dialog::backdrop { background: rgb(0 0 0 / 0.5); }
.reserve-dialog__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-5) var(--sp-6) 0;
}
.reserve-dialog__title {
  font-family: var(--font-display, Georgia, serif);
  font-weight: 400;
  font-size: 1.375rem;
  letter-spacing: var(--tr-h2);
}
.reserve-dialog__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 48px;
  min-height: 48px;
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  font-size: 0.8125rem;
  font-weight: 700;
  touch-action: manipulation;
}
.reserve-form { padding: var(--sp-5) var(--sp-6) var(--sp-4); }
.reserve-form .field { margin-block-end: var(--sp-4); }
.reserve-alt {
  padding: var(--sp-4) var(--sp-6) var(--sp-6);
  border-block-start: 1px solid var(--border);
  font-size: var(--t-sm);
  color: var(--muted);
}

.nl-dialog {
  width: min(24rem, 92%);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-6);
  background: var(--surface);
  color: var(--fg);
}
.nl-dialog::backdrop { background: rgb(0 0 0 / 0.4); }
.nl-row { display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: flex-end; }
.nl-row .field { flex: 1 1 14rem; margin-block-end: 0; }

/* Forms: hairline weights, document corners */
.field input, .field select, .field textarea {
  border-width: 1px;
  border-radius: var(--r-xs);
}

/* --------------------------------------------------------------------------
   12b. DATEPICKER — /private-events/ #ev-date, built by js/datepicker.js.
   Tokens only, no new colour. Hairlines carry it: the two permitted shadows
   stay with the drawer and the reserve dialog. Targets are 44px minimum.
   -------------------------------------------------------------------------- */
.date-row { display: flex; gap: var(--sp-2); }
.date-row input { flex: 1 1 auto; min-width: 0; }
.date-trigger {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 3.25rem;    /* matches the 52px field height */
  min-block-size: 3.25rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-xs);
  background: var(--surface);
  color: var(--muted);
  touch-action: manipulation;
}
@media (hover: hover) and (pointer: fine) {
  .date-trigger:hover { color: var(--fg); background: var(--surface-2); }
}

.datepicker {
  width: min(23rem, 92%);
  margin: auto;                /* base.css's * reset kills the UA centring */
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  padding: var(--sp-5);
  background: var(--surface);
  color: var(--fg);
}
.datepicker::backdrop { background: rgb(0 0 0 / 0.4); }
.datepicker__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  margin-block-end: var(--sp-3);
}
.datepicker__title {
  flex: 1 1 auto;
  text-align: center;
  font-family: var(--font-display, Georgia, serif);
  font-size: 1.1875rem;
  letter-spacing: var(--tr-h3);
}
.datepicker__nav {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 44px;
  min-block-size: 44px;
  border: 1px solid var(--border);
  border-radius: var(--r-xs);
  color: var(--muted);
  touch-action: manipulation;
}
@media (hover: hover) and (pointer: fine) {
  .datepicker__nav:hover { color: var(--fg); background: var(--surface-2); }
}
.datepicker table { width: 100%; border-collapse: collapse; }
.datepicker th {
  padding-block: var(--sp-2);
  font-family: var(--font-body, system-ui, sans-serif);
  font-size: var(--t-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tr-caps);
  text-transform: uppercase;
  color: var(--muted);
}
.datepicker td { padding: 1px; text-align: center; }
.datepicker__day {
  inline-size: 100%;
  min-inline-size: 44px;
  min-block-size: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--r-xs);
  font-variant-numeric: tabular-nums;
  color: var(--fg);
  touch-action: manipulation;
}
@media (hover: hover) and (pointer: fine) {
  .datepicker__day:hover { background: var(--surface-2); }
}
/* Today: a non-colour mark, so it survives both themes */
.datepicker__day--today { text-decoration: underline; text-underline-offset: 3px; }
.datepicker td[aria-selected="true"] .datepicker__day {
  background: var(--accent);
  color: var(--accent-fg);
}
.datepicker__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-block-start: var(--sp-3);
}
.datepicker__hint { font-size: var(--t-sm); color: var(--muted); }

/* --------------------------------------------------------------------------
   13. PAGE FURNITURE
   -------------------------------------------------------------------------- */
.page-head { padding-block: var(--sp-10) var(--sp-8); }
.page-head__lede {
  max-width: 44ch;
  margin-block-start: var(--sp-4);
  font-size: var(--t-lead);
  line-height: var(--lh-lead);
  color: var(--muted);
}
.page-head__img { margin-block-start: var(--sp-8); }
.page-head__img img { width: 100%; height: auto; object-fit: cover; }

/* §K: from 1024 the opener photograph sits BESIDE the title and lede instead
   of below them — the first viewport carries the whole page head. Guarded
   with :has() so image-less page heads (contact, 404) keep the plain flow. */
@media (min-width: 1024px) {
  .page-head:has(.page-head__img) {
    display: grid;
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    column-gap: clamp(2.5rem, 5vw, 5.5rem);
  }
  .page-head:has(.page-head__img) > * { grid-column: 1; }
  .page-head:has(.page-head__img) > .page-head__img {
    grid-column: 2;
    /* span 4: rule-head, h1, lede, and an optional fourth text block; on a
       three-child head the empty fourth row absorbs the min-height instead */
    grid-row: 1 / span 4;
    margin: 0;                    /* neutralises .bleed and the top margin */
    min-block-size: 24rem;
  }
  .page-head:has(.page-head__img) > .page-head__img picture,
  .page-head:has(.page-head__img) > .page-head__img img { height: 100%; }
}

/* Nadia's essay — signed and dated */
.essay { max-width: 44ch; }
.essay p + p { margin-block-start: var(--sp-4); }
.essay__signoff {
  margin-block-start: var(--sp-8);
  font-family: var(--font-display, Georgia, serif);
  font-style: italic;
  font-size: 1.25rem;
}
.essay__date {
  display: block;
  margin-block-start: var(--sp-1);
  font-family: var(--font-body, system-ui, sans-serif);
  font-style: normal;
  font-size: var(--t-sm);
  color: var(--muted);
}

/* The illustrative critic-quote slot — full 60-word treatment (§B.1) */
.press-quote { max-width: 36rem; }
.press-quote blockquote {
  font-family: var(--font-display, Georgia, serif);
  font-style: italic;
  font-size: clamp(1.375rem, 1.2rem + 0.8vw, 1.75rem);
  line-height: 1.4;
  letter-spacing: -0.01em;
  text-wrap: pretty;
}
.press-quote__attr {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin-block-start: var(--sp-4);
  font-size: var(--t-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--muted);
}
.press-quote__attr::before {
  content: "";
  inline-size: 1.5rem;
  block-size: 1px;
  background: var(--gold);
}

/* Gallery: CSS grid, never a carousel. Asymmetric from 768; at 1280 all six
   frames share one row — a contact sheet, the §K "multiple per viewport". */
.gallery-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); }
.gallery-grid img { width: 100%; height: 100%; object-fit: cover; }
@media (min-width: 768px) {
  .gallery-grid { grid-template-columns: repeat(3, 1fr); gap: var(--sp-4); }
  .gallery-grid > :first-child { grid-row: span 2; }
}
@media (min-width: 1280px) {
  .gallery-grid { grid-template-columns: repeat(6, 1fr); }
  .gallery-grid > :first-child { grid-row: auto; }
  /* Mixed 3:4 and 2:3 sources: one shared crop keeps the row a clean band */
  .gallery-grid img { aspect-ratio: 3 / 4; }
}

/* People — the portrait gets more space than the bio */
.person { display: grid; gap: var(--sp-6); }
@media (min-width: 768px) {
  .person { grid-template-columns: 7fr 5fr; gap: clamp(16px, 3vw, 56px); align-items: end; }
}
.person__portrait img { width: 100%; height: auto; }
/* A landscape source shown at the portrait format its neighbour sets, so the
   two halves of a pair-band read as the same block — picture, then text —
   and their headings land level. CSS crop; no extra files. */
.person__portrait--45 img { aspect-ratio: 4 / 5; object-fit: cover; }
.person__role {
  font-size: var(--t-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--muted);
}

/* Asymmetric split — 5/7 (or flipped) at desktop, stacked below */
.cols { display: grid; gap: var(--sp-8); }
@media (min-width: 1024px) {
  .cols { grid-template-columns: 5fr 7fr; gap: clamp(16px, 3vw, 56px); align-items: start; }
  .cols--flip { grid-template-columns: 7fr 5fr; }
}

/* --- §K re-consolidation components. Everything below 1024 in this group
   reproduces the exact spacing the old single-column markup had, so the
   mobile page does not move by a pixel; 1024+ is where they earn their keep
   by seating two related groups per viewport instead of one. --- */

/* Homepage story: the room photograph beside the essay from 1024. Below 1024
   the text column mimics the old wrap--prose centring (its max-width included
   the gutter padding, hence the calc). */
.story-cols__text {
  max-width: calc(var(--w-prose) - 2 * var(--gutter));
  margin-inline: auto;
}
@media (min-width: 1024px) {
  .story-cols {
    display: grid;
    /* The essay caps at 44ch; the photograph takes everything left over */
    grid-template-columns: minmax(0, 1fr) minmax(auto, 46ch);
    column-gap: clamp(2.5rem, 5vw, 5rem);
    align-items: start;
  }
  /* The essay is ~90 lines; the photograph keeps it company instead of
     scrolling away after one viewport. */
  .story-cols > figure {
    position: sticky;
    top: calc(var(--header-h) + var(--sp-6));
  }
  .story-cols__text { max-width: none; margin-inline: 0; }
}

/* Two groups that were one .section each on mobile sharing one desktop band
   (chef + The Coalhouse on the homepage; Nadia + Elliot on /about/).
   The mobile gap of 2 x --section-y is exactly what two adjacent .sections
   put between their contents. */
.pair-band { display: grid; gap: calc(var(--section-y) * 2); }
@media (min-width: 1024px) {
  .pair-band {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(2.5rem, 4vw, 4.5rem);
    align-items: start;
  }
  /* Inside a half-width cell the 7/5 split has no room — portrait above bio */
  .pair-band .person { grid-template-columns: 1fr; align-items: start; }
  .pair-band .cols { grid-template-columns: 1fr; }
}
/* Three-cell variant (the /about/ staff band) gets its third column where
   the width affords it; between 1024 and 1279 the third cell wraps. */
@media (min-width: 1280px) {
  .pair-band--trio { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Short titled notes (rule-head + heading + a paragraph) that were one
   .section each on mobile: on desktop they share rows. */
.info-grid { display: grid; gap: calc(var(--section-y) * 2); }
@media (min-width: 1024px) {
  .info-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-12) clamp(2.5rem, 4vw, 4rem);
  }
  .info-grid__span { grid-column: 1 / -1; }
}

/* A .stack-lg of wrapped label+paragraph pairs becomes a column grid on
   desktop; a leading h2 spans the full row. Margin reset beats base.css's
   .stack-lg > * + * on order, not specificity. */
@media (min-width: 1024px) {
  .ops-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-10) clamp(2.5rem, 4vw, 4rem);
  }
  .ops-grid > * + * { margin-block-start: 0; }
  .ops-grid > h2 { grid-column: 1 / -1; }
}
@media (min-width: 1280px) {
  .ops-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* A .rows list that is really a comparison set — the open roles on /careers/,
   the four inboxes on /contact/, the fact-sheet <dl> on /press/. Below 1024
   nothing changes: the full-bleed list keeps its exact rhythm. From 1024 the
   entries sit two abreast so roles, inboxes and facts compare side by side;
   each entry's own border-bottom keeps ruling the rows, so the grid reads as
   two parallel lists, never as cards. */
@media (min-width: 1024px) {
  .rows--grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(2.5rem, 4vw, 4rem);
  }
}

/* One deliberate void per page */
.void { padding-block: clamp(3.5rem, 6vw, 8rem); }

/* Stat / figure rows (capacity, minimums, pay ranges) */
.figure-row { display: flex; flex-wrap: wrap; gap: var(--sp-6) var(--sp-10); }

/* The four Coalhouse numbers are a comparison set, so they read as one line.
   Inside the narrow "What it costs" column they wrapped 2x2 and sat hard left;
   they now stand alone in the open space between the prose and the enquiry
   form. The asymmetric padding puts them about a third of the way down that
   space rather than dead centre. */
.figure-band {
  display: flex;
  justify-content: center;
  padding-inline: var(--gutter);
  /* Tight on a phone — the asymmetry below exists to place the row a third of
     the way down a wide, empty desktop band, and on a 844px-tall screen it just
     reads as 150px of dead ground above the form. */
  padding-block: var(--sp-8) var(--sp-10);
}
@media (min-width: 1024px) {
  .figure-band { padding-block: var(--sp-12) var(--sp-24); }
}
.figure-band .figure-row {
  justify-content: center;
  text-align: center;
  gap: var(--sp-8) clamp(var(--sp-6), 6vw, var(--sp-20));
}
@media (min-width: 640px) {
  .figure-band .figure-row { flex-wrap: nowrap; }
}
.figure { display: grid; gap: var(--sp-1); }
.figure dt, .figure .figure__label {
  font-size: var(--t-eyebrow);
  font-weight: 600;
  letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase;
  color: var(--muted);
}
.figure dd, .figure .figure__value {
  margin: 0;
  font-family: var(--font-display, Georgia, serif);
  font-size: var(--t-h2);
  line-height: var(--lh-h2);
}

/* --------------------------------------------------------------------------
   14. FOOTER — gold rule top; columns open with the fire rule
   -------------------------------------------------------------------------- */
.site-footer { border-top: 1px solid var(--gold); }
.site-footer .rule-head { margin-block-end: var(--sp-4); }
.site-footer .footer-grid h3 { margin-bottom: 0; font-size: var(--t-eyebrow); }

/* --------------------------------------------------------------------------
   15. DESKTOP (§K) — re-consolidate, wider page padding, 1440 cap
   -------------------------------------------------------------------------- */
@media (min-width: 1024px) {
  .wrap, .wrap--wide { padding-inline: clamp(1.5rem, 6vw, 7.5rem); }
  /* Section rhythm tightens where sections now carry two groups per viewport.
     72px of padding still puts 144px between groups — over 4x the 32px
     intra-group gap, comfortably past the >=1.5x floor in §C.4. The mobile
     clamp (56-ish px) is untouched. */
  :root { --section-y: 4.5rem; }
}
@media (min-width: 1280px) {
  .wrap--wide { max-width: 90rem; }
}

/* --------------------------------------------------------------------------
   16. REDUCED MOTION — 0.01ms, never none; the bar toggles without motion
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .cta-bar { transition-duration: 0.01ms !important; }
  .course-rail { scroll-behavior: auto; }
  /* The datepicker never moves under reduce — no transform transition at all */
  .datepicker, .date-trigger, .datepicker__day { transition: none; transform: none; }
}

/* --------------------------------------------------------------------------
   17. PRINT — a menu people will actually print
   -------------------------------------------------------------------------- */
@media print {
  .site-header, .cta-bar, .drawer, .course-rail, .menu-tabs,
  .concept-chip, dialog { display: none !important; }
  body { padding: 0; background: none; }
  .menu-doc { max-width: none; display: block; }
  .course-head { position: relative; top: auto; }   /* same reason as the 1024 rule above */
}
