/* =============================================================
   BRASSICA — main.css
   Built against the Brassica Web Design Guide v1.0 (2026).
   Build against tokens, never against literals.
   Breakpoint model: desktop ≥1170px, mobile ≤1169px.
   ============================================================= */

/* -------------------------------------------------------------
   1. TOKENS  (Design Guide, Appendix: Token Reference, p.65–67)
   ------------------------------------------------------------- */
:root {
  /* Color — brand */
  --brand-primary:        #ED2891;
  --brand-primary-hover:  #CC2585;
  --brand-secondary:      #D5A459;
  --brand-secondary-hover:#CF9134;
  --brand-light:          #FFFFFF;
  --brand-dark:           #231F20;

  /* Color — text */
  --text-primary-dark:    #231F20;
  --text-primary-light:   #F9F9F9;
  --text-secondary-dark:  #3F383D;
  /* Client decision (v1.0.4): secondary-light retired in favor of
     primary light everywhere it was used. Token kept so a future
     change is one line here. Original guide value: #CAC5B4. */
  --text-secondary-light: #F9F9F9;
  --text-tertiary:        #D5A459;

  /* Color — background */
  --bg-light:             #F9F9F9;
  --bg-dark:              #231F20;
  /* Secondary surfaces — used when two content sections touch, so the
     second one steps to a subtly different shade of the same family. */
  --bg-light-secondary:   #FFFFFF;
  --bg-dark-secondary:    #3F383D;
  /* Guide specifies 30%; raised 10% (to 33%) by client direction so
     overlaid type holds a little better across all heroes. */
  --overlay-image:        rgba(0, 0, 0, 0.33);

  /* Layout */
  --radius:               1px;
  --rule-weight:          1px;
  --stroke-button:        2px;
  --container-max:        1440px;
  --live-area:            1240px;   /* within the 1200–1280 range */
  --header-content-max:   1120px;
  --gutter:               24px;
  --header-h:             108px;
  --side-margin:          clamp(20px, 5vw, 80px);

  /* Buttons */
  --btn-height-sm:        36px;
  --btn-height-md:        44px;
  --btn-height-lg:        60px;
  --btn-min-width:        150px;

  /* Motion */
  --transition:           0.2s ease-out;
  --tracking-hover-delta: -0.01em;

  /* Section rhythm (p.15–16) */
  --section-pad:          clamp(120px, 10vw, 160px);
  --block-gap:            56px;   /* between blocks in a section: 48–64 */
  --headline-to-body:     24px;
  --body-to-cta:          32px;
  --rule-gap:             24px;

  /* Type family — Raleway, one family across the entire site */
  --font: "Raleway", "Helvetica Neue", Arial, sans-serif;
  /* Display face — Norwester, used for H4 (all caps). Falls back to Raleway. */
  --font-display: "Norwester", "Raleway", "Helvetica Neue", Arial, sans-serif;
}

/* Norwester — self-hosted display face for H4 (see --font-display). */
@font-face {
  font-family: "Norwester";
  src: url("../fonts/norwester.woff2") format("woff2"),
       url("../fonts/norwester.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@media (max-width: 1169px) {
  :root {
    --header-h:          100px;
    --section-pad:       clamp(72px, 12vw, 96px);
    --block-gap:         40px;
    --headline-to-body:  20px;
    --body-to-cta:       28px;
    --rule-gap:          20px;
  }
}

/* -------------------------------------------------------------
   1b. LIGHT / DARK MODE
   The guide (p.9) defines mode inversion as swapping backgrounds and
   their paired text tokens — light becomes dark, dark becomes light —
   while Brand Primary and Brand Secondary stay constant.

   LIGHT mode is the DEFAULT; dark is the opt-in (v1.36.0). The base tokens
   below are still authored dark-first, and this rule swaps the token *values*
   on <html> unless the visitor has chosen dark — so "no attribute" reads as
   light. The .section--dark component overrides reference these same tokens,
   so they flip automatically. Chrome and hero imagery are frozen below so they
   don't invert (a declaration on the element always beats an inherited one).
   ------------------------------------------------------------- */
html:not([data-mode="dark"]) {
  --bg-light:            #231F20;
  --bg-dark:             #F9F9F9;
  --bg-light-secondary:  #3F383D;
  --bg-dark-secondary:   #FFFFFF;
  --text-primary-dark:   #F9F9F9;
  --text-primary-light:  #231F20;
  --text-secondary-dark: #F9F9F9;
  --text-secondary-light:#3F383D;
  --brand-dark:          #F9F9F9;
  --brand-light:         #231F20;
}

/* Frozen surfaces — re-pin the tokens to their light-mode values on these
   subtrees, so they keep the same appearance in both modes:
   • Header / footer / drawer are persistent dark chrome (nav must stay
     light over hero imagery).
   • Heroes carry light text over a 30% image overlay in both modes (p.9).
   • Overlays and the toggle itself read the same either way. */
.site-header, .mobile-nav, .site-footer,
.media-hero, .page-banner, .error-hero, .offerings,
.mode-toggle, .bbanner {
  --bg-dark:            #231F20;
  --bg-light:           #F9F9F9;
  --bg-dark-secondary:  #3F383D;
  --bg-light-secondary: #FFFFFF;
  --text-primary-light: #F9F9F9;
  --text-primary-dark:  #231F20;
  --text-secondary-light:#F9F9F9;
  --text-secondary-dark: #3F383D;
  --brand-dark:         #231F20;
  --brand-light:        #FFFFFF;
}

/* -------------------------------------------------------------
   2. RESET & BASE
   ------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.65;
  color: var(--text-primary-dark);
  background: var(--bg-light);
}

img, svg { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
button { font: inherit; background: none; border: 0; padding: 0; cursor: pointer; color: inherit; }

/* Anchor targets clear the fixed header */
[id] { scroll-margin-top: calc(var(--header-h) + 24px); }

/* Skip link (accessibility) */
.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--bg-dark); color: var(--text-primary-light);
  padding: 12px 20px;
}
.skip-link:focus { left: 12px; top: 12px; }

/* -------------------------------------------------------------
   3. TYPOGRAPHY  (p.11–14)
   One H1 per page. Headlines never go bold. Tracking ≥ 0.
   ------------------------------------------------------------- */
h1, .h1 { font-weight: 200; font-size: 64px; line-height: 1.1;  letter-spacing: 0.005em; margin: 0; }
h2, .h2 { font-weight: 300; font-size: 48px; line-height: 1.15; letter-spacing: 0.01em;  margin: 0; }
h3, .h3 { font-weight: 300; font-size: 36px; line-height: 1.2;  letter-spacing: 0.01em;  margin: 0; }
h4, .h4 { font-family: var(--font-display); font-weight: 400; font-size: 28px; line-height: 1.3; letter-spacing: 0.04em; text-transform: uppercase; margin: 0; }
h5, .h5 { font-weight: 500; font-size: 20px; line-height: 1.35; margin: 0; }
h6, .h6, .eyebrow {
  font-weight: 600; font-size: 14px; line-height: 1.4;
  letter-spacing: 0.135em; text-transform: uppercase; margin: 0;
}

.lead    { font-weight: 300; font-size: 20px; line-height: 1.6; }
.body    { font-weight: 400; font-size: 17px; line-height: 1.65; }
.caption { font-weight: 400; font-size: 14px; line-height: 1.5; letter-spacing: 0.01em; }
.legal   { font-weight: 400; font-size: 12px; line-height: 1.5; letter-spacing: 0.02em; }

/* Widow / orphan control (progressive — ignored where unsupported).
   Headings balance across lines; body copy avoids a lone last-line word. */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 { text-wrap: balance; }
p, .lead, .body, li { text-wrap: pretty; }

@media (max-width: 1169px) {
  h1, .h1 { font-size: 40px; }
  h2, .h2 { font-size: 32px; }
  h3, .h3 { font-size: 28px; }
  h4, .h4 { font-size: 24px; }
  h5, .h5 { font-size: 18px; }
  .lead   { font-size: 18px; }
}

p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

/* Body copy measure: 65–75 characters (p.12) */
/* Keeps a phrase on one line — hyphens are break opportunities, so
   "Soon-to-Be" would otherwise split across lines. */
.nowrap { white-space: nowrap; }

.measure { max-width: 70ch; }
.measure--center { max-width: 70ch; margin-left: auto; margin-right: auto; }

/* Text links (Tertiary text color). Tracking tightens on hover like
   buttons — rest sits at 0.01em so the shrink never goes negative. */
.text-link {
  color: var(--text-tertiary);
  letter-spacing: 0.01em;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color var(--transition), letter-spacing var(--transition);
}
.text-link:hover { color: var(--brand-secondary-hover); letter-spacing: 0; }

/* -------------------------------------------------------------
   4. LAYOUT: CONTAINER, SECTIONS, RHYTHM  (p.15–18)
   ------------------------------------------------------------- */
.container {
  max-width: var(--container-max);
  margin: 0 auto;
  padding-left: var(--side-margin);
  padding-right: var(--side-margin);
}
.live {
  max-width: var(--live-area);
  margin-left: auto;
  margin-right: auto;
}

.section { padding-top: var(--section-pad); padding-bottom: var(--section-pad); }

/* Strict pairing: light bg → dark text; dark bg → light text (p.9) */
.section--light { background: var(--bg-light); color: var(--text-primary-dark); }
.section--light .text-secondary { color: var(--text-secondary-dark); }
.section--dark  { background: var(--bg-dark);  color: var(--text-primary-light); }
.section--dark  .text-secondary { color: var(--text-secondary-light); }

/* One surface per mode: every content section uses the primary Background
   (Dark or Light). The --bg-*-secondary tokens are kept for component chrome
   (e.g. the banner close button), not for section alternation. */

.center { text-align: center; }

.stack > * + *            { margin-top: var(--block-gap); }
.headline + .lead,
h1 + .lead, h2 + .lead, h3 + .lead,
h1 + p, h2 + p, h3 + p    { margin-top: var(--headline-to-body); }
.cta-row                  { margin-top: var(--body-to-cta); display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; align-items: center; }
.cta-row--left            { justify-content: flex-start; }

/* -------------------------------------------------------------
   5. IMAGE PLACEHOLDERS & MEDIA BLOCKS
   Hatched boxes marked IMAGE — art-directed separately (p.4).
   Every image that carries text carries the 30% overlay (p.9).
   ------------------------------------------------------------- */
.ph {
  position: relative;
  background:
    repeating-linear-gradient(45deg,
      rgba(255,255,255,0.05) 0 12px, rgba(0,0,0,0.06) 12px 24px),
    #3a3536;
  overflow: hidden;
}
.ph--light {
  background:
    repeating-linear-gradient(45deg,
      rgba(0,0,0,0.035) 0 12px, rgba(0,0,0,0.08) 12px 24px),
    #e9e7e4;
}
.ph__label {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 600; letter-spacing: 0.15em;
  text-transform: uppercase; color: rgba(255,255,255,0.55);
  pointer-events: none;
}
.ph--light .ph__label { color: rgba(35,31,32,0.4); }

/* Full-screen media header shared by most pages */
.media-hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-primary-light);
  text-align: center;
  background: var(--bg-dark);
  overflow: hidden;
}
.media-hero--short { min-height: 62vh; }
.media-hero__media { position: absolute; inset: 0; will-change: transform; }
.media-hero__media img,
.media-hero__media video { width: 100%; height: 100%; object-fit: cover; }
.media-hero__media::after {           /* the 30% overlay — not optional */
  content: ""; position: absolute; inset: 0;
  background: var(--overlay-image);
}
.media-hero__content {
  position: relative; z-index: 1;
  padding: calc(var(--header-h) + 40px) var(--side-margin) 64px;
  max-width: 880px;
}
.media-hero__content .lead { margin-top: var(--headline-to-body); }

/* Heroes carrying a fuller copy deck (Catering): a touch more room, and
   the supporting paragraphs sit at Body size beneath the Lead. */
.media-hero--copy .media-hero__content { max-width: 980px; }
.media-hero--copy .media-hero__content p:not(.lead) { font-size: 16px; margin-top: 16px; }

/* Hero carousel slides (Home) */
.hero-slides { position: absolute; inset: 0; }
.hero-slide {
  position: absolute; inset: 0; opacity: 0;
  transition: opacity 1.2s ease;
}
.hero-slide.is-active { opacity: 1; }
.hero-slide img { width: 100%; height: 100%; object-fit: cover; }

/* The mobile header floats over the hero, so its copy has to clear it. */
@media (max-width: 1169px) {
  .media-hero__content { padding-top: calc(var(--header-h) + 32px); }
}

/* -------------------------------------------------------------
   6. RULES & DOTTED DIVIDERS  (p.26–27)
   All rules 1px. Dots are round, 1px, evenly spaced.
   ------------------------------------------------------------- */
.rule        { border: 0; height: var(--rule-weight); margin: var(--rule-gap) 0; background: var(--brand-dark); }
.rule--light { background: var(--text-primary-light); }
.rule--gold  { background: var(--brand-secondary); }
.rule--pink  { background: var(--brand-primary); }   /* reserved: Don't Forget only */

/* Round-dot lines via radial gradients (crisper than border-style:dotted) */
.dots-h, .dots-v { --dot-color: var(--text-primary-light); flex: none; }
.dots-h {
  height: 3px;
  background-image: radial-gradient(circle, var(--dot-color) 1.2px, transparent 1.4px);
  background-size: 9px 3px;
  background-repeat: repeat-x;
  background-position: center;
}
.dots-v {
  width: 3px; align-self: stretch;
  background-image: radial-gradient(circle, var(--dot-color) 1.2px, transparent 1.4px);
  background-size: 3px 9px;
  background-repeat: repeat-y;
  background-position: center;
}
.dots--gold { --dot-color: var(--brand-secondary); }

/* Menu section-title lockup: rule — H2 — rule (p.40) */
.title-lockup {
  display: flex; align-items: center; gap: 24px;
  text-align: center;
}
.title-lockup::before, .title-lockup::after {
  content: ""; flex: 1; height: var(--rule-weight);
  background: var(--brand-secondary);
}
.title-lockup > * { flex: none; }

/* Dotted subhead lockup: dots — H4 gold — dots (Load It Up With, p.42) */
.subhead-lockup { display: flex; align-items: center; gap: 20px; }
.subhead-lockup::before, .subhead-lockup::after {
  content: ""; flex: 1; height: 3px;
  background-image: radial-gradient(circle, var(--brand-secondary) 1.2px, transparent 1.4px);
  background-size: 9px 3px; background-repeat: repeat-x; background-position: center;
}
/* Same type treatment as "Don't Forget" (18px, uppercase, 0.08em tracking),
   held in the brass Text Tertiary color. */
.subhead-lockup > .h4 {
  flex: none;
  color: var(--text-tertiary);
  text-transform: uppercase; font-size: 18px; letter-spacing: 0.08em;
}

/* -------------------------------------------------------------
   7. BUTTONS  (p.22–25)
   Three tiers, three sizes. Radius 1px everywhere.
   Hug with a 150px minimum. Title Case labels (markup).
   Hover: color + letter-spacing tighten together, 0.2s ease-out.
   ------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--btn-min-width);
  border-radius: var(--radius);
  font-weight: 500; font-size: 15px; line-height: 1;
  letter-spacing: 0.09em;
  text-decoration: none; text-align: center;
  cursor: pointer; white-space: nowrap;
  transition: color var(--transition), background-color var(--transition),
              border-color var(--transition), letter-spacing var(--transition);
  border: 0;
}
.btn:hover { letter-spacing: 0.08em; }   /* 0.09 − 0.01em */

/* Width lock: a hidden ghost of the label, rendered at rest tracking
   (the widest state), holds the button's width so the hover tighten
   never shifts neighbors. The visible line re-centers inside. */
.btn__label { display: inline-flex; flex-direction: column; align-items: center; }
.btn__label::after {
  content: attr(data-label);
  height: 0; overflow: hidden; visibility: hidden; pointer-events: none;
  letter-spacing: 0.09em;              /* rest tracking for buttons */
}
.nav-label { display: inline-flex; flex-direction: column; align-items: flex-start; }
.nav-label::after {
  content: attr(data-label);
  height: 0; overflow: hidden; visibility: hidden; pointer-events: none;
  letter-spacing: 0.1em;               /* rest tracking for nav links */
}

/* Sizes */
.btn--sm { height: var(--btn-height-sm); padding: 4px 12px;  gap: 4px;  font-size: 14px; }
.btn--md { height: var(--btn-height-md); padding: 10px 16px; gap: 6px;  }
.btn--lg { height: var(--btn-height-lg); padding: 16px 22px; gap: 10px; }

/* Tiers */
.btn--primary {
  background: var(--brand-primary);
  color: #F9F9F9;   /* pink is brand-constant → the label stays light in both modes */
}
.btn--primary:hover { background: var(--brand-primary-hover); color: #F9F9F9; }

.btn--secondary {
  background: transparent;
  border: var(--stroke-button) solid var(--brand-secondary);
  color: var(--text-primary-dark);
}
.section--dark .btn--secondary,
.on-dark .btn--secondary,
.site-header .btn--secondary,
.mobile-nav .btn--secondary,
.site-footer .btn--secondary,
.lightbox__panel .btn--secondary,
.offerings .btn--secondary,
.media-hero .btn--secondary { color: var(--text-primary-light); }
/* Hover: stroke deepens to the hover gold; no fill, label keeps its
   contextual color (client decision v1.0.11 — the guide's fill-on-hover
   from p.25 is retired). The tracking tighten comes from .btn:hover. */
.btn--secondary:hover {
  border-color: var(--brand-secondary-hover);
}
.btn--secondary.is-active {          /* filter active state (p.35) */
  background: var(--brand-secondary-hover);
  border-color: var(--brand-secondary-hover);
  color: var(--text-primary-light);
}

.btn--tertiary {
  background: transparent; border: 0;
  min-width: 0;
  color: inherit;
}
.btn--tertiary:hover { color: var(--brand-secondary-hover); }

/* Focus: never removed, never hover-only (p.25) */
.btn:focus-visible,
a:focus-visible,
button:focus-visible,
.accordion__trigger:focus-visible {
  outline: 2px solid var(--brand-secondary);
  outline-offset: 2px;
}

.btn[disabled], .btn.is-disabled { opacity: 0.4; pointer-events: none; }

/* Icons: trailing arrow = leaves the site; chevron = opens in place */
.btn__icon { flex: none; width: 1em; height: 1em; }
.btn__icon svg { width: 100%; height: 100%; fill: currentColor; }
.btn__chev { transition: transform var(--transition); }
[aria-expanded="true"] > .btn__chev { transform: rotate(180deg); }

/* Touch targets ≥ 44×44 on mobile (p.18) */
@media (max-width: 1169px) {
  .btn--sm { min-height: 44px; }
  .btn--tertiary { min-height: 44px; }
}

/* -------------------------------------------------------------
   8. HEADER & NAVIGATION  (p.28–31)
   ------------------------------------------------------------- */
.site-header {
  /* --banner-offset is set by popup.js while an announcement banner is
     on screen, so the fixed header rides below it and settles to 0 as
     the banner scrolls away. */
  position: fixed; top: var(--banner-offset, 0px); left: 0; right: 0; z-index: 100;
  height: var(--header-h);
  background: var(--bg-dark);
  color: var(--text-primary-light);
  border-bottom: var(--rule-weight) solid var(--text-primary-light);
  transition: background-color var(--transition), border-color var(--transition);
}
/* Transparent at the top of hero pages, with the opaque chrome fading in
   on scroll — on mobile as well as desktop (client direction; the guide's
   p.18 rule had the mobile header sitting above content rather than over
   it). Only applies to pages whose hero/dark section sits behind it. */
body.brassica-hero-page .site-header.is-transparent {
  background-color: transparent;
  border-bottom-color: transparent;
}
/* Opening the mobile drawer fills the header in, even at the top of a
   hero page — otherwise the chrome floats over imagery while a solid
   panel hangs beneath it. Reverts on close if still at the top, and the
   header's existing transition handles the fade both ways. */
body.nav-open .site-header.is-transparent {
  background-color: var(--bg-dark);
  border-bottom-color: var(--text-primary-light);
}
/* At the top of a hero page, hovering the header — or opening a mega-menu —
   fills the transparent background in. The header's transition eases it. */
body.brassica-hero-page .site-header.is-transparent:hover,
body.brassica-hero-page.nav-submenu-open .site-header.is-transparent {
  background-color: var(--bg-dark);
  border-bottom-color: var(--text-primary-light);
}
/* While a mega-menu is open, the panel below carries the single bottom rule, so
   the header's own rule is hidden — header + panel read as one block (only the
   bottom edge is ruled). Restored the instant the panel closes on hover-off.
   Both selectors: the first covers solid headers (non-hero / scrolled pages),
   the second matches (and, being later, overrides) the hero hover-fill rule. */
body.nav-submenu-open .site-header,
body.brassica-hero-page.nav-submenu-open .site-header.is-transparent {
  border-bottom-color: transparent;
  /* Drop the rule instantly the moment the panel opens — it shouldn't ease out
     and linger as the panel reveals. The background still fills in on its own
     transition; only the border change is made immediate here. */
  transition: background-color var(--transition);
}
.site-header__inner {
  max-width: var(--header-content-max);
  height: 100%;
  margin: 0 auto;
  padding: 0 24px;
  display: flex; align-items: center;
}
.site-header__brand { flex: none; margin-right: 36px; }
.site-header__brand svg { width: 50px; height: 50px; color: var(--brand-primary); }

.site-nav { display: flex; align-items: center; gap: 12px; }
.site-nav__item { position: relative; }
.site-nav__link {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 10px 8px;
  font-size: 15px; font-weight: 500; letter-spacing: 0.1em;
  line-height: 1; text-decoration: none;   /* Title Case per mockup */
  color: var(--text-primary-light);
  transition: color var(--transition), letter-spacing var(--transition);
}
.site-nav__link:hover { color: var(--brand-secondary-hover); letter-spacing: 0.09em; }
.site-nav__chev { width: 10px; height: 10px; transition: transform var(--transition); }
.site-nav__chev svg { width: 100%; height: 100%; }
/* The chevron artwork is a 1.4-weight stroke (half of Material's). At
   this 10px display size that would render sub-pixel, so the nav
   instances bump the stroke to stay a crisp hairline. Larger uses
   (the hero scroll cue) keep the thin weight from the file. */
.site-nav__chev svg { stroke-width: 2.4; }
.site-nav__item.is-open .site-nav__chev,
.site-nav__item:has(:focus-visible) .site-nav__chev { transform: rotate(90deg); }

/* Submenu → a full-width mega-menu that drops from the header (p.29). One
   panel spans the whole width; content sits in the header's grid with a
   touch more room. Opens on hover, focus, and click. */
.site-nav__submenu {
  position: fixed;
  top: calc(var(--banner-offset, 0px) + var(--header-h));
  left: 0; right: 0;
  background: var(--bg-dark);
  border-bottom: var(--rule-weight) solid var(--text-primary-light);
  display: none;
  z-index: 110;
}
/* Invisible bridge across the header's bottom edge so the pointer can travel
   from trigger down into the panel without the hover state breaking. */
.site-nav__submenu::before {
  content: ""; position: absolute;
  top: -10px; left: 0; right: 0; height: 10px;
}
.site-nav__item.is-open > .site-nav__submenu,
.site-nav__item:has(:focus-visible) > .site-nav__submenu {
  display: block;
  animation: submenu-reveal var(--transition);
}
/* Top-to-bottom unmask, easing out. Close stays instant — restraint. */
@keyframes submenu-reveal {
  from { clip-path: inset(0 0 100% 0); }
  to   { clip-path: inset(0 0 0 0); }
}
/* Left-align the content with the first nav item ("Our Menu"), not the logo:
   header padding + logo width + brand margin + nav-link padding. */
.mega { max-width: var(--header-content-max); margin: 0 auto; padding: 34px 24px 40px calc(24px + 50px + 36px + 8px); }
.mega__all {
  font-size: 15px; font-weight: 600; letter-spacing: 0.1em;
  color: var(--text-primary-light); text-decoration: none;
  transition: color var(--transition);
}
/* "All" is the first column; the state columns sit to its right. */
.mega__cols { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 24px 56px; }
.mega__col { display: flex; flex-direction: column; gap: 11px; min-width: 130px; }
.mega__state {
  font-size: 15px; font-weight: 600; letter-spacing: 0.08em;
  color: var(--text-primary-light); text-decoration: none;
  transition: color var(--transition);
}
.mega__region {
  font-size: 14px; font-weight: 400; letter-spacing: 0.05em;
  color: var(--text-secondary-light); text-decoration: none;
  transition: color var(--transition);
}
.mega--row { display: flex; flex-wrap: wrap; gap: 44px; padding-top: 28px; padding-bottom: 28px; }
.mega--row a {
  font-size: 15px; font-weight: 500; letter-spacing: 0.1em;
  color: var(--text-primary-light); text-decoration: none;
  transition: color var(--transition);
}
.mega a:hover, .mega__all:hover { color: var(--brand-secondary-hover); }

/* Page dimmer behind the header while a mega-menu is open. */
.nav-overlay {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(0, 0, 0, 0.3);
  opacity: 0; visibility: hidden;
  transition: opacity var(--transition), visibility 0s linear 0.2s;
}
body.nav-submenu-open .nav-overlay {
  opacity: 1; visibility: visible;
  transition: opacity var(--transition);
}

.site-header__ctas { margin-left: auto; display: flex; align-items: center; gap: 16px; }

.site-header__toggle { display: none; }

/* --- Mobile header & drawer (p.30–31) --- */
@media (max-width: 1169px) {
  /* Stays fixed (not sticky) so it can float transparently over a hero,
     exactly as it does on desktop. */
  .site-header__inner { max-width: none; padding: 24px; }
  .site-nav, .site-header__ctas { display: none; }

  .site-header__toggle {
    display: inline-flex; align-items: center; justify-content: center;
    margin-left: auto;
    width: 44px; height: 44px;
    color: var(--text-primary-light);
  }
  .site-header__toggle svg { width: 26px; height: 26px; fill: currentColor; }
  .site-header__toggle .icon-close { display: none; }
  .site-header__toggle[aria-expanded="true"] .icon-menu  { display: none; }
  .site-header__toggle[aria-expanded="true"] .icon-close { display: block; }

  .mobile-nav {
    position: fixed;
    /* Sits below the header, and below an announcement banner if one is up. */
    top: calc(var(--banner-offset, 0px) + var(--header-h));
    left: 0; right: 0; bottom: 0;
    background: var(--bg-dark);
    color: var(--text-primary-light);
    padding: 24px;
    overflow-y: auto;
    display: none;
    z-index: 99;
  }
  /* The panel unrolls top to bottom… */
  .mobile-nav.is-open {
    display: flex; flex-direction: column;   /* so the toggle can anchor to the bottom */
    animation: mobile-nav-reveal 0.35s ease-out;
  }
  @keyframes mobile-nav-reveal {
    from { clip-path: inset(0 0 100% 0); }
    to   { clip-path: inset(0 0 0 0); }
  }
  /* …and its contents drift down into place a beat behind it. */
  .mobile-nav.is-open .mobile-nav__list,
  .mobile-nav.is-open .mobile-nav__ctas {
    animation: mobile-nav-content 0.4s ease-out 0.08s both;
  }
  @keyframes mobile-nav-content {
    from { opacity: 0; transform: translateY(-10px); }
    to   { opacity: 1; transform: translateY(0); }
  }

  .mobile-nav__list { list-style: none; margin: 0; padding: 0; }
  .mobile-nav__list > li { padding-bottom: 24px; }
  .mobile-nav__link,
  .mobile-nav__trigger {
    display: inline-flex; align-items: center; gap: 8px;
    min-height: 44px;
    font-size: 15px; font-weight: 500; letter-spacing: 0.1em;
    text-decoration: none;               /* Title Case per mockup */
    color: var(--text-primary-light);
  }
  .mobile-nav__trigger .site-nav__chev { transform: rotate(90deg); }
  .mobile-nav__trigger[aria-expanded="true"] .site-nav__chev { transform: rotate(-90deg); }

  /* Submenu pushes the list down; it does not overlay (p.30) */
  .mobile-nav__submenu {
    list-style: none; margin: 8px 0 0; padding: 0 0 0 20px;
    display: none;
  }
  .mobile-nav__trigger[aria-expanded="true"] + .mobile-nav__submenu { display: block; }
  .mobile-nav__submenu li { padding: 8px 0; }
  .mobile-nav__submenu a {
    color: var(--text-primary-light); text-decoration: none;
    font-size: 14px; font-weight: 500; letter-spacing: 0.1em;
    display: inline-flex; min-height: 44px; align-items: center;
  }
  /* Locations grouped by state: state bold at the base indent, regions
     nudged in beneath it and lighter. */
  .mobile-nav__submenu a.mobile-nav__state { font-weight: 600; }
  .mobile-nav__submenu li:has(.mobile-nav__region) { padding: 4px 0; }
  .mobile-nav__submenu a.mobile-nav__region {
    padding-left: 18px; font-weight: 400; font-size: 13px;
    color: var(--text-secondary-light);
  }
  .nav-overlay { display: none; }
  .mobile-nav__ctas { display: flex; flex-direction: column; gap: 16px; margin-top: 8px; max-width: 320px; }

  body.nav-open { overflow: hidden; }
}
@media (min-width: 1170px) {
  .mobile-nav { display: none !important; }
}

/* Pages without a media hero start below the fixed header — both breakpoints,
   since the header now overlaps content on mobile too. */
.page-offset { padding-top: var(--header-h); }
/* Safety net: any view without a hero and without an explicit offset
   (e.g. the fallback template) still clears the fixed header. */
body:not(.brassica-hero-page) main:not(.page-offset) { padding-top: var(--header-h); }

/* -------------------------------------------------------------
   9. FOOTER  (p.32–33)
   ------------------------------------------------------------- */
.site-footer {
  background: var(--bg-dark);
  color: var(--text-primary-light);
  text-align: center;
  padding: 96px var(--side-margin) 48px;
}
.site-footer__wordmark { display: inline-block; color: var(--brand-primary); }
.site-footer__wordmark svg { height: 50px; width: auto; }

.site-footer__links {
  list-style: none; margin: 48px 0 0; padding: 0;
  display: flex; justify-content: center; gap: 40px;
}
/* Footer links match the header nav: 15px Medium, 0.1em tracking,
   tightening on hover (nav-label ghosts hold the width). */
.site-footer__links a {
  font-size: 15px; font-weight: 500; letter-spacing: 0.1em;
  text-decoration: none;
  color: var(--text-primary-light);
  transition: color var(--transition), letter-spacing var(--transition);
}
.site-footer__links a:hover { color: var(--brand-secondary-hover); letter-spacing: 0.09em; }

.site-footer__instagram {
  display: inline-flex; margin-top: 44px;
  color: var(--brand-secondary);
  width: 44px; height: 44px; align-items: center; justify-content: center;
  transition: color var(--transition);
}
.site-footer__instagram:hover { color: var(--brand-secondary-hover); }
.site-footer__instagram svg { width: 30px; height: 30px; fill: currentColor; }

/* Recent Instagram posts — three square thumbnails under the icon. Cached at
   250×250; displayed at --ig-thumb (bump this one value to show them larger). */
.site-footer__ig-feed {
  --ig-thumb: 150px;
  display: flex; justify-content: center; flex-wrap: wrap;
  gap: 12px; margin: 20px auto 0;
}
.site-footer__ig-feed .ig-thumb {
  display: block; width: var(--ig-thumb); height: var(--ig-thumb);
  overflow: hidden; border-radius: 2px;
}
.site-footer__ig-feed .ig-thumb img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: opacity var(--transition), transform var(--transition);
}
.site-footer__ig-feed .ig-thumb:hover img { opacity: 0.88; transform: scale(1.03); }
@media (max-width: 1169px) {
  .site-footer__ig-feed .ig-thumb { width: 28vw; height: 28vw; max-width: 150px; max-height: 150px; }
}

.site-footer__rule {
  border: 0; height: var(--rule-weight);
  background: var(--text-primary-light);
  max-width: var(--live-area); margin: 56px auto 32px;
}
.site-footer__caption { max-width: 760px; margin: 0 auto; }
.site-footer__caption a { color: inherit; }
.site-footer__legal { margin-top: 16px; }

@media (max-width: 1169px) {
  .site-footer { padding-top: 72px; }
  .site-footer__links { flex-direction: column; gap: 24px; }
}

/* -------------------------------------------------------------
   10. ACCORDIONS, TABS & FILTERS  (p.34–35)
   ------------------------------------------------------------- */
/* Accordion */
.accordion { display: flex; flex-direction: column; gap: 24px; text-align: left; }
.accordion__row {
  border: var(--rule-weight) solid var(--brand-dark);
  border-radius: var(--radius);
  background: transparent;
}
.accordion__trigger {
  width: 100%;
  display: flex; align-items: flex-start; gap: 16px;
  padding: 28px 32px;
  text-align: left;
}
.accordion__heading { flex: 1; }
.accordion__heading .h3 { font-size: 26px; line-height: 1.25; }
.accordion__heading .caption { display: block; margin-top: 6px; color: var(--text-secondary-dark); }
.accordion__icon {
  flex: none; width: 20px; height: 20px; margin-top: 6px;
  position: relative; color: var(--text-primary-dark);
}
/* Motion note — deliberate departure from Design Guide p.34.
   The guide says this icon should never spin, and it used to crossfade the
   vertical bar to nothing. Revisited and overruled on 2026-08-19: the bar now
   pivots 90° onto the horizontal, so the plus *becomes* the minus instead of
   losing a limb. Both bars are the same 20px length and 2px weight, so at the
   end of the turn they sit exactly on top of one another and read as one line.
   Reversing is free — releasing aria-expanded runs the transition backwards. */
.accordion__icon::before, .accordion__icon::after {
  content: ""; position: absolute; background: currentColor;
  transition: transform var(--transition);
}
.accordion__icon::before { left: 0; right: 0; top: 9px; height: 2px; }
.accordion__icon::after  { top: 0; bottom: 0; left: 9px; width: 2px; }
.accordion__trigger[aria-expanded="true"] .accordion__icon::after { transform: rotate(90deg); }

/* Reduced motion: same end state, no turn. */
@media (prefers-reduced-motion: reduce) {
  .accordion__icon::before, .accordion__icon::after { transition: none; }
}

.accordion__panel { overflow: hidden; height: 0; transition: height var(--transition); }
.accordion__panel-inner { padding: 0 32px 32px; }
.accordion__panel-inner .cta-row { justify-content: flex-start; }

@media (max-width: 1169px) {
  .accordion__trigger { padding: 20px; }
  .accordion__heading .h3 { font-size: 20px; }
  .accordion__panel-inner { padding: 0 20px 24px; }
}

/* Tabs */
.tabs__list {
  display: flex; gap: 32px; flex-wrap: wrap;
  border-bottom: var(--rule-weight) solid var(--brand-secondary);
  padding-bottom: 14px;
  margin-bottom: 48px;
}
.tabs__tab {
  font-size: 17px; font-weight: 400;
  color: var(--text-primary-light);
  transition: color var(--transition);
}
.section--light .tabs__tab { color: var(--text-primary-dark); }
.tabs__tab:hover { color: var(--brand-secondary-hover); }
.tabs__tab[aria-selected="true"] { color: var(--text-tertiary); }
.tabs__panel { animation: tab-fade var(--transition); }
.tabs__panel[hidden] { display: none; }
@keyframes tab-fade { from { opacity: 0; } to { opacity: 1; } }

/* Mobile-only section label, shown when the tabs collapse to a stack. */
.tab-mobile-label { display: none; }

/* Stacked variant (Benefits, Culture): render as a stack at ALL widths — the
   same treatment the tabs collapse to on mobile — so no set can be missed by
   not clicking a tab. The tab row is hidden; each panel shows with its label. */
.tabs--stacked .tabs__list { display: none; }
.tabs--stacked .tabs__panel { animation: none; }
.tabs--stacked .tabs__panel[hidden] { display: block; }
.tabs--stacked .tabs__panel + .tabs__panel { margin-top: 64px; }
.tabs--stacked .tab-mobile-label {
  display: block; color: var(--text-tertiary);
  padding-bottom: 16px; margin-bottom: 24px;
  border-bottom: var(--rule-weight) solid var(--brand-secondary);   /* gold rule under the eyebrow */
}

/* Mobile: drop the tab affordance entirely and stack every panel — it
   reads more clearly than tabs on a narrow screen. */
@media (max-width: 1169px) {
  .tabs__list { display: none; }
  .tabs__panel { animation: none; }
  .tabs__panel[hidden] { display: block; }
  .tabs__panel + .tabs__panel { margin-top: 56px; }
  .tab-mobile-label { display: block; color: var(--text-tertiary); margin-bottom: 20px; }
}

/* -------------------------------------------------------------
   Career path — inline SVG version of the handout (Benefits page). Brand pink
   and gold are frozen (same in both modes); the Team Member anchor and the
   outline nodes follow the light/dark tokens (currentColor / --bg-dark), so the
   whole graphic reads on either background. Geometry lives in
   assets/img/career-path.svg; only paint is set here.
   ------------------------------------------------------------- */
/* The path is revealed by a button (see benefits.js); height animates so it
   unrolls rather than snapping into place. The button starts above the
   collapsed path and moves below it once open — the panel comes first in the
   markup and the button is re-ordered, so the DOM order stays logical. */
.cp-wrap { display: flex; flex-direction: column; }
.cp-wrap .cp-wrap__cta { order: -1; }              /* collapsed: button on top */
.cp-wrap.is-open .cp-wrap__cta { order: 1; margin-top: 8px; }   /* open: below the path */
/* Open Roles sits above the Hide control rather than beside it, so the pair
   reads as one primary action with a quiet way back rather than two choices of
   equal weight. Tighter than the standard 16px row gap for the same reason. */
.cp-wrap__cta { flex-direction: column; gap: 10px; }
.cp-reveal { overflow: hidden; transition: height 0.4s cubic-bezier(0.4, 0, 0.2, 1); }
@media (prefers-reduced-motion: reduce) { .cp-reveal { transition: none; } }

.career-path { margin: 48px auto 0; max-width: 480px; }
.career-path-svg { display: block; width: 100%; height: auto; font-family: var(--font); }
.career-path-svg text { font-weight: 500; }
/* Circles */
.cp-c-outline   { fill: none; stroke: currentColor;          stroke-width: 2.5; }
.cp-c-anchor    { fill: currentColor; }
.cp-c-gold      { fill: none; stroke: var(--brand-secondary); stroke-width: 2.5; }
.cp-c-pink      { fill: none; stroke: var(--brand-primary);   stroke-width: 2.5; }
.cp-c-gold-fill { fill: var(--brand-secondary); }
.cp-c-pink-fill { fill: var(--brand-primary); }
/* Circle text */
.cp-t-outline { fill: currentColor; }
.cp-t-anchor  { fill: var(--bg-dark); }              /* flips with the section */
.cp-t-gold    { fill: var(--brand-secondary); }
.cp-t-pink    { fill: var(--brand-primary); }
.cp-t-fill    { fill: #F9F9F9; }
/* Connectors, star, and the closing wordmark */
.cp-line   { fill: none; stroke: var(--brand-secondary); stroke-width: 2.5; }
.cp-head   { fill: var(--brand-secondary); }
.cp-star   { fill: var(--brand-secondary); }
.cp-beyond { fill: var(--brand-secondary); font-family: var(--font-display); letter-spacing: 0.04em; }

/* Filters: Small Secondary buttons, centered row, wraps on mobile */
.filters {
  display: flex; justify-content: center; flex-wrap: wrap; gap: 10px;
  margin-top: 40px;
}
/* Filter chips — caption-sized with a 1px Text-Primary-Dark stroke, so
   they read as filters, not as the site's gold navigation buttons. */
.filters .btn {
  min-width: 0;
  height: auto;
  padding: 7px 14px;
  border-width: var(--rule-weight);
  border-color: var(--text-primary-dark);
  color: var(--text-primary-dark);
  background: transparent;
  font-size: 14px;
  letter-spacing: 0.01em;
}
.filters .btn:hover {
  background: transparent;
  border-color: var(--text-primary-dark);
  color: var(--text-primary-dark);
  letter-spacing: 0;
}
.filters .btn.is-active {
  background: var(--text-primary-dark);
  border-color: var(--text-primary-dark);
  color: var(--text-primary-light);
}
/* Width-lock ghost matches the chip's resting tracking. */
.filters .btn__label::after { letter-spacing: 0.01em; }

/* Tertiary buttons in a filter row stay label-only (no chip stroke). */
.filters .btn--tertiary {
  border: 0;
  padding-left: 8px; padding-right: 8px;
  color: var(--text-primary-dark);
}
.filters .btn--tertiary:hover { color: var(--brand-secondary-hover); background: transparent; }

/* -------------------------------------------------------------
   FILTER DROPDOWNS (Apply)
   Trigger and panel read as one outlined container that unrolls,
   reusing the header submenu's reveal.
   ------------------------------------------------------------- */
.filters--dropdowns { gap: 16px; align-items: center; }

.filter-select { position: relative; }

.filter-select__trigger {
  display: inline-flex; align-items: center; gap: 12px;
  min-width: 240px;
  padding: 10px 14px;
  border: var(--rule-weight) solid var(--text-primary-dark);
  border-radius: var(--radius);
  background: transparent;
  color: var(--text-primary-dark);
  font-size: 14px; font-weight: 500; letter-spacing: 0.01em; line-height: 1.2;
  text-align: left;
  transition: border-color var(--transition), letter-spacing var(--transition);
}
.filter-select__trigger:hover { letter-spacing: 0; }
.filter-select__label { flex: 1; }
.filter-select.has-selection .filter-select__trigger { border-color: var(--brand-secondary-hover); }

.filter-select__chev { flex: none; width: 10px; height: 10px; transition: transform var(--transition); }
.filter-select__chev svg { width: 100%; height: 100%; stroke-width: 2.4; }
.filter-select.is-open .filter-select__chev { transform: rotate(90deg); }

/* Open: the seam between trigger and panel disappears. */
.filter-select.is-open .filter-select__trigger {
  border-bottom-color: transparent;
  border-radius: var(--radius) var(--radius) 0 0;
}

.filter-select__panel {
  position: absolute; top: 100%; left: 0; z-index: 20;
  min-width: 100%;
  margin-top: -1px;
  padding: 4px 0 8px;
  background: var(--bg-light);
  border: var(--rule-weight) solid var(--text-primary-dark);
  border-radius: 0 0 var(--radius) var(--radius);
  display: none;
  text-align: left;
}
.filter-select.is-open .filter-select__panel {
  display: block;
  animation: submenu-reveal var(--transition);
}

.filter-option {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 14px;
  font-size: 14px; letter-spacing: 0.01em; white-space: nowrap;
  cursor: pointer;
  transition: color var(--transition);
}
.filter-option:hover { color: var(--brand-secondary-hover); }

/* Circular control — reads like a radio, behaves like a checkbox so more
   than one region can be chosen at a time. */
.filter-option input {
  appearance: none; -webkit-appearance: none;
  flex: none; width: 15px; height: 15px; margin: 0;
  border: var(--rule-weight) solid var(--text-primary-dark);
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  transition: background-color var(--transition), box-shadow var(--transition);
}
.filter-option input:checked {
  background: var(--text-primary-dark);
  box-shadow: inset 0 0 0 3px var(--bg-light);
}
.filter-option input:focus-visible {
  outline: 2px solid var(--brand-secondary);
  outline-offset: 2px;
}

@media (max-width: 1169px) {
  .filters--dropdowns { flex-direction: column; align-items: stretch; }
  .filter-select__trigger { width: 100%; min-height: 44px; }
  .filter-select__panel { min-width: 0; width: 100%; }
  .filter-option { min-height: 44px; }
}

.result-count { margin-top: 28px; color: var(--text-secondary-dark); }

/* Empty state replaces the list (p.56) */
.empty-state {
  border: var(--rule-weight) solid var(--brand-dark);
  border-radius: var(--radius);
  padding: 40px 32px;
  text-align: left;
}

/* -------------------------------------------------------------
   DARK-SECTION VARIANTS for the filter + accordion components
   (Apply, FAQs, Locations run on Background Dark — client decision).
   Everything inherits light text; these flip the strokes and fills
   that were hard-coded to the dark tokens.
   ------------------------------------------------------------- */
/* Chip filters (FAQs) — and the region pills that live in a media hero,
   which is always a light-text-over-image context in either mode. */
.section--dark .filters .btn,
.media-hero .filters .btn {
  border-color: var(--text-primary-light);
  color: var(--text-primary-light);
}
.section--dark .filters .btn:hover,
.media-hero .filters .btn:hover {
  border-color: var(--text-primary-light);
  color: var(--text-primary-light);
}
.section--dark .filters .btn.is-active,
.media-hero .filters .btn.is-active {
  background: var(--text-primary-light);
  border-color: var(--text-primary-light);
  color: var(--text-primary-dark);
}
.section--dark .filters .btn--tertiary { color: var(--text-primary-light); }
.section--dark .filters .btn--tertiary:hover { color: var(--brand-secondary-hover); }

/* Region pills inside a header image: centered, with room above them. */
.filters--hero { justify-content: center; margin-top: 28px; }
.media-hero--short .filters--hero { margin-top: 20px; }

/* Region filter — pills vs. phone dropdown.
   Pills (desktop) and the Apply-style dropdown (phones) drive one JS filter.
   In a section (Catering; Locations phone), the visible control carries the
   spacing to the list via margin-bottom, so the hidden one leaves no gap. */
.js-region-pills:not(.filters--hero) { margin-bottom: 72px; }

.region-dropdown {
  display: none;                 /* shown on phones only */
  flex-direction: column;
  align-items: center;
  gap: 14px;
  margin: 40px auto 44px;
  width: 100%; max-width: 320px;
}
.region-dropdown:first-child { margin-top: 0; }   /* leads the Locations section */
.region-dropdown .filter-select,
.region-dropdown .filter-select__trigger { width: 100%; }
.region-dropdown .js-clear-filters { align-self: center; }

@media (max-width: 760px) {
  .js-region-pills { display: none; }
  .region-dropdown { display: flex; }
}

/* Catering hero: lead and body share one measure so their widths match. */
.catering-hero .media-hero__content p { max-width: 38rem; margin-left: auto; margin-right: auto; }
/* -------------------------------------------------------------
   CATERING GALLERY — a grid, not CSS columns: columns fill independently and
   always leave a ragged bottom edge. Here the rows are locked and each photo
   is cropped to fill its cell (object-fit: cover), so the block is flush along
   the top AND bottom while the mixed portrait/landscape rhythm survives.
   Placement classes come from brassica_catering_gallery_classes().
   One column on phones, two on tablets, three (with the rhythm) on desktop.
   ------------------------------------------------------------- */
.catering-gallery {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  margin-top: 8px;
}
.catering-gallery__item {
  position: relative;
  margin: 0;
  aspect-ratio: 4 / 3;          /* sets the row height; images crop to fit */
  overflow: hidden;
  border-radius: 2px;
}
.catering-gallery__item img {
  display: block; width: 100%; height: 100%; object-fit: cover;
}

@media (min-width: 641px) {
  .catering-gallery { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 1170px) {
  .catering-gallery { grid-template-columns: repeat(3, 1fr); gap: 16px; }
  /* Every cell is placed explicitly (row and column come from PHP as custom
     properties), so nothing depends on auto-placement — which only moves
     forward and would leave a hole above a tall image. */
  .catering-gallery__item {
    grid-column: var(--c, auto) / span var(--cs, 1);
    grid-row: var(--r, auto) / span var(--rs, 1);
  }
  /* The tall one spans both rows and simply stretches — no ratio of its own,
     so its top and bottom land exactly on its neighbours' edges. */
  .catering-gallery__item.is-tall { aspect-ratio: auto; }
  /* Leftovers close the final row: double-wide, or the full width. */
  .catering-gallery__item.is-w2 { aspect-ratio: 8 / 3; }
  .catering-gallery__item.is-w3 { aspect-ratio: 4 / 1; }
}

/* The repeated catering CTA is for phones only — on desktop the header
   carries it in plain sight. */
.catering-cta-mobile { display: none; }
@media (max-width: 1169px) {
  .catering-cta-mobile { display: flex; margin-top: 32px; }
}

/* "Where Catering Delivery is Offered" — shown at every width, unlike the CTA
   above it: nothing in the header answers this question. */
.catering-cta-delivery { margin-top: 32px; }
@media (max-width: 1169px) {
  /* Stacked under the ordering CTA, so it wants its own smaller gap. */
  .catering-cta-delivery { margin-top: 16px; }
}

/* Catering intro copy, now below the header image and above the gallery. */
.catering-intro { margin-bottom: 48px; }
.catering-intro p:not(.lead) { margin-top: 16px; font-size: 16px; }
/* Match the lead's width to the body copy below it. Both use a ch measure, but
   ch scales with font size — so the 20px lead's 70ch was wider than the 16px
   body's 70ch. 56ch at 20px equals 70ch at 16px, so the two columns line up. */
.catering-intro .lead { max-width: 56ch; margin-left: auto; margin-right: auto; }

/* Dropdown filters (Apply) */
.section--dark .filter-select__trigger {
  border-color: var(--text-primary-light);
  color: var(--text-primary-light);
}
.section--dark .filter-select.has-selection .filter-select__trigger { border-color: var(--brand-secondary-hover); }
.section--dark .filter-select__panel {
  background: var(--bg-dark);
  border-color: var(--text-primary-light);
}
.section--dark .filter-option input { border-color: var(--text-primary-light); }
.section--dark .filter-option input:checked {
  background: var(--text-primary-light);
  box-shadow: inset 0 0 0 3px var(--bg-dark);
}

/* Accordion rows (Apply results, FAQs) */
.section--dark .accordion__row { border-color: var(--text-primary-light); }
.section--dark .accordion__heading .caption { color: var(--text-secondary-light); }
.section--dark .accordion__icon { color: var(--text-primary-light); }

/* Result count + empty state */
.section--dark .result-count { color: var(--text-secondary-light); }
.section--dark .empty-state { border-color: var(--text-primary-light); }

/* -------------------------------------------------------------
   11. HOME  (p.37–39)
   ------------------------------------------------------------- */
.home-hero__wordmark { display: inline-block; color: var(--brand-light); }
.home-hero__wordmark svg { height: 100px; width: auto; margin: 0 auto; }
@media (max-width: 480px) {
  /* If 100px will not fit with clear space, swap to wordmark alone at 50px */
  .home-hero__wordmark svg { height: clamp(50px, 24vw, 100px); }
}

/* Scroll cue — 50×50 Material chevron, Text Primary Light, bottom of
   the home hero. Points down; the click glides to #about. */
.hero-scroll-cue {
  position: absolute;
  left: 50%; bottom: 36px;
  transform: translateX(-50%);
  z-index: 2;
  width: 50px; height: 50px;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-primary-light);
  transition: color var(--transition), transform var(--transition);
}
.hero-scroll-cue svg {
  width: 50px; height: 50px;
  transform: rotate(90deg);          /* forward chevron → down */
  fill: currentColor;
}
.hero-scroll-cue:hover {
  color: var(--brand-secondary-hover);
  transform: translateX(-50%) translateY(3px);
}

/* Offerings pinned scroll (03) */
.offerings { position: relative; background: var(--bg-dark); color: var(--text-primary-light); }
.offerings__track { position: relative; }
.offerings__viewport {
  position: sticky; top: 0;
  height: 100vh; height: 100svh;
  overflow: hidden;
  display: flex; align-items: center;
}
.offerings__media { position: absolute; inset: 0; will-change: transform; }
.offerings__media .offering-slide {
  position: absolute; inset: 0; opacity: 0; transition: opacity 0.5s ease;
}
.offerings__media .offering-slide.is-active { opacity: 1; }
/* <picture> wraps the image when a mobile crop is set — it needs to fill the
   slide exactly as a bare <img> did. */
.offerings__media picture,
.offering-static-img picture { display: block; width: 100%; height: 100%; }
.offerings__media img { width: 100%; height: 100%; object-fit: cover; }
.offerings__media::after { content: ""; position: absolute; inset: 0; background: var(--overlay-image); }

.offerings__copy {
  position: relative; z-index: 1;
  will-change: transform;
  width: 50%;
  padding-left: clamp(48px, 10vw, 176px);   /* generous left inset */
  padding-right: 24px;
  max-width: 760px;
  display: grid;                            /* stack the two groups */
}
/* One group on stage at a time: both occupy the same grid cell,
   vertically centered; the active one fades in as the other fades out. */
.offerings__group {
  grid-area: 1 / 1;
  align-self: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.4s ease, visibility 0s linear 0.4s;
}
.offerings__group.is-active {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.4s ease;
}
.offerings__group > h2 { margin-bottom: 28px; }
.offering-item { padding: 18px 0; opacity: 0.45; transition: opacity 0.3s ease; }
.offering-item.is-active { opacity: 1; }
.offering-item p { margin: 6px 0 0; color: var(--text-secondary-light); }
.offering-item::after {
  content: ""; display: block; margin-top: 18px;
  height: var(--rule-weight); background: var(--text-primary-light);
  max-width: 420px;
}

/* Degraded / mobile: stacked sequence — image, then its copy (p.39) */
.offerings--static .offerings__viewport { position: static; height: auto; display: block; }
.offerings--static .offerings__media { display: none; }
.offerings--static .offerings__copy { width: auto; max-width: none; padding: var(--section-pad) var(--side-margin); display: block; }
.offerings--static .offerings__group { opacity: 1; visibility: visible; }
.offerings--static .offerings__group + .offerings__group { margin-top: 48px; }
.offerings--static .offering-item { opacity: 1; }
.offerings--static .offering-static-img { aspect-ratio: 16 / 9; margin: 24px 0; }
.offerings--static .offering-static-img img { width: 100%; height: 100%; object-fit: cover; }

/* Mobile / reduced-motion: the stacked offerings have no full-bleed imagery
   behind the copy, so they follow the mode like a normal content section —
   light surface in light mode, dark in dark mode. Re-pin the tokens to the
   light-mode values, undoing the freeze just for this stacked variant. */
html:not([data-mode="dark"]) .offerings--static {
  --bg-light:            #231F20;
  --bg-dark:             #F9F9F9;
  --bg-light-secondary:  #3F383D;
  --bg-dark-secondary:   #FFFFFF;
  --text-primary-dark:   #F9F9F9;
  --text-primary-light:  #231F20;
  --text-secondary-dark: #F9F9F9;
  --text-secondary-light:#3F383D;
  --brand-dark:          #F9F9F9;
  --brand-light:         #231F20;
}

@media (max-width: 1169px) {
  .offerings__copy { width: auto; padding-right: var(--side-margin); }
}

/* Ways To Enjoy — the same pinned component, with a CTA per option. Only the
   active option's button is on stage; the rest collapse away, so one action
   shows at a time. Collapsing height (not display) keeps it animated. */
.offering-item__cta {
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  margin-top: 0;
  transition: max-height 0.35s ease, opacity 0.25s ease, margin-top 0.35s ease;
}
.offering-item.is-active .offering-item__cta {
  max-height: 120px;
  opacity: 1;
  margin-top: 18px;
}
/* Stacked / mobile: every option is visible, so every CTA is too. */
.offerings--static .offering-item__cta { max-height: none; opacity: 1; margin-top: 18px; }
@media (prefers-reduced-motion: reduce) {
  .offering-item__cta { transition: none; }
}

/* Get the App — phones only: the app is a phone experience, so the section
   doesn't appear on desktop. */
.app-cta { display: none; }
@media (max-width: 1169px) {
  .app-cta { display: block; }
}

/* -------------------------------------------------------------
   12. OUR MENU  (p.40–43)
   ------------------------------------------------------------- */
.menu-section { max-width: 980px; margin: 0 auto; }
.menu-section + .menu-section { margin-top: var(--block-gap); }
.menu-section .title-lockup { margin-bottom: 44px; }
.menu-section .title-lockup h2 { letter-spacing: 0.06em; text-transform: uppercase; font-size: 34px; }

.menu-row { display: flex; align-items: stretch; justify-content: center; gap: 0; text-align: center; }
.menu-item { flex: 1; padding: 0 28px; }
.menu-item .h4, .menu-cell .h4 { text-transform: uppercase; font-size: 20px; letter-spacing: 0.04em; }
.menu-item p { margin: 8px 0 0; font-size: 15px; color: var(--text-secondary-light); }
.menu-item .caption { display: block; margin-top: 4px; color: var(--text-secondary-light); text-transform: uppercase; letter-spacing: 0.08em; font-size: 11px; }

/* OR / symbol lockups (With, Crunch) */
.menu-or {
  flex: 1; display: flex; align-items: center; gap: 14px; padding: 0 20px;
  color: var(--text-tertiary);
}
.menu-or::before, .menu-or::after {
  content: ""; flex: 1; height: 3px;
  background-image: radial-gradient(circle, var(--text-primary-light) 1.2px, transparent 1.4px);
  background-size: 9px 3px; background-repeat: repeat-x; background-position: center;
}
.menu-or .h4 { text-transform: uppercase; font-size: 20px; }
.menu-or svg { width: 44px; height: 16px; color: var(--brand-secondary); }

/* Enjoy One: 2×2 with vertical divider between columns, horizontal between
   rows. The dotted lines never intersect: horizontal rules stop short of
   the center line, and the vertical line is inset top and bottom. */
.menu-grid-2x2 { display: grid; grid-template-columns: 1fr 3px 1fr; column-gap: 0; text-align: center; }
.menu-grid-2x2 > .dots-v { grid-row: 1 / span 3; grid-column: 2; margin: 10px 0; }
.menu-grid-2x2 .menu-cell { padding: 24px 28px; }
.menu-grid-2x2 .dots-h { width: auto; }
.menu-grid-2x2 > div:first-child .dots-h  { margin-right: 56px; }
.menu-grid-2x2 > div:last-child  .dots-h  { margin-left: 56px; }

/* Don't Forget (08): the page's pink budget. The title sits on the top
   border like a legend — background-light behind the text opens a gap
   in the border; no flanking rules. */
.dont-forget {
  position: relative;
  border: var(--rule-weight) solid var(--brand-primary);
  border-radius: var(--radius);
  padding: 40px 32px;
  margin-top: var(--block-gap);
  min-height: 168px;
  display: flex; align-items: center;   /* vertically center the items */
}
.dont-forget .menu-row { width: 100%; align-items: center; }
.dont-forget__title {
  position: absolute; top: 0; left: 50%;
  transform: translate(-50%, -50%);
  color: var(--brand-primary);
}
.dont-forget__title .h4 {
  text-transform: uppercase; font-size: 18px; letter-spacing: 0.08em;
  /* Matches the menu section's own surface so it cuts the pink border. */
  background: var(--bg-dark);
  padding: 0 28px;
}
.dont-forget .menu-row { margin-top: -6px; }

.menu-cta { margin-top: 64px; }

/* Mobile: single column; vertical dotted dividers become horizontal (p.27, 43) */
@media (max-width: 1169px) {
  .menu-row { flex-direction: column; align-items: center; }
  .menu-item { padding: 0; }

  /* Every mobile dotted horizontal divider: identical 50% width and an
     even 28px rhythm above and below, so the whole menu breathes evenly. */
  .menu-row .dots-v,
  .menu-grid-2x2 .dots-v,
  .menu-grid-2x2 .dots-h {
    width: 50%; min-width: 0; height: 3px;
    grid-row: auto; grid-column: auto; align-self: center;
    margin: 28px auto !important;
    background-image: radial-gradient(circle, var(--text-primary-light) 1.2px, transparent 1.4px);
    background-size: 9px 3px; background-repeat: repeat-x; background-position: center;
  }

  /* With / Crunch: the OR text and crunch symbol keep their flanking dots. */
  .menu-or { padding: 0; margin: 28px 0; width: 50%; }

  .menu-grid-2x2 { grid-template-columns: 1fr; }
  .menu-grid-2x2 > div { display: flex; flex-direction: column; align-items: center; }
  .menu-grid-2x2 .menu-cell { padding: 0; }

  .menu-section .title-lockup { gap: 14px; }
  .menu-section .title-lockup h2 { font-size: 24px; }

  /* Keep the legend on one centered line. */
  .dont-forget__title .h4 { white-space: nowrap; }
}

/* -------------------------------------------------------------
   13. LOCATIONS & CATERING  (p.44–46, 59–60)
   ------------------------------------------------------------- */
.loc-group { max-width: var(--live-area); margin: 0 auto; }
/* Gap only BETWEEN visible groups. Using :not([hidden]) with the general
   sibling combinator means a filtered-to group with only hidden groups
   before it gets no top margin — so every single-region view starts at the
   same offset as the first group in the "All" view. */
.loc-group:not([hidden]) ~ .loc-group:not([hidden]) { margin-top: var(--section-pad); }
.loc-group__title {
  text-align: center;
  letter-spacing: 0.14em; text-transform: uppercase; font-size: 34px;
  padding-bottom: 18px; margin-bottom: 8px;
  border-bottom: var(--rule-weight) solid var(--brand-secondary);
}

.loc-entry {
  display: grid;
  /* The actions column carries two ordering buttons side by side, so it takes
     the larger share; name and address tighten to suit. */
  grid-template-columns: 1fr 0.8fr 1.5fr;
  gap: var(--gutter);
  align-items: start;
  padding: 44px 0 36px;
  border-bottom: var(--rule-weight) solid var(--brand-dark);
}
.loc-entry__name .h3 { font-size: 30px; }
.loc-entry__name .lead { margin-top: 10px; font-size: 18px; white-space: pre-line; }
/* Optional bold on the status line (e.g. "Coming 2027"). 600 is the heaviest
   Raleway weight loaded, so it stays crisp against the 300 default. */
.loc-entry__hours-line1.is-bold { font-weight: 600; }
.loc-entry__addr { font-weight: 500; font-size: 15px; line-height: 1.6; padding-top: 8px; }
.loc-entry__addr .loc-entry__phone { display: block; margin-top: 14px; font-weight: 500; text-decoration: none; }
.loc-entry__addr a { color: inherit; }
/* Address links read as plain text; the underline appears only on hover/focus. */
.loc-entry__map { text-decoration: none; }
.loc-entry__map:hover,
.loc-entry__map:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
.loc-entry__actions {
  display: flex; flex-direction: column; align-items: flex-end; gap: 18px;
  padding-top: 8px;
}
/* The two ordering buttons sit side by side, wrapping only if they must. */
.loc-entry__btns { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 12px; }
.loc-entry__actions .text-link { font-weight: 600; font-size: 14px; color: var(--text-primary-dark); }
.section--dark .loc-entry { border-bottom-color: var(--text-primary-light); }
.section--dark .loc-entry__actions .text-link { color: var(--text-primary-light); }

@media (max-width: 1169px) {
  .loc-entry { grid-template-columns: 1fr; gap: 16px; padding: 32px 0 28px; }
  .loc-entry__actions { align-items: flex-start; }
  .loc-entry__btns { justify-content: flex-start; }
  .loc-group__title { font-size: 24px; }
}

/* -------------------------------------------------------------
   Delivery Maps (/delivery-maps)

   Map left, details right — reusing .loc-group and the region filter from
   Locations, so the two pages filter identically. The entry is its own
   component rather than a .loc-entry variant: the map column wants a fixed
   aspect ratio and the right column stacks, which is a different shape from
   the three-column locations row, and forcing one to be the other would mean
   unpicking most of it anyway.
   ------------------------------------------------------------- */
/* Title lives in the page body (no media hero), so it owns the spacing down to
   the lead and on to the filters that follow. */
.dmap-intro { margin-bottom: 40px; }
.dmap-intro .lead { margin-top: var(--headline-to-body); }

.dmap-entry {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1fr);
  gap: var(--gutter);
  align-items: center;
  padding: 44px 0 36px;
  border-bottom: var(--rule-weight) solid var(--brand-dark);
}
.section--dark .dmap-entry { border-bottom-color: var(--text-primary-light); }

/* 4:3 keeps a circular delivery zone from being letterboxed into a sliver.
   position/overflow so the placeholder can absolutely fill it. */
.dmap-entry__map {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--bg-light);
}
.dmap-entry__canvas { width: 100%; height: 100%; }
.dmap-entry__img { width: 100%; height: 100%; object-fit: cover; display: block; }

.dmap-entry__body .h3 { font-size: 30px; }
.dmap-entry__addr {
  margin-top: 18px;
  font-weight: 500; font-size: 15px; line-height: 1.6;
}
.dmap-entry__addr a { color: inherit; }
.dmap-entry__body .loc-entry__phone {
  display: block; margin-top: 14px;
  font-weight: 500; font-size: 15px; text-decoration: none;
  color: inherit;
}
.dmap-entry__body .lead {
  margin-top: 14px; font-size: 18px; white-space: pre-line;
}
.dmap-entry__actions { margin-top: 24px; }

@media (max-width: 1169px) {
  /* Map on top, details beneath — the same stacking order as the desktop
     reading order, so nothing has to be re-learned on a phone. */
  .dmap-entry {
    grid-template-columns: 1fr;
    gap: 20px;
    align-items: start;
    padding: 32px 0 28px;
  }
  .dmap-entry__map { aspect-ratio: 3 / 2; }
  .dmap-entry__body .h3 { font-size: 24px; }
}

/* Locations hero jump links */
.media-hero__jumps { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; margin-top: 40px; }

/* Sarah Fairchild (04) */
.artist { max-width: var(--live-area); margin: var(--section-pad) auto 0; text-align: center; }
.artist__banner { aspect-ratio: 3 / 1; }
img.artist__banner { display: block; width: 100%; object-fit: cover; }
.artist h3 { margin-top: 40px; }
.artist .lead { margin-top: 16px; }
.artist .cta-row { margin-top: 28px; }
@media (max-width: 1169px) { .artist__banner { aspect-ratio: 16 / 9; } }

/* Restaurant details (single location).
   Desktop: photo + map side by side, details spanning beneath.
   Mobile: photo, then details, then map at the bottom. */
/* Detail pages are non-hero now, so <main> already reserves the header height;
   this is just the breathing room below it. */
.loc-detail { padding-top: 56px; padding-bottom: var(--section-pad); }
.loc-detail__grid {
  display: grid; gap: var(--gutter);
  max-width: var(--live-area); margin: 0 auto;
  grid-template-columns: 1fr 1fr;
  grid-template-areas:
    "photo map"
    "entry entry";
}
.loc-detail__photo { grid-area: photo; }
.loc-detail__map   { grid-area: map; }
.loc-detail__grid .loc-entry { grid-area: entry; margin-top: 24px; }
.loc-detail__photo, .loc-detail__map { aspect-ratio: 11 / 10; position: relative; overflow: hidden; }
.loc-detail__photo img { width: 100%; height: 100%; object-fit: cover; }
.loc-detail__map iframe { width: 100%; height: 100%; border: 0; display: block; filter: grayscale(1); }
.loc-detail__map__canvas { width: 100%; height: 100%; }
/* Google controls off + grey base already applied via the API options. */
.loc-detail .loc-entry { border-bottom-color: var(--text-primary-light); }

/* Brand-colored map pin. Tip anchored at map center; scales from the tip
   so the squash-and-stretch keeps the point planted. Triggered by JS only
   after the map has loaded and scrolled into view. */
.map-pin {
  position: absolute; left: 50%; top: 50%;
  width: 34px; height: 48px;
  margin: -48px 0 0 -17px;
  z-index: 2; pointer-events: none;
  opacity: 0;
  transform-origin: 50% 100%;
}
.map-pin.is-visible { animation: pin-drop 0.6s both; }
.map-pin svg { width: 100%; height: 100%; filter: drop-shadow(0 3px 4px rgba(0,0,0,0.3)); }

/* A gentle dropped-object arc: a light stretch on the fall, a soft squash
   on impact, a small rebound, then settle. Kept subtle on purpose. */
@keyframes pin-drop {
  0% {
    opacity: 0;
    transform: translateY(-28px) scaleX(0.92) scaleY(1.1);
    animation-timing-function: cubic-bezier(0.45, 0, 0.9, 0.55);  /* ease-in fall */
  }
  60% {
    opacity: 1;
    transform: translateY(0) scaleX(0.95) scaleY(1.06);
    animation-timing-function: ease-out;
  }
  76% { transform: translateY(0) scaleX(1.08) scaleY(0.92); }     /* soft squash */
  88% { transform: translateY(-2px) scaleX(0.98) scaleY(1.03); }   /* small rebound */
  100% { opacity: 1; transform: translateY(0) scale(1, 1); }
}

@media (max-width: 1169px) {
  .loc-detail { padding-top: 32px; }
  .loc-detail__grid {
    grid-template-columns: 1fr;
    grid-template-areas:
      "photo"
      "entry"
      "map";
  }
  .loc-detail__grid .loc-entry { margin-top: 0; }
}

/* -------------------------------------------------------------
   14. CAREERS CLUSTER  (p.47–55)
   ------------------------------------------------------------- */
/* Alternating two-column sections */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: center; }
.split + .split { margin-top: var(--section-pad); }
.split__media { aspect-ratio: 4 / 3; }
.split__media img { width: 100%; height: 100%; object-fit: cover; }
.split__content h2 { margin-bottom: 18px; }
.split__content .content-rule {
  border: 0; height: var(--rule-weight);
  background: var(--text-primary-light);
  margin: 28px 0 0;                 /* closes the content, not the section */
}
.section--light .split__content .content-rule { background: var(--brand-dark); }
.split__content .cta-row { justify-content: flex-start; margin-top: var(--body-to-cta); }
.split--flip .split__media { order: 2; }

@media (max-width: 1169px) {
  .split { grid-template-columns: 1fr; gap: 32px; }
  .split--flip .split__media { order: 0; }   /* image first, always (p.49) */
}

/* Stat rows (Culture tabs) */
.stat-row { display: flex; align-items: baseline; gap: 16px; padding: 18px 0; flex-wrap: wrap; }
.stat-row__icon { flex: none; width: 25px; height: 25px; color: var(--brand-secondary); align-self: center; }

/* -------------------------------------------------------------
   Scroll reveal (Benefits, Culture) — a row waits greyed out with its icon in
   the text color, then comes up to full strength with the icon in gold and a
   rule drawing itself left to right underneath. Gated on .has-js (set in the
   <head>) so without JavaScript every row simply renders as normal.
   ------------------------------------------------------------- */
.stat-row__rule {
  display: block; width: 100%; height: var(--rule-weight);
  background: var(--brand-secondary);
  transform: scaleX(0);
  /* Leaving: retracts to the right, continuing the direction it drew in.
     (At scaleX(1) the origin is visually irrelevant, so the switch never
     shows as a jump.) */
  transform-origin: right center;
}
.has-js .stat-row {
  opacity: 0.45;
  transition: opacity 0.5s ease;
}
.has-js .stat-row .stat-row__icon {
  color: currentColor;                     /* text color until revealed */
  transition: color 0.5s ease;
}
.has-js .stat-row__rule { transition: transform 0.7s cubic-bezier(0.4, 0, 0.2, 1) 0.1s; }

.has-js .stat-row.is-revealed { opacity: 1; }
.has-js .stat-row.is-revealed .stat-row__icon { color: var(--brand-secondary); }
.has-js .stat-row.is-revealed .stat-row__rule { transform: scaleX(1); transform-origin: left center; }

/* Benefits rows are a grid — the rule spans the full width on its own line. */
.benefits-list .stat-row__rule { grid-column: 1 / -1; margin-top: 6px; }

/* Pinned list (built by global.js on desktop): the stage locks centred in the
   area below the fixed header while the track scrolls past it, so the list
   holds still and only the highlight moves. */
/* Popup headline set in the display face. Matches the H4 treatment — Norwester
   is a caps face, so the transform isn't a style choice, it's how the type is
   drawn. Raleway headlines are left exactly as typed. */
.bpopup__headline--display {
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 400;
}

.pin-track { position: relative; }
/* The stage is only as tall as the list; global.js sets its sticky `top` so the
   list sits centred in the area below the fixed header. Sizing it to the
   content (rather than a full viewport) is what lets shorter laptop screens
   pin at all. */
.pin-stage {
  position: sticky;
  top: calc(var(--banner-offset, 0px) + var(--header-h));
}
/* Applied by global.js only when a list would otherwise be too tall to pin on
   this screen — trims 10px off each row's padding, top and bottom, which is
   what buys Culture's six-item set a pin on a 13" laptop. TIGHT_SAVE in
   global.js must stay in step with the 20px total this gives back. */
.pin-stage.is-tight .stat-row { padding-top: 8px; padding-bottom: 8px; }

@media (prefers-reduced-motion: reduce) {
  .has-js .stat-row { opacity: 1; transition: none; }
  .has-js .stat-row .stat-row__icon { color: var(--brand-secondary); transition: none; }
  .has-js .stat-row__rule { transform: scaleX(1); transition: none; }
}
/* Mobile: icon always stacks above the subhead, never beside it. */
@media (max-width: 1169px) {
  .stat-row { flex-direction: column; align-items: flex-start; gap: 10px; }
  .stat-row__icon { align-self: flex-start; }
}
.stat-row__icon svg { width: 100%; height: 100%; fill: currentColor; }
.stat-row .h3 { font-size: 24px; font-weight: 400; }
.stat-row .stat-row__note { color: var(--text-secondary-light); font-size: 15px; }
.stat-row .stat-row__note.is-italic { font-style: italic; }

/* Coworkers grid (Culture 03) */
.coworkers { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--gutter); margin-top: 48px; }
.coworker { position: relative; aspect-ratio: 4 / 5; overflow: hidden; }
.coworker img { width: 100%; height: 100%; object-fit: cover; }
.coworker__meta {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: 20px; text-align: left;
  color: #F9F9F9;   /* over the photo's dark gradient — light in both modes */
  background: linear-gradient(transparent 40%, rgba(0,0,0,0.78));   /* 0.65 + 20% */
  opacity: 0; transition: opacity var(--transition);
}
.coworker:hover .coworker__meta,
.coworker:focus-within .coworker__meta { opacity: 1; }
.coworker__meta .h5 { font-size: 18px; }
.coworker__meta .coworker__title { display: block; margin-top: 2px; color: var(--text-tertiary); }
.coworker__meta p { margin: 6px 0 0; font-size: 14px; }
.coworker__photo img { width: 100%; height: 100%; object-fit: cover; }

@media (max-width: 1169px) {
  .coworkers { grid-template-columns: repeat(2, 1fr); }
  /* Touch equivalent: always visible on mobile (p.55) */
  .coworker__meta { opacity: 1; position: static; background: none; color: inherit; padding: 12px 0 0; }
  .coworker { aspect-ratio: auto; }
  .coworker .coworker__photo { aspect-ratio: 4 / 5; }
}

/* -------------------------------------------------------------
   15. APPLY & FAQS  (p.56–58)
   ------------------------------------------------------------- */
/* Apply banner — full-width image, top of the image anchored to the top
   of the page, same 62vh height as the Locations hero. The transparent
   header floats over it; the title sits in the section below. */
.page-banner {
  position: relative;
  min-height: 62vh;
  background: var(--bg-dark);
  overflow: hidden;
}
.page-banner img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: top;
}
.page-banner::after {
  content: ""; position: absolute; inset: 0;
  background: var(--overlay-image);   /* keeps the light nav legible on top */
}

.roles-wrap { max-width: 900px; margin: 0 auto; }
.roles-wrap .accordion { margin-top: 40px; }
.roles-wrap .load-more { margin-top: 40px; }
.roles-wrap .roles-outro { margin-top: 48px; }
.job-desc { text-align: left; }
.job-desc ul { padding-left: 20px; }
.job-desc li { margin: 4px 0; }

/* -------------------------------------------------------------
   16. LIGHTBOXES  (Privacy p.61, Delivery Map p.60)
   ------------------------------------------------------------- */
.lightbox {
  position: fixed; inset: 0; z-index: 200;
  display: none;
  align-items: center; justify-content: center;
  padding: 24px;
}
.lightbox.is-open { display: flex; }
.lightbox__backdrop { position: absolute; inset: 0; background: rgba(0,0,0,0.6); }
.lightbox__panel {
  position: relative; z-index: 1;
  background: var(--bg-dark); color: var(--text-primary-light);
  max-width: 880px; width: 100%;
  max-height: min(86vh, 1000px);
  overflow-y: auto;
  padding: 56px;
  border-radius: var(--radius);
}
/* Delivery maps are taller than they are wide, so the panel takes its
   height from the image rather than forcing a square crop. */
.lightbox__panel--map { max-width: 680px; padding: 24px; }
/* Centered lockup: eyebrow above the market name. */
.lightbox__title {
  display: block;
  text-align: center;
  color: var(--text-primary-light);
  margin: 12px 0 26px;
}
.lightbox__eyebrow {
  display: block;
  font-weight: 600; font-size: 14px; line-height: 1.4;
  letter-spacing: 0.135em; text-transform: uppercase;
}
.lightbox__market {
  display: block;
  margin-top: 8px;
  font-weight: 300;
  font-size: clamp(26px, 4vw, 36px);
  line-height: 1.2; letter-spacing: 0.01em;
}
.lightbox__market:empty { display: none; }
.lightbox__panel--map .lightbox__map { position: relative; }
.lightbox__panel--map .lightbox__map img {
  display: block;
  width: 100%; height: auto;
  max-height: min(calc(86vh - 176px), 820px);   /* leaves room for the title + padding so the panel never scrolls */
  object-fit: contain;
  margin: 0 auto;
}
/* Only the empty state needs a reserved box. */
.lightbox__panel--map .lightbox__map.is-placeholder { aspect-ratio: 1 / 1; }
/* Live delivery-circle map (Google Maps JS). A square that fits within the
   panel's vertical room, so the map has real dimensions when it initializes. */
.lightbox__panel--map .lightbox__map-canvas {
  width: 100%;
  max-width: min(calc(86vh - 176px), 700px);
  aspect-ratio: 1 / 1;
  margin: 0 auto;
  background: var(--bg-dark-secondary);
  overflow: hidden;
}
/* Google injects its own controls/links; keep corners tidy inside the panel. */
.lightbox__panel--map .lightbox__map-canvas img { max-width: none; }
/* Close sits in the panel's own corner — 40 × 40, 10px off — so it stays
   close to hand on mobile instead of drifting out to the screen edge. */
.lightbox__close {
  position: absolute; top: 10px; right: 10px;
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-primary-light);
  z-index: 3;
  transition: color var(--transition), transform var(--transition);
}
.lightbox__close svg { width: 22px; height: 22px; fill: currentColor; }
.lightbox__close:hover { color: var(--brand-secondary-hover); transform: scale(1.08); }
body.lightbox-open { overflow: hidden; }

/* Privacy content */
.privacy-body { text-align: left; margin-top: 40px; }
.privacy-body h3 { font-size: 24px; margin: 36px 0 12px; }
.privacy-body .label { font-weight: 500; }
.privacy-intro { text-align: center; }
.privacy-intro .caption { display: block; margin-top: 12px; color: var(--text-secondary-light); }

@media (max-width: 1169px) {
  .lightbox__panel { padding: 48px 24px 32px; }
}

/* -------------------------------------------------------------
   16b. BLOCK-EDITOR CONTENT (seeded Gutenberg blocks)
   The editable content uses core blocks carrying the same classes
   as the templates. These rules make block output (hr separators,
   wp-block-group wrappers) sit identically to the hand-built markup.
   ------------------------------------------------------------- */
hr.dots-v, hr.dots-h {
  border: 0; margin: 0; max-width: none; opacity: 1;
}
hr.dots-h { height: 3px; width: 100%; }
.menu-row hr.dots-v { align-self: stretch; }
.wp-block-group.menu-item p { margin-top: 8px; }

/* Spacing the templates carried as inline styles */
.subhead-lockup { margin: 40px 0 28px; }
.subhead-lockup:first-of-type { margin-top: 44px; }

/* Load It Up With: the three rows share one height, items centered */
@media (min-width: 1170px) {
  .subhead-lockup + .menu-row { min-height: 112px; align-items: center; }
}
.wp-block-heading.h1.center { margin-bottom: var(--section-pad); }

/* Benefits rows: icon + H3 on the first line, description on its own line
   beneath, aligned under the heading. Grid rather than flex so the note
   always breaks to its own row — with flex, a max-width on the note
   clamps its basis and it creeps back up beside the heading on wide
   viewports. */
/* Icon + heading on one line, description beneath, aligned under the heading.
   Grid rather than flex so the note always breaks to its own row. */
.benefits-list .stat-row {
  display: grid;
  grid-template-columns: 25px 1fr;
  grid-template-areas:
    "icon  title"
    ".     note";
  column-gap: 16px;
  row-gap: 10px;
  align-items: center;
  padding: 22px 0;
}
.benefits-list .stat-row__icon { grid-area: icon; }
.benefits-list .stat-row .h3   { grid-area: title; font-size: 26px; }
.benefits-list .stat-row__note {
  grid-area: note;
  max-width: 70ch;
  font-size: 16px; line-height: 1.65;
}

/* Feature banner between a section's eyebrow and its entries (Benefits,
   Culture) — same treatment as the Sarah Fairchild banner on Locations. */
.section-banner { aspect-ratio: 3 / 1; margin-bottom: 40px; }
img.section-banner { display: block; width: 100%; object-fit: cover; }
@media (max-width: 1169px) {
  .section-banner { aspect-ratio: 16 / 9; margin-bottom: 28px; }
}

/* -------------------------------------------------------------
   BENEFITS CAROUSEL — one benefit on stage at a time (desktop). Below
   1170px it dissolves into the plain stack and the nav disappears.
   ------------------------------------------------------------- */
.bcar { position: relative; }
.bcar__track { display: block; }
.bcar__nav { display: none; }

@media (min-width: 1170px) {
  .bcar { overflow: hidden; }
  .bcar__track {
    display: flex; flex-wrap: nowrap;
    transition: transform 0.45s cubic-bezier(0.4, 0, 0.2, 1);
    will-change: transform;
  }
  .bcar__slide { flex: 0 0 100%; width: 100%; }

  .bcar__nav {
    display: flex; align-items: center; justify-content: center; gap: 20px;
    margin-top: 8px;
  }
  .bcar__arrow {
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px; padding: 0;
    background: transparent; border: 0; cursor: pointer;
    color: var(--text-primary-light);          /* white on dark, dark on light */
    transition: color var(--transition), opacity var(--transition);
  }
  .bcar__arrow svg { width: 18px; height: 18px; }
  .bcar__arrow:hover { color: var(--brand-secondary-hover); }
  /* At either end the matching arrow disappears — the space is kept so the
     dots don't shuffle sideways as you page. */
  .bcar__arrow.is-hidden { visibility: hidden; pointer-events: none; }

  .bcar__dots { display: flex; align-items: center; gap: 14px; }
  .bcar__dot {
    width: 9px; height: 9px; padding: 0;
    border: 0; border-radius: 50%; cursor: pointer;
    background: #000;                          /* inactive: full black */
    transition: background-color var(--transition), transform var(--transition);
  }
  .bcar__dot.is-active { background: var(--brand-secondary); }
  .bcar__dot:hover { transform: scale(1.2); }
}

@media (max-width: 1169px) {
  .benefits-list .stat-row {
    grid-template-columns: 1fr;
    grid-template-areas:
      "icon"
      "title"
      "note";
  }
}

/* Legacy flat h2/p sequences (seeded before v1.6) still read correctly. */
.benefits-list h2 { margin-top: var(--block-gap); }
.benefits-list h2:first-child { margin-top: 0; }
.benefits-list h2 + p { margin-top: var(--headline-to-body); }

/* Editor legibility: give slot groups a hint of structure in-admin */
.editor-styles-wrapper .wp-block-group[class*="slot-"] {
  outline: 1px dashed rgba(213, 164, 89, 0.5);
  outline-offset: 8px;
  margin: 24px 0;
}

/* -------------------------------------------------------------
   16c. POPUPS
   Desktop: 800px wide, height follows the content, three layouts.
   Mobile: full-width text panel anchored to the bottom of the frame;
   imagery is never shown there.
   Colors arrive per-popup as --popup-bg / --popup-fg.
   ------------------------------------------------------------- */
.bpopup {
  position: fixed; inset: 0; z-index: 300;
  display: none;
  align-items: center; justify-content: center;
  padding: 24px;
}
.bpopup.is-open { display: flex; }
.bpopup__backdrop { position: absolute; inset: 0; background: rgba(0,0,0,0.6); }

.bpopup__panel {
  position: relative; z-index: 1;
  width: 800px; max-width: 100%;
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  background: var(--popup-bg, var(--bg-dark));
  color: var(--popup-fg, var(--text-primary-light));
  border-radius: var(--radius);
  opacity: 0;
  transform: translateY(-24px);
  animation: bpopup-in 0.5s cubic-bezier(0.2, 0.8, 0.3, 1) forwards;
}
/* Fade in and drop into place. */
@keyframes bpopup-in {
  to { opacity: 1; transform: translateY(0); }
}

/* Material close, 40 × 40, 10px off the corner. */
.bpopup__close {
  position: absolute; top: 10px; right: 10px;
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  color: var(--popup-fg, var(--text-primary-light));
  z-index: 3;
  transition: color var(--transition), transform var(--transition);
}
.bpopup__close svg {
  width: 24px; height: 24px; fill: currentColor;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.35));   /* legible over imagery */
}
.bpopup__close:hover { color: var(--brand-secondary-hover); transform: scale(1.08); }

.bpopup__media img { display: block; width: 100%; height: 100%; object-fit: cover; }
.bpopup__body { padding: 48px 44px; }
.bpopup__content > *:first-child { margin-top: 0; }
.bpopup__content p { margin: 0 0 1em; }
.bpopup__content p:last-child { margin-bottom: 0; }
/* The popup's headline gap, as its own named value derived from the sitewide
   token — so it still moves with the design system, and there is one obvious
   knob to turn rather than arithmetic buried in a margin.
      Desktop takes the token as-is (24px).
      Below 1170px the token already steps down to 20px, and the popup wants a
      shade tighter again at that size, so it sheds 2px more (18px).
   This has to be restated at all because `.bpopup__content p` above sets margin
   with the SHORTHAND, which resets margin-top to zero and outranks the sitewide
   `h2 + p` rule. */
.bpopup__content { --popup-headline-gap: var(--headline-to-body); }
@media (max-width: 1169px) {
  .bpopup__content { --popup-headline-gap: calc(var(--headline-to-body) - 2px); }
}
.bpopup__content h2 + p,
.bpopup__content h3 + p { margin-top: var(--popup-headline-gap); }
.bpopup__ctas { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }

/* Layout 1 — two column: image left half, content right half. */
.bpopup__panel--two-col { display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; }
.bpopup__panel--two-col .bpopup__media { min-height: 100%; }

/* Layout 2 — text only, centered. */
.bpopup__panel--text .bpopup__body { text-align: center; padding: 56px 48px; }
.bpopup__panel--text .bpopup__ctas { justify-content: center; }

/* Layout 3 — image only on desktop; its text appears on mobile instead. */
.bpopup__panel--image .bpopup__body { display: none; }

@media (max-width: 1169px) {
  /* One mobile treatment: text, full width, anchored to the bottom. */
  .bpopup { align-items: flex-end; padding: 0; }
  .bpopup__panel {
    width: 100%; max-width: none;
    max-height: 85vh;
    border-radius: 0;
    display: block;                       /* unwind the desktop grid */
  }
  .bpopup__media { display: none; }       /* imagery never shows on mobile */
  .bpopup__panel--image .bpopup__body { display: block; }
  .bpopup__body,
  .bpopup__panel--text .bpopup__body { padding: 32px 24px 36px; text-align: left; }
  .bpopup__panel--text .bpopup__ctas { justify-content: flex-start; }
  .bpopup__close { top: 10px; right: 10px; }
}

/* Editor preview: keep popup content readable in the block editor. */
.editor-styles-wrapper .bpopup { position: static; display: block; }

/* -------------------------------------------------------------
   16d. ANNOUNCEMENT BANNER
   Full width, 50px tall, top of the page, above everything — and in
   normal flow, so it scrolls away rather than sticking.
   ------------------------------------------------------------- */
.bbanner {
  position: relative; z-index: 400;
  height: 50px;
  overflow: hidden;
  background: var(--banner-bg, var(--brand-primary));
  color: var(--banner-fg, var(--text-primary-light));
}
.bbanner__link { display: block; height: 100%; color: inherit; text-decoration: none; }
.bbanner__viewport {
  position: absolute; inset: 0;
  display: flex; align-items: center;
  overflow: hidden;
  padding-right: 50px;              /* clear of the close button */
}
.bbanner__track {
  display: flex; flex: none;
  white-space: nowrap;
  will-change: transform;
  animation: bbanner-marquee 40s linear infinite;   /* duration set in JS */
}
.bbanner__item {
  padding-right: 56px;
  font-size: 14px; font-weight: 500;
  letter-spacing: 0.12em; text-transform: uppercase;
  line-height: 1;
}
/* Two identical halves in the track, so -50% is a seamless loop. */
@keyframes bbanner-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.bbanner:hover .bbanner__track,
.bbanner:focus-within .bbanner__track { animation-play-state: paused; }  /* pause on hover + keyboard focus */

/* Solid block behind the X: the marquee scrolls past underneath, and
   overflow clipping alone won't stop it (padding is inside the clip). */
.bbanner__close {
  position: absolute; top: 0; right: 0;
  width: 50px; height: 50px;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-dark-secondary);
  color: var(--text-primary-light);
  z-index: 2;
  transition: background-color var(--transition);
}
.bbanner__close svg {
  width: 20px; height: 20px; fill: currentColor;
  transition: transform var(--transition);
}
.bbanner__close:hover { background: var(--bg-dark); }
.bbanner__close:hover svg { transform: scale(1.12); }

@media (prefers-reduced-motion: reduce) {
  .bbanner__track { animation: none; }
  .bbanner__viewport { justify-content: center; }
}

/* Static banner: a single message, held still and centered. Symmetric side
   padding (both sides clear the close button) so it centers in the full bar. */
.bbanner--static .bbanner__track { animation: none; }
.bbanner--static .bbanner__viewport { justify-content: center; padding-left: 50px; }
.bbanner--static .bbanner__item { padding-right: 0; }

/* Phones: the bar is narrow, so a longer message ran under the close button.
   Type steps down, and a static message is allowed to wrap onto more lines
   with the bar growing to fit (popup.js measures the height, so the fixed
   header still sits correctly beneath it). The ticker stays on one line — it
   has to, to scroll — and just takes the smaller type. */
@media (max-width: 767px) {
  .bbanner__item { font-size: 12px; letter-spacing: 0.08em; }

  .bbanner--static { height: auto; min-height: 50px; }
  .bbanner--static .bbanner__link { height: auto; }
  .bbanner--static .bbanner__viewport {
    position: relative; inset: auto;
    padding: 12px 60px;                 /* 50px close button + 10px breathing room */
    min-height: 50px;
  }
  /* width:100% matters: the track is `flex: none`, so without an explicit
     width it takes its max-content size and refuses to shrink — the message
     would run straight out of the bar instead of wrapping. */
  .bbanner--static .bbanner__track {
    display: block; white-space: normal;
    width: 100%; min-width: 0;
  }
  /* Padding alone isn't enough: a message can land a few pixels inside the
     available width and stay stubbornly on one line, crowding the close
     button. Capping the text column forces the break to happen early and in a
     predictable place. Expressed in em so it tracks the font size — 20em is
     roughly 28 characters of this uppercase, letter-spaced type. */
  .bbanner--static .bbanner__item {
    display: block; white-space: normal;
    text-align: center; line-height: 1.35;
    max-width: 20em;
    margin-left: auto; margin-right: auto;
  }
}

/* -------------------------------------------------------------
   17. UTILITIES & ODDS AND ENDS
   ------------------------------------------------------------- */
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* Show on mobile, hide on desktop (the 1170px switch). */
@media (min-width: 1170px) { .desktop-hidden { display: none !important; } }
.mt-0 { margin-top: 0 !important; }

/* All-dark pages (Privacy Policy, 404): dark body so the fixed-header
   offset never flashes a light band between chrome and content. */
body.brassica-dark-page { background: var(--bg-dark); }

/* -------------------------------------------------------------
   MODE TOGGLE — split pill, sliding gold thumb.
   The gold thumb is brand-constant. The TRACK behind the icons changes
   with the mode (dark near-black → brand light) so the toggle itself
   confirms the switch even over a full-bleed image or in the drawer.
   Light selected → thumb left (sun); dark → thumb right.
   ------------------------------------------------------------- */
.mode-toggle {
  position: relative;
  display: inline-flex;
  width: 84px; height: 40px;
  padding: 4px;
  border-radius: 999px;
  background: #231F20;                       /* dark-mode track */
  border: 1px solid var(--brand-secondary);
  transition: background 0.3s ease;
}
html:not([data-mode="dark"]) .mode-toggle { background: #F9F9F9; }   /* brand-light track */
.mode-toggle__opt {
  position: relative; z-index: 1;
  flex: 1;
  display: flex; align-items: center; justify-content: center;
  color: #797677;                            /* inactive icon: medium grey, reads on either track */
  transition: color 0.3s ease;
}
.mode-toggle__opt svg { width: 20px; height: 20px; fill: currentColor; }
.mode-toggle__thumb {
  position: absolute; top: 4px; left: 4px;
  width: calc(50% - 4px); height: calc(100% - 8px);
  border-radius: 999px;
  background: var(--brand-secondary);
  transform: translateX(100%);   /* default = dark → thumb on the moon (right) */
  transition: transform 0.32s cubic-bezier(0.2, 0.8, 0.3, 1);
}
/* Active icon (over the gold thumb) goes dark for contrast. Default dark. */
.mode-toggle__opt[data-mode="dark"] { color: #231F20; }
html:not([data-mode="dark"]) .mode-toggle__thumb { transform: translateX(0); }
html:not([data-mode="dark"]) .mode-toggle__opt[data-mode="dark"]  { color: #797677; }  /* moon now unselected → same grey */
html:not([data-mode="dark"]) .mode-toggle__opt[data-mode="light"] { color: #F9F9F9; }  /* sun matches the brand-light track */
.mode-toggle__opt:focus-visible { outline: 2px solid var(--brand-secondary); outline-offset: 3px; border-radius: 999px; }

/* Desktop: floats in the lower-right corner. */
.mode-toggle--floating {
  position: fixed; right: 20px; bottom: 20px; z-index: 150;
  box-shadow: 0 4px 14px rgba(0,0,0,0.28);
}
@media (max-width: 1169px) { .mode-toggle--floating { display: none; } }

/* Mobile: lives in the drawer, left-aligned, anchored to the bottom of the
   viewport. When submenus expand and the content grows past the screen,
   it flows below the fold and scrolls into view. */
.mobile-nav__mode {
  display: none;
  justify-content: flex-start;
  margin-top: auto;          /* push to the bottom of the flex column */
  padding-top: 32px;
}
@media (max-width: 1169px) { .mobile-nav__mode { display: flex; } }
.mode-toggle--in-menu { flex: none; }

/* 404 — full-bleed hero, image anchored to the bottom of the frame. */
.error-hero {
  position: relative;
  min-height: calc(100vh - var(--header-h));
  min-height: calc(100svh - var(--header-h));
  display: flex; align-items: center; justify-content: center;
  text-align: center;
  color: var(--text-primary-light);
  background: var(--bg-dark);
  overflow: hidden;
}
.error-hero__media { position: absolute; inset: 0; }
.error-hero__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: bottom;           /* the broken cookie stays in frame */
}
.error-hero__media::after {          /* the 30% overlay — not optional */
  content: ""; position: absolute; inset: 0;
  background: var(--overlay-image);
}
.error-hero__content {
  position: relative; z-index: 1;
  max-width: 920px;
  padding: 48px var(--side-margin);
}
.error-hero__content .lead { margin-top: var(--headline-to-body); }
.error-hero__content a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color var(--transition);
}
.error-hero__content a:hover { color: var(--brand-secondary-hover); }

/* WP admin bar coexistence */
body.admin-bar .site-header { top: calc(var(--banner-offset, 0px) + 32px); }
@media (max-width: 782px) { body.admin-bar .site-header { top: calc(var(--banner-offset, 0px) + 46px); } }

/* -------------------------------------------------------------
   Contact Us (/contact)

   A light page carrying a Jetpack form. Jetpack owns the markup, so most of
   this hangs off its classes (.grunion-field-wrap, .grunion-field-label) with
   our own .cf-* classes layered on by contact.js.

   The rule that keeps this version-tolerant: every direct child of the form
   spans the full width by default, and only field wrappers opt back into the
   two-column grid. A future Jetpack release adding a wrapper we've never seen
   then lands full-width and readable rather than wedged into half a column.
   ------------------------------------------------------------- */

/* Visually hidden, still read aloud. */
.screen-reader-text {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

.contact__wrap { max-width: var(--live-area); }

.contact__head { margin-bottom: 36px; }
.contact__title { letter-spacing: 0.08em; }
.contact__head .rule { margin: 24px 0 0; }

/* Deliberately unequal: the "required" note belongs to the form, not to the
   copy above it, so it sits close to the fields and well clear of the lede.
   Equal gaps everywhere is what made the page read as one undifferentiated
   column. */
.contact__intro { margin-bottom: 18px; }

/* One paragraph now, where there was a 36px heading and a lede beneath it.
   No top margin: it is the first thing in the intro, so the gap above it is
   the head's `margin-bottom` doing its job. Keeping `--headline-to-body` here
   would be spacing it away from a heading that no longer exists. */
.contact__lede { font-size: 18px; }

/* The FAQ link keeps its hairline underline. This lived on the retired
   `.contact__lead-in`, and moving the copy without moving this would have
   quietly restored the heavy default slab — the browser scales underline
   thickness with font size, and the fix was never about the size it happened
   to be sitting at. */
.contact__lede a {
  color: inherit;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}
.contact__required { margin-top: 38px; font-size: 15px; color: var(--text-secondary-light); }

/* --- The form grid --- */
/* Three spacing steps rather than one uniform gap. Everything on this page was
   the same distance apart, so nothing read as belonging to anything else — the
   character count floated as far from its message box as the message box sat
   from the field above it. The negative margins below are derived from the row
   gap, so changing the gap keeps every pairing proportional. */
.contact__form {
  --cf-row-gap: 28px;   /* between independent fields */
  --cf-tight: 4px;      /* a caption to the thing it describes */
  --cf-snug: 14px;      /* controls that operate together */
  --cf-tail: 32px;      /* consent line → challenge → button, as one cluster */
}
.contact__form form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--cf-row-gap) var(--gutter);
  align-items: start;
}
/* Full width unless a field opts out — see the note above. */
.contact__form form > * { grid-column: 1 / -1; margin: 0; }
.contact__form form > .grunion-field-wrap { grid-column: auto; }
.contact__form form > .cf-field--textarea { grid-column: 1 / -1; }

/* Order Number and Date Visited pair up on one row, half each, like Name and
   Email above them. A check number means nothing without the day it was rung
   up — they are one answer in two boxes, so they sit together. Both fall to
   full width with everything else on a phone. */

/* --- Fields --- */
.contact__form {
  /* Nearly invisible by design — the box is a whisper until you're in it, and
     the gold focus stroke shows where you are.

     Built from --text-primary-light, which is the text colour of a
     `.section--dark` surface and which the theme already inverts per mode. So
     this is correct in both modes with one declaration, and — unlike the
     currentColor version it replaces — it does NOT go transparent when an
     unselected select sets `color: transparent` to hide its placeholder. That
     coupling is what made the dropdown outlines disappear. */
  --cf-border: color-mix(in srgb, var(--text-primary-light) 26%, transparent);

  --cf-pad-x: 18px;
  /* A fixed control height is the whole trick behind the alignment.
     The label and chevron are positioned from the TOP of the wrapper by half
     this height — so they sit dead centre of the control and, crucially, stay
     there when Jetpack appends a validation message and makes the wrapper
     taller. Positioning from 50% of the wrapper is what dropped the label onto
     the bottom border the moment an error appeared. */
  --cf-height: 64px;
  --cf-pad-top: 26px;
  --cf-pad-bottom: 6px;
  --cf-textarea-h: 100px;
  --cf-label-sm: 13px;
}

/* Grid so the wrapper is exactly as tall as its control. The label is centred
   on the wrapper, so any stray whitespace between the two would push it off
   the middle of the visible box — which is what made the titles sit low. */
.contact__form .grunion-field-wrap { position: relative; display: grid; }

/* Jetpack wraps some controls — selects especially — in a container of its own
   that carries a border. We draw the box, so anything between the wrap and the
   control gets flattened; otherwise selects render as a box inside a box. */
.contact__form .grunion-field-wrap > div,
.contact__form .grunion-field-wrap > span {
  border: 0; padding: 0; margin: 0; background: none;
}

/* Inside a field wrapper the only things that belong are the label and the
   control. Jetpack's per-field validation text ("This field is required.")
   appears on blur, which both duplicates the summary above the button and —
   before the fix above — stretched the wrapper and dragged the label down with
   it. Written as "anything that is neither a label nor a control nor a
   container holding one", so it catches the message whatever element Jetpack
   uses and however late it is injected.

   **Anything of ours that lives inside a wrapper has to be named here.** This
   rule is a catch-all by design, and it does not care whose element it is: it
   silently swallowed `.cf-date-hint`, which is why the date format stayed
   invisible until the field was focused. It also outranks a plain
   `.contact__form .cf-date-hint` on specificity — five `:not()`s worth — so the
   fix is an exemption here, not a louder rule over there. */
.contact__form .grunion-field-wrap > *:not(label):not(input):not(select):not(textarea):not(.cf-date-hint):not(:has(input, select, textarea)) {
  display: none;
}

/* Jetpack's own confirmation, identified from the actual page source rather
   than guessed at: `.contact-form-ajax-submission` holds a summary of every
   submitted value, and the form picks up `.submission-success`. Both are hidden
   once we've put our own thank-you up.

   Scoped to `.is-sent` deliberately. If contact.js ever fails to run, Jetpack's
   plain confirmation still appears — which is ugly but truthful, and far better
   than a guest submitting into an apparently dead page. */
.contact__form.is-sent .contact-form-ajax-submission,
.contact__form.is-sent form.contact-form { display: none !important; }

/* Older Jetpack confirmation chrome, harmless to keep covered. */
.contact__form .go-back-message,
.contact__form .contact-form-submission > h4,
.contact__form blockquote.contact-form-submission { display: none; }

.contact__form .grunion-field,
.contact__form input[type="text"],
.contact__form input[type="email"],
.contact__form input[type="tel"],
.contact__form select,
.contact__form textarea {
  width: 100%;
  /* Transparent rather than a panel colour, so the fields sit on the page
     rather than on top of it — and so they follow the page in both modes
     without a second set of rules. */
  background: transparent;
  border: var(--rule-weight) solid var(--cf-border);
  border-radius: var(--radius);
  color: inherit;
  font-family: inherit;
  font-size: 17px;
  font-weight: 300;
  /* Top padding leaves room for the label to rise into. */
  padding: var(--cf-pad-top) var(--cf-pad-x) var(--cf-pad-bottom);
  transition: border-color var(--transition);
  appearance: none;
  line-height: 1.4;
}
.contact__form .grunion-field,
.contact__form input[type="text"],
.contact__form input[type="email"],
.contact__form input[type="tel"],
.contact__form select { height: var(--cf-height); }

/* An explicit height, not a min-height, because Jetpack ships rows="20" and a
   min-height loses to it — which is why this box kept rendering as a canyon.
   An explicit height makes rows irrelevant; contact.js grows it from here. */
.contact__form textarea {
  height: var(--cf-textarea-h);
  min-height: var(--cf-textarea-h);
  line-height: 1.6;
  resize: none;          /* auto-grow owns the height */
  overflow: hidden;
}
/* Active field goes gold — the one place the brand colour earns its keep here,
   marking where you are without shouting. */
.contact__form .grunion-field:focus,
.contact__form select:focus,
.contact__form textarea:focus {
  outline: none;
  border-color: var(--brand-secondary);
}
/* No separate focus ring. The site-wide `:focus-visible { outline }` rule drew
   a second gold line outside the gold border — hence the double outline. The
   border going from near-invisible to gold is a big enough change to stand on
   its own as the focus indicator. */
.contact__form .grunion-field:focus-visible,
.contact__form select:focus-visible,
.contact__form textarea:focus-visible {
  outline: none;
  border-color: var(--brand-secondary);
}

/* --- Autofill ---------------------------------------------------------
   Chrome and Safari paint autofilled fields with their own pale background,
   declared `!important` in the UA stylesheet — so `background-color` in author
   CSS loses. The way through is an inset box-shadow thick enough to cover the
   field, which the UA rule doesn't touch, plus -webkit-text-fill-color for the
   text (plain `color` loses the same argument).

   The shadow needs a real colour, and these fields are transparent — so it
   uses --bg-dark, the surface token for this section, which inverts with the
   mode like everything else here.

   **The two blocks below are deliberately NOT merged into one comma-separated
   list.** `:autofill` is standard, `:-webkit-autofill` is not; a selector list
   containing one unknown selector is invalid *in its entirety*, so merging
   them would silently disable the fix in whichever browser didn't recognise
   its neighbour. Duplication is the cost of it working in both.
   ------------------------------------------------------------------- */
.contact__form .grunion-field:-webkit-autofill,
.contact__form .grunion-field:-webkit-autofill:hover,
.contact__form .grunion-field:-webkit-autofill:focus,
.contact__form select:-webkit-autofill,
.contact__form textarea:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px var(--bg-dark) inset;
  box-shadow: 0 0 0 1000px var(--bg-dark) inset;
  -webkit-text-fill-color: var(--text-primary-light);
  caret-color: var(--text-primary-light);
  /* Chrome animates its background in on focus; an absurdly long transition
     means that animation never arrives. */
  transition: background-color 5000s ease-in-out 0s;
}

.contact__form .grunion-field:autofill,
.contact__form .grunion-field:autofill:hover,
.contact__form .grunion-field:autofill:focus,
.contact__form select:autofill,
.contact__form textarea:autofill {
  box-shadow: 0 0 0 1000px var(--bg-dark) inset;
  -webkit-text-fill-color: var(--text-primary-light);
  caret-color: var(--text-primary-light);
  transition: background-color 5000s ease-in-out 0s;
}

/* Autofill often lands without firing an input event, so the label can be left
   sitting on top of the filled-in value until contact.js re-checks. These
   raise it immediately — again in two blocks, for the reason above. */
.contact__form .grunion-field-wrap:has(input:-webkit-autofill) .grunion-field-label {
  top: 8px; transform: none;
  font-size: var(--cf-label-sm); letter-spacing: 0.02em;
}
.contact__form .grunion-field-wrap:has(input:autofill) .grunion-field-label {
  top: 8px; transform: none;
  font-size: var(--cf-label-sm); letter-spacing: 0.02em;
}

/* Chevron on the selects.
   Drawn as a masked pseudo-element filled with `currentColor` rather than a
   background SVG with a baked-in stroke — a hardcoded colour in a data URI
   can't follow the colour mode, which is exactly how the arrows stayed dark on
   the dark page. Masking means it's always the same colour as the text beside
   it, in any mode, for free.
   Hung off :has(select) rather than a JS-applied class so it exists before
   (and without) JavaScript. */
.contact__form select {
  padding-right: calc(var(--cf-pad-x) * 2 + 12px);
  cursor: pointer;
}
.contact__form .grunion-field-wrap:has(select)::after {
  content: "";
  position: absolute;
  right: var(--cf-pad-x);
  /* Same anchor as the label: centred on the control, measured from the top,
     so the two stay level whatever gets appended underneath. */
  top: calc(var(--cf-height) / 2);
  transform: translateY(-50%);
  width: 12px; height: 8px;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") center / 12px 8px no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E") center / 12px 8px no-repeat;
  pointer-events: none;
}

/* Until something is chosen, the select renders its own placeholder text in
   exactly the spot the floating label occupies, and the two overlap into one
   unreadable line. Hiding the *control's* text rather than editing Jetpack's
   markup works whatever that markup turns out to be — and leaves the option
   readable to a screen reader, which is the right outcome anyway.
   :invalid does the work with no JavaScript, since all three are required. */
.contact__form select:invalid,
.contact__form .cf-field--select:not(.is-filled) select {
  color: transparent;
  /* -webkit-text-fill-color, not just color: in WebKit and Blink the fill
     colour is what actually paints the text, and `color` alone loses to an
     inherited fill. Saying both means the closed field is blank on every
     engine rather than on most of them. */
  -webkit-text-fill-color: transparent;
}

/* ...but the options themselves stay readable, including while the control
   above is transparent.
   iOS draws its picker in the system UI and ignores all of this, which is why
   Safari looked right; Chrome draws its own list with the page's styles, so the
   placeholder row inherited the transparency meant for the closed field and
   came out blank. The two states are one element, so each has to be named. */
.contact__form select option,
.contact__form select:invalid option,
.contact__form .cf-field--select:not(.is-filled) select option {
  color: var(--text-primary-light);
  -webkit-text-fill-color: var(--text-primary-light);
}

/* --- Floating label --- */
.contact__form .grunion-field-label {
  position: absolute;
  left: var(--cf-pad-x);
  /* Half the control's height, measured from the TOP of the wrapper — not 50%
     of the wrapper. The control is the wrapper's first child, so this lands
     dead centre of the box and stays there even when Jetpack appends a
     validation message below and the wrapper grows. Positioning from 50% of
     the wrapper is exactly what dropped the label onto the bottom border the
     moment an error appeared. */
  top: calc(var(--cf-height) / 2);
  transform: translateY(-50%);
  transform-origin: left top;
  font-size: 17px;
  font-weight: 300;
  color: var(--text-secondary-light);
  pointer-events: none;      /* clicks fall through to the control */
  transition: top var(--transition), font-size var(--transition), transform var(--transition);
  max-width: calc(100% - var(--cf-pad-x) * 2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The textarea's label sits at the top from the start — the field is tall, so
   a vertically-centred label would float in the middle of nothing. */
.contact__form .cf-field--textarea .grunion-field-label,
.contact__form .grunion-field-wrap:has(textarea) .grunion-field-label {
  top: var(--cf-pad-top); transform: none;
}

.cf-field.is-focused .grunion-field-label,
.cf-field.is-filled .grunion-field-label,
/* No-JS / pre-JS fallback: :has() covers typed and browser-restored values. */
.grunion-field-wrap:has(input:not(:placeholder-shown)) .grunion-field-label,
.grunion-field-wrap:has(textarea:not(:placeholder-shown)) .grunion-field-label,
.grunion-field-wrap:has(select:focus) .grunion-field-label,
.grunion-field-wrap:focus-within .grunion-field-label,
/* A required select with nothing chosen is :invalid; once chosen it's :valid,
   which is the same signal as "has a value" and needs no JavaScript. */
.contact__form .grunion-field-wrap:has(select:valid) .grunion-field-label {
  top: 8px;
  transform: none;
  font-size: var(--cf-label-sm);
  letter-spacing: 0.02em;
}
.contact__form .cf-field--textarea.is-focused .grunion-field-label,
.contact__form .cf-field--textarea.is-filled .grunion-field-label,
.contact__form .grunion-field-wrap:has(textarea:not(:placeholder-shown)) .grunion-field-label,
.contact__form .grunion-field-wrap:has(textarea:focus) .grunion-field-label { top: 8px; }

/* Jetpack writes "(required)"; the page says asterisks mean required. */
.contact__form .grunion-label-required { font-size: 0; }
.contact__form .grunion-label-required::after { content: "*"; font-size: var(--cf-label-sm); }
.cf-field:not(.is-focused):not(.is-filled) .grunion-label-required::after { font-size: 17px; }

/* --- Counter, consent, Turnstile --- */
/* Pulled up tight under the message box — it's a caption on that field, not a
   separate item in the form. */
.cf-counter {
  margin-top: calc(var(--cf-tight) - var(--cf-row-gap));
  text-align: right;
  font-size: 15px;
  color: var(--text-secondary-light);
}
.cf-counter.is-low { color: var(--brand-secondary-hover); font-weight: 500; }

/* Date Visited's label sits at the top from the start.

   It already did, incidentally, and this rule makes that deliberate: the shared
   float rule keys off `:not(:placeholder-shown)`, and **a date input has no
   placeholder at all** — so it never matches `:placeholder-shown`, and the
   shared rule has been reading it as permanently filled. Saying it here means
   the behaviour stops depending on a side effect of a selector written for
   text fields.

   It wants to be pinned anyway: the format is in the label, and the value the
   browser draws is hidden until the field is in use, so there is nothing for a
   centred label to collide with and nothing for it to sit above.

   Order Number is NOT in this rule. It went back to an ordinary
   `placeholder=" "` when the hint line came out, so it floats like Name, Email
   and Phone. The two sit side by side and behave differently, which is right:
   only one of them is a control that draws its own text. */
.contact__form .grunion-field-wrap:has(input[name$="-datevisited"]) .grunion-field-label {
  top: 8px;
  transform: none;
  font-size: var(--cf-label-sm);
  letter-spacing: 0.02em;
}

/* An empty date field shows `mm/dd/yyyy` at full size, under the small label.
 *
 * Which takes two rules working together, because the browsers can't agree on
 * what an empty date input looks like: desktop Chrome and Firefox print the
 * format, **iOS prints nothing at all**. Neither behaviour can be relied on, so
 * the visible text while empty is a span we render ourselves, and the browser's
 * own copy is suppressed for exactly as long as ours is showing.
 *
 * Handing over on focus matters on desktop: from that point the guest is typing
 * into the browser's own segments, and those have to be the ones on screen.
 *
 * Hidden with `color: transparent` rather than `visibility`, so the field keeps
 * its height and nothing shifts at the handover.
 *
 * `.is-filled` comes from our own floating-label script — not `:valid`, because
 * this field is optional and an empty one is perfectly valid, so that rule would
 * never hide anything. */
.contact__form input[type="date"]:not(:focus)::-webkit-datetime-edit {
  color: transparent;
}
.contact__form .grunion-field-wrap.is-filled input[type="date"]::-webkit-datetime-edit {
  color: inherit;
}

/* Our stand-in, sitting exactly where a date would: the input's own top and
   left padding, at the input's own size. Not the label's size — this is
   standing in for a value, and reading it as a value is the point. */
.contact__form .cf-date-hint {
  position: absolute;
  left: var(--cf-pad-x);
  top: var(--cf-pad-top);
  font-size: 17px;
  font-weight: 300;
  line-height: 1.4;
  color: var(--text-secondary-light);
  pointer-events: none;   /* the click belongs to the input underneath */
}

/* Gone the moment the field is in use, so ours and the browser's are never
   both on screen. */
.contact__form .grunion-field-wrap:focus-within .cf-date-hint,
.contact__form .grunion-field-wrap.is-filled .cf-date-hint {
  display: none;
}

/* Firefox, which needs no help.
   It prints `mm/dd/yyyy` on its own and ignores `::-webkit-datetime-edit`, so
   the rule that suppresses the native copy never reaches it — leaving ours
   sitting directly on top of an identical string. Both say the same thing in
   the same place, so it reads as slightly heavy text rather than as two hints,
   but there's no reason to draw it twice. `-moz-appearance` is the narrowest
   honest test for "this is Gecko"; if it ever stops answering, the fallback is
   the harmless overlap we have today rather than a missing hint. */
@supports (-moz-appearance: none) {
  .contact__form .cf-date-hint { display: none; }
}

/* **Where it puts the value.** iOS centres it in the box while every other
   field on this form is left-aligned, so a chosen date sat visibly out of line
   with the answer above it. `text-align` on the input alone doesn't reach it:
   the value lives in a shadow pseudo-element that has to be named directly. */
.contact__form input[type="date"] {
  text-align: left;
}
.contact__form input[type="date"]::-webkit-date-and-time-value {
  text-align: left;
  margin: 0;
}
.contact__form input[type="date"]::-webkit-datetime-edit {
  text-align: left;
}

/* The calendar button is a browser-drawn icon with a fixed dark glyph, so it
   vanishes once this section's background goes dark. `invert()` is the only
   lever CSS has on it.

   Inverted under `[data-mode="dark"]` and left alone otherwise, because **light
   is this theme's default**: `html:not([data-mode="dark"])` also matches an
   `<html>` with no attribute at all, so the light-mode token block is already
   in force before anyone touches the toggle. Dark is the opt-in. Writing this
   the other way round — invert by default, undo for light — would have left the
   icon inverted on a light page for every first-time visitor. */
.contact__form input[type="date"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: 0.7;
}
.contact__form input[type="date"]::-webkit-calendar-picker-indicator:hover {
  opacity: 1;
}
html[data-mode="dark"] .contact__form input[type="date"]::-webkit-calendar-picker-indicator {
  filter: invert(1);
}


.cf-consent { font-size: 15px; color: var(--text-secondary-light); }
.cf-consent a { color: inherit; text-underline-offset: 3px; text-decoration-thickness: 1px; }
/* The arrow rides with the link text, so it can't wrap onto a line of its own
   and leave a stray glyph hanging under the sentence. */
.cf-consent__link { white-space: nowrap; }
.cf-consent__icon {
  display: inline-block;
  width: 11px; height: 11px;
  margin-left: 5px;
  vertical-align: baseline;
  text-decoration: none;
}
.cf-consent__icon svg { width: 100%; height: 100%; display: block; fill: currentColor; }

/* No reserved height. With appearance="interaction-only" the widget usually
   never draws, and a min-height would hold open an empty 65px band under the
   consent line for every guest who sails through — which is most of them.
   On the rare occasion a challenge is needed it appears and pushes the button
   down, which is the correct moment for the layout to move. */
.cf-turnstile-wrap:empty { display: none; }

/* Jetpack leaves empty containers between fields, and each one takes a whole
   grid row plus its gaps — the reason the button sat so far from everything
   else. Empty means empty: nothing is lost by collapsing them. */
.contact__form form > div:empty,
.contact__form form > p:empty,
.contact__form form > span:empty { display: none; }

/* Jetpack keeps two `.contact-form__error` containers permanently in the form,
   revealed by adding `show-errors`. They are not `:empty` — each holds a
   warning icon and a list — so they were quietly taking a full grid row apiece
   between the consent line and the button. That, not the Turnstile, was the
   gap. Hidden until they have something to say. */
.contact__form form > .contact-form__error:not(.show-errors) { display: none; }

/* The tail of the form — consent line, optional challenge, button — is one
   cluster, tighter than the gap between independent fields.
   Uses the general sibling combinator from the consent line rather than naming
   the button: the button's wrapper isn't something we can see, and an earlier
   attempt aimed this at "whatever follows the Turnstile", which turned out to
   be one of the hidden error divs above. Elements that are display:none
   contribute nothing, so the spacing is the same whether the challenge draws
   or not. */
.contact__form form > .cf-consent ~ * {
  margin-top: calc(var(--cf-tail) - var(--cf-row-gap));
}

/* --- Submit --- */
/* A grid item stretches by default, which is what made this span the whole
   row. Pin it to the start and let the button size to its own content. */
.contact__form .contact-submit { margin: 0; }
/* Pulled up close to the Turnstile widget: the challenge and the button are one
   action, and a full row's gap made them read as unrelated. */
.contact__form form > .contact-submit,
.contact__form form > button[type="submit"],
.contact__form form > input[type="submit"] {
  justify-self: start;
  margin-top: calc(var(--cf-snug) - var(--cf-row-gap));
}

.contact__form button[type="submit"],
.contact__form input[type="submit"] {
  display: inline-flex; align-items: center; justify-content: center;
  width: auto;
  min-width: var(--btn-min-width);
  height: var(--btn-height-md);
  padding: 10px 16px;
  background: transparent;
  border: var(--stroke-button) solid var(--brand-secondary);
  border-radius: var(--radius);
  color: var(--text-primary-light);
  font-family: inherit; font-size: 14px; font-weight: 600;
  letter-spacing: 0.09em; text-transform: none;
  cursor: pointer;
  transition: border-color var(--transition), letter-spacing var(--transition);
}
.contact__form button[type="submit"]:hover,
.contact__form input[type="submit"]:hover {
  border-color: var(--brand-secondary-hover);
  letter-spacing: 0.08em;
}

/* Inactive until every required field has something in it.
   Deliberately NOT the `disabled` attribute: a disabled button can't be
   focused, gives no reason why, and leaves a guest tapping a dead control with
   no idea what's missing. This stays clickable — so the click runs the
   browser's own validation, which jumps to the first empty field and says what
   it needs — while looking clearly not-yet-ready. */
.contact__form button[type="submit"][aria-disabled="true"],
.contact__form input[type="submit"][aria-disabled="true"] {
  opacity: 0.4;
  border-color: var(--cf-border);
}
.contact__form button[type="submit"][aria-disabled="true"]:hover,
.contact__form input[type="submit"][aria-disabled="true"]:hover {
  border-color: var(--cf-border);
  letter-spacing: 0.09em;
}

/* --- Errors --- */
/* Jetpack's own error block, plus our Turnstile message. Gold rather than red:
   these are "try again" messages, not destructive warnings, and red on this
   palette reads as an alarm the situation doesn't warrant. */
.contact__form .form-error,
.contact__form .contact-form-errors {
  grid-column: 1 / -1;
  color: var(--brand-secondary-hover);
  font-size: 16px; line-height: 1.5;
}
/* Jetpack's generic heading ("Please fill out the form correctly.") sits above
   its own list of specifics. The list says what's actually wrong; the heading
   just tells an adult they made a mistake.
   Cast wide deliberately — the previous attempt assumed h3/h4 as a direct
   child and missed. There is no heading inside this form we want to keep, so
   hiding all of them is safe as well as effective. contact.js also sweeps for
   the exact string, in case it isn't a heading at all. */
.contact__form form h2,
.contact__form form h3,
.contact__form form h4,
.contact__form .form-error h2,
.contact__form .form-error h3,
.contact__form .form-error h4,
.contact__form .contact-form-errors h2,
.contact__form .contact-form-errors h3,
.contact__form .contact-form-errors h4 { display: none; }
.contact__form .form-error ul,
.contact__form .contact-form-errors ul { margin: 0; padding: 0; list-style: none; }
.contact__form .form-error a,
.contact__form .contact-form-errors a { color: inherit; }
.contact__form .grunion-field-wrap.grunion-error .grunion-field { border-color: var(--brand-secondary-hover); }

/* --- Success state --- */
.cf-sent { max-width: 100%; }
.cf-sent:focus { outline: none; }
.cf-sent:focus-visible { outline: 2px solid var(--brand-secondary-hover); outline-offset: 6px; }
.cf-sent__title { font-size: 36px; font-weight: 300; line-height: 1.25; }
.cf-sent__body { margin-top: var(--headline-to-body); font-size: 18px; }
.cf-sent__media { margin-top: 48px; }
.cf-sent__media img { width: 100%; height: auto; display: block; }

@media (max-width: 1169px) {
  /* Override the variable, not the gap — the tightened pairings are derived
     from it, so they stay proportional on a phone instead of inverting. */
  .contact__form { --cf-row-gap: 22px; }
  .contact__form form { grid-template-columns: 1fr; }
  .contact__form form > .grunion-field-wrap { grid-column: 1 / -1; }
  /* The lede is body copy at every width now, so there is no headline step to
     scale down here — the 26px rule that used to live on this line belonged to
     the retired heading. */
  .cf-sent__title { font-size: 26px; }
  .contact__head { margin-bottom: 32px; }
  .contact__intro { margin-bottom: 32px; }
  /* 16px stops iOS zooming the page when a field takes focus. */
  .contact__form .grunion-field,
  .contact__form select,
  .contact__form textarea { font-size: 16px; }
  /* Full width is right on a phone — a thumb-sized target beats a tidy one. */
  .contact__form form > .contact-submit,
  .contact__form form > button[type="submit"],
  .contact__form form > input[type="submit"] { justify-self: stretch; }
  .contact__form button[type="submit"],
  .contact__form input[type="submit"] { width: 100%; }
}

/* Dark mode. Only the border token and the option list need saying — the
   fields are transparent, the text is inherited, and the chevron is masked
   currentColor, so all three follow the mode on their own. */
/* No [data-mode="dark"] block here any more. Every colour on this page is now
   expressed in the tokens for a `.section--dark` surface, and the theme already
   flips those per mode — so a second set of overrides would be a second place
   to keep in step, and the first place to fall out of step.
   The option list is the one exception: it's drawn by the OS, so it gets an
   explicit pair rather than inheriting. */
.contact__form select option {
  color: var(--text-primary-light);
  -webkit-text-fill-color: var(--text-primary-light);
  background-color: var(--bg-dark);
}

/* State subheads in the Restaurant list.
   How much of this lands is up to the browser — the dropdown list is an OS
   widget, and most platforms accept little more than colour and weight on an
   optgroup label, some accept none of it. That is survivable here, because the
   grouping is carried by the markup rather than the styling: <optgroup> is
   already announced as a group and already unselectable, with or without a
   single one of these declarations. The styling is the polish, not the
   mechanism. */
.contact__form select optgroup {
  color: var(--text-secondary-light);
  background-color: var(--bg-dark);
  font-weight: 600;
  font-style: normal;
}

.contact__form select optgroup option {
  color: var(--text-primary-light);
  -webkit-text-fill-color: var(--text-primary-light);
  font-weight: 400;
}

@media (prefers-reduced-motion: reduce) {
  .contact__form .grunion-field-label { transition: none; }
}

/* The `hidden` attribute has to beat our own display rules — .btn is
   inline-flex and .accordion is flex, and any author rule outranks the
   browser's built-in [hidden] { display: none }. Declared last so source
   order settles the tie; more specific rules (.tabs__panel[hidden] on
   mobile) still win. */
[hidden] { display: none; }
