/* ============================================================================
   ONE DAY — Fall Festival 2026 · Denver
   Design system: "Sunset over the Front Range"
   Palette lifted from the event flyer. No external CSS deps.
   ========================================================================= */

/* No @view-transition here on purpose. Cross-document transitions froze the
   incoming page when navigation started while the mobile drawer was open and
   body overflow was locked: the new page rendered but could not scroll and
   never finished painting. Not worth the polish. */

/* ---------- Tokens ------------------------------------------------------ */
:root {
  /* Sampled from the client's own flyer by band-quantizing each region of the
     artwork, not eyeballed. Percentages are that colour's share of its band.
       #0E0D26  foreground/skyline (59% of the headline band)
       #FFE8C5  "ONE DAY" headline cream (28%)
       #EC8D55  tagline orange (27%)
       #F4B765  amber panel behind the date + activity list (44%)
       #DA2A21  mountain red (25% of the mountain band)
       #542428  mountain shadow / "OCTOBER 10" text (19%)
       #FCA721  sun gold (12%)   #F37A2F  sun outer (18%)
       #EC7723  "WHERE FAITH..." accent line (20%) */
  --ink:        #0E0D26;
  --ink-2:      #171634;
  --ink-3:      #241F42;
  --ember:      #EC7723;   /* flyer accent orange — CTA fill, ink type on it = 6.3:1 */
  --rust:       #C65E26;   /* one-pager heading rust, recurring in both documents */
  --paper:      #F5E6D1;   /* one-pager panel tint — the soft light surface */
  --char:       #1C1C1C;   /* one-pager body ink */
  --brick:      #DA2A21;   /* flyer mountain red — kept for small emphasis only */
  --flame:      #EC7723;   /* their accent line orange, 6.3:1 on ink */
  --tagline:    #EC8D55;   /* the softer tagline orange, used verbatim */
  --sun:        #FCA721;
  --amber:      #F4B765;
  --sand:       #F4B765;
  --maroon:     #542428;
  --cream:      #FFE8C5;
  --cream-dim:  #E2CBAA;

  --bg:         var(--ink);
  --fg:         var(--cream);
  --muted:      #B6A392;   /* 6.97:1 on --ink */
  --hairline:   color-mix(in oklab, var(--cream) 14%, transparent);
  --card:       color-mix(in oklab, var(--ink-2) 88%, var(--ember) 12%);

  /* Type */
  --display: "Montserrat", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --body:    "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* Fluid scale */
  --step--1: clamp(.82rem, .78rem + .2vw, .93rem);
  --step-0:  clamp(1rem, .95rem + .25vw, 1.13rem);
  --step-1:  clamp(1.2rem, 1.1rem + .5vw, 1.5rem);
  --step-2:  clamp(1.5rem, 1.3rem + 1vw, 2.1rem);
  --step-3:  clamp(1.9rem, 1.5rem + 2vw, 3rem);
  --step-4:  clamp(2.4rem, 1.7rem + 3.4vw, 4.5rem);
  --step-5:  clamp(3.2rem, 1.8rem + 6.5vw, 8rem);

  /* Space */
  --gutter: clamp(1.1rem, 4vw, 2.5rem);
  --section: clamp(4rem, 9vw, 8rem);
  --measure: 66ch;
  --radius: 18px;
  --radius-sm: 12px;

  --shadow: 0 24px 60px -24px rgb(0 0 0 / .75);
  --ring: 0 0 0 3px color-mix(in oklab, var(--sun) 55%, transparent);
}

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

body {
  font-family: var(--body);
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

/* `overflow-x: hidden` on body makes its overflow-y compute to `auto`, promoting
   body to a scroll container — a classic source of iOS scroll jank. `clip` blocks
   sideways overflow without creating a scroll box. */
html { overflow-x: hidden; }
@supports (overflow: clip) { html { overflow-x: clip; } }

img, svg, video { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }
:focus-visible { outline: none; box-shadow: var(--ring); border-radius: 6px; }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 800;
  line-height: .98;
  letter-spacing: -.02em;
  text-wrap: balance;
}

/* ---------- Layout ------------------------------------------------------ */
.wrap { width: min(1200px, 100% - var(--gutter) * 2); margin-inline: auto; }
.wrap--narrow { width: min(760px, 100% - var(--gutter) * 2); }
.section { padding-block: var(--section); position: relative; }
.section p, .section li { color: var(--cream-dim); }
.stack > * + * { margin-top: 1rem; }
.lede { font-size: var(--step-1); color: var(--cream-dim); max-width: var(--measure); text-wrap: pretty; }

.eyebrow {
  font-family: var(--display);
  font-size: var(--step--1);
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--amber);
  display: flex; align-items: center; gap: .7rem;
}
.eyebrow::before {
  content: ""; width: 2.2rem; height: 2px; flex: none;
  background: linear-gradient(90deg, var(--flame), transparent);
}
.eyebrow--center { justify-content: center; }
.eyebrow--center::after {
  content: ""; width: 2.2rem; height: 2px; flex: none;
  background: linear-gradient(270deg, var(--flame), transparent);
}

/* ---------- Skip link --------------------------------------------------- */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--sun); color: var(--ink); padding: .8rem 1.2rem; font-weight: 700;
}
.skip:focus { left: 1rem; top: 1rem; }

/* ---------- Header ------------------------------------------------------ */
.site-header {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 100; isolation: isolate;
  transition: background .35s ease, box-shadow .35s ease;
}
.site-header::before {
  content: ""; position: absolute; inset-block-start: 0; inset-inline: 0; height: 190%;
  z-index: -1; pointer-events: none;
  background: linear-gradient(180deg, rgb(14 13 38 / .72) 0%, rgb(14 13 38 / .38) 55%, transparent 100%);
  transition: opacity .35s ease;
}
.site-header[data-scrolled="true"]::before { opacity: 0; }
.site-header[data-scrolled="true"] {
  background: color-mix(in oklab, var(--ink) 88%, transparent);
  box-shadow: 0 1px 0 var(--hairline);
}
/* ⚠️ The frosted blur MUST live on a pseudo-element, never on .site-header itself.
   backdrop-filter (like transform and filter) makes an element a containing block for
   position:fixed descendants — and the mobile drawer is a descendant of the header. With the
   blur on the header, opening the menu while scrolled clipped the drawer to the header's ~76px
   box: it rendered as a tiny crunched panel showing only the first link. At scroll 0 there was
   no blur and therefore no bug, which is why it only ever misbehaved once you scrolled. */
.site-header::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  -webkit-backdrop-filter: saturate(1.4) blur(14px); backdrop-filter: saturate(1.4) blur(14px);
  opacity: 0; transition: opacity .35s ease;
}
.site-header[data-scrolled="true"]::after { opacity: 1; }
.nav { display: flex; align-items: center; gap: 1.5rem; padding-block: .95rem; }
/* Landscape on a notched iPhone puts the notch over the leading edge, which slid the logo
   underneath it. The drawer got env() insets when it was built; the header never did. */
@supports (padding: env(safe-area-inset-left)) {
  /* With viewport-fit=cover the page now runs edge to edge, so the header's background reaches
     the real top of the screen instead of starting below the status bar. Pad the CONTENT down
     out of the notch so only the background lives up there. */
  .site-header .wrap {
    padding-inline-start: max(var(--gutter), env(safe-area-inset-left));
    padding-inline-end: max(var(--gutter), env(safe-area-inset-right));
  }
  .site-header .nav { padding-block-start: calc(.95rem + env(safe-area-inset-top)); }
  .nav__links { padding-block-start: calc(6rem + env(safe-area-inset-top)); }
  body { padding-inline: 0; }
}

.brand { display: flex; align-items: center; gap: .7rem; text-decoration: none; margin-inline-end: auto; }
.brand__mark { width: 38px; height: 38px; flex: none; color: var(--ember);
  transition: color .25s ease, transform .25s cubic-bezier(.34,1.56,.64,1); }
.brand:hover .brand__mark { color: var(--sun); transform: rotate(-6deg) scale(1.06); }
.brand__text { font-family: var(--display); font-weight: 800; letter-spacing: -.03em; font-size: 1.26rem; line-height: 1; }
.brand__text span { color: var(--ember); }
.brand__sub { display: block; font-family: var(--body); font-weight: 500; font-size: .62rem;
  letter-spacing: .19em; text-transform: uppercase; color: var(--cream-dim); margin-top: .26rem; }

.nav__links { display: flex; align-items: center; gap: .35rem; list-style: none; padding: 0; }
.nav__links a:not(.btn) {
  display: block; padding: .55rem .8rem; border-radius: 999px; text-decoration: none;
  font-size: .95rem; font-weight: 500; color: var(--cream-dim);
  transition: color .2s ease, background .2s ease;
}
.nav__links a:not(.btn):hover { color: var(--cream); background: color-mix(in oklab, var(--cream) 8%, transparent); }
.nav__links a:not(.btn)[aria-current="page"] { color: var(--sun); }
.nav__links a.btn { text-decoration: none; }
.nav__meta { display: none; }   /* drawer-only; revealed in the mobile nav media query */

.nav__toggle {
  display: none; background: none; border: 1px solid var(--hairline);
  border-radius: 10px; padding: .6rem; cursor: pointer;
  min-width: 46px; min-height: 46px; align-items: center; justify-content: center;
}
/* One morphing icon, not two SVGs swapped with display:none. The three bars rotate into the
   X, which reads as a state change rather than a substitution. */
.nav__burger { display: block; position: relative; width: 22px; height: 16px; }
.nav__burger i {
  position: absolute; inset-inline: 0; height: 2px; border-radius: 2px; background: currentColor;
  transition: transform .34s cubic-bezier(.2,.85,.25,1), opacity .18s ease .06s;
}
.nav__burger i:nth-child(1) { inset-block-start: 0; }
.nav__burger i:nth-child(2) { inset-block-start: 7px; }
.nav__burger i:nth-child(3) { inset-block-start: 14px; }
.nav__toggle[aria-expanded="true"] .nav__burger i:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav__toggle[aria-expanded="true"] .nav__burger i:nth-child(2) { opacity: 0; transform: scaleX(.15); }
.nav__toggle[aria-expanded="true"] .nav__burger i:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }


/* ---------- Buttons ----------------------------------------------------- */
.btn {
  --btn-bg: var(--ember);
  --btn-fg: #16101F;
  display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
  padding: .9rem 1.6rem; border-radius: 999px; border: 1px solid transparent;
  background: var(--btn-bg); color: var(--btn-fg);
  font-family: var(--display); font-weight: 700; font-size: .98rem; letter-spacing: -.01em;
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: transform .18s cubic-bezier(.34,1.56,.64,1), filter .18s ease, box-shadow .18s ease;
  box-shadow: 0 10px 30px -12px color-mix(in oklab, var(--ember) 65%, transparent);
}
.btn:hover { transform: translateY(-2px) scale(1.015); filter: brightness(1.07); }
.btn:active { transform: translateY(0) scale(.98); }
.btn--sun { --btn-bg: var(--sun); --btn-fg: var(--ink); box-shadow: 0 10px 30px -12px color-mix(in oklab, var(--sun) 70%, transparent); }
.btn--ghost {
  --btn-bg: transparent; --btn-fg: var(--cream);
  border-color: color-mix(in oklab, var(--cream) 30%, transparent); box-shadow: none;
}
.btn--ghost:hover { background: color-mix(in oklab, var(--cream) 8%, transparent); }
.btn--sm { padding: .62rem 1.1rem; font-size: .88rem; }
.btn--lg { padding: 1.1rem 2rem; font-size: 1.08rem; }
.btn-row { display: flex; flex-wrap: wrap; gap: .8rem; }

/* ---------- Hero -------------------------------------------------------- */
/* Drawn in CSS + SVG, not the flyer raster. Owner's call. Every colour is
   sampled from the flyer so it stays on-brand. */
.hero { position: relative; min-height: 100svh; display: grid; align-items: end;
  isolation: isolate; overflow: hidden; background: var(--ink); }

.hero__sky { position: absolute; inset: 0; z-index: -3;
  background: radial-gradient(120% 78% at 50% 74%,
    #FFD48A 0%, #F4B765 22%, #FCA721 40%, #F37A2F 56%, #DA2A21 70%, #542428 84%, var(--ink) 100%); }

/* The flyer's sun is a FLAT disc with a crisp rim, not a soft blob. The element
   IS the disc, so the rim can be a real ring and the halo can bloom outside it. */
.hero__sun {
  position: absolute; z-index: -2; left: 50%; bottom: 32%;
  width: min(30vw, 306px); aspect-ratio: 1; translate: -50% 0; border-radius: 50%;
  background: radial-gradient(circle at 50% 38%, #FFF3CE 0%, #FFD873 34%, #FDBC49 66%, #F9A21C 100%);
  box-shadow:
    0 0 0 2px #FFEFC0,                         /* the crisp rim, a hard edge not a blur */
    0 0 0 5px rgb(232 128 31 / .85),           /* the rim's own darker outline, as on the flyer */
    0 0 0 12px rgb(252 167 33 / .28),          /* inner bloom */
    0 0 100px 38px rgb(253 170 60 / .45),      /* halo */
    0 0 210px 90px rgb(240 120 40 / .26);      /* far glow */
  animation: sun-rise 2.6s cubic-bezier(.16,1,.3,1) both;
}
@keyframes sun-rise { from { translate: -50% 30%; opacity: 0; } to { translate: -50% 0; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .hero__sun { animation: none; } }

.hero__crestwrap { position: absolute; inset-inline: 0; inset-block-start: 0; z-index: -1;
  display: grid; place-items: center; padding-top: clamp(4.6rem, 9vh, 6rem); pointer-events: none; }
.hero__crest { width: clamp(88px, 11.5vh, 132px); height: auto;
  filter: drop-shadow(0 3px 16px rgb(70 28 4 / .34)); }

.hero__birds { position: absolute; inset-inline: 0; inset-block-start: 0; height: 60%; z-index: -1;
  pointer-events: none; opacity: .85; }
.hero__birds svg { width: 100%; height: 100%; }

/* Silhouette on a solid slab that runs to the bottom, else sky leaks under it. */
.hero__ridge { position: absolute; inset-inline: 0; inset-block-end: 0; z-index: -1;
  display: flex; flex-direction: column; pointer-events: none; }
.hero__ridge svg { width: 100%; display: block; fill: currentColor; flex: none; }
.hero__ridge::after { content: ""; flex: 1 1 auto; background: currentColor; }
.hero__ridge--far  { color: #DA2A21; height: 50%; }
.hero__ridge--far  svg { height: clamp(56px, 9vw, 130px); }
.hero__ridge--mid  { color: #6B2A2C; height: 30%; }
.hero__ridge--mid  svg { height: clamp(46px, 8vw, 110px); }
.hero__ridge--near { color: #0B0A1E; height: 26%; }
.hero__ridge--near svg { height: clamp(120px, 19vw, 265px); }

.hero__scrim { position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: linear-gradient(180deg, rgb(14 13 38 / .38) 0%, rgb(14 13 38 / 0) 18%,
    rgb(14 13 38 / 0) 40%, rgb(14 13 38 / .16) 55%, rgb(14 13 38 / .62) 70%, rgb(14 13 38 / .93) 100%); }

.hero__inner { padding-block: clamp(5rem, 11vh, 7.5rem) clamp(3.2rem, 7vh, 5rem); position: relative; }
.hero__title { font-size: var(--step-5); font-weight: 900; letter-spacing: -.045em; line-height: .82;
  color: var(--cream); text-transform: uppercase; text-shadow: 0 8px 40px rgb(0 0 0 / .5); }
.hero__tagline { font-family: var(--display); font-weight: 800; text-transform: uppercase;
  font-size: clamp(1rem, .55rem + 2vw, 2rem); letter-spacing: -.01em;
  color: #FF9A52; margin-top: .55rem; text-shadow: 0 2px 18px rgb(0 0 0 / .7); }
.hero .eyebrow {
  color: #FFF1D2; width: max-content; align-self: start;
  background: rgb(14 13 38 / .78); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  padding: .42rem 1rem; border-radius: 999px; letter-spacing: .2em;
  text-shadow: 0 1px 6px rgb(0 0 0 / .5);
}
.hero .eyebrow::before { display: none; }
.hero__meta { display: flex; flex-wrap: wrap; gap: .45rem 1.6rem; margin-top: 1.3rem;
  font-size: var(--step-0); color: var(--cream); text-shadow: 0 2px 12px rgb(0 0 0 / .5); }
.hero__meta span { display: inline-flex; align-items: center; gap: .5rem; }
.hero__meta svg { width: 1.1em; height: 1.1em; flex: none; color: var(--sun); }
.hero .btn-row { margin-top: 1.6rem; }

.hero__scroll { position: absolute; left: 50%; bottom: .5rem; translate: -50% 0;
  font-size: .7rem; letter-spacing: .2em; text-transform: uppercase; color: var(--cream-dim);
  display: grid; justify-items: center; gap: .4rem; }
.hero__scroll i { display: block; width: 1px; height: 34px;
  background: linear-gradient(var(--cream-dim), transparent); animation: nudge 2s ease-in-out infinite; }
@keyframes nudge { 0%,100% { opacity: .3; transform: translateY(-4px); } 50% { opacity: 1; transform: translateY(2px); } }
@media (max-width: 700px) { .hero__sun { bottom: 47%; width: min(50vw, 240px); } }

@media (max-height: 780px), (max-width: 700px) { .hero__scroll { display: none; } }

@media (max-height: 700px) {
  .hero__inner { padding-block: 4.2rem 1.6rem; }
  .hero__title { font-size: clamp(2.6rem, 13vw, 4rem); }
  .hero__meta { gap: .25rem 1.1rem; margin-top: .8rem; font-size: .92rem; }
  .countdown { margin-top: .9rem; gap: .4rem; }
  .count-unit { min-width: 60px; padding: .5rem .6rem; }
  .count-unit b { font-size: 1.3rem; }
  .hero .btn-row { margin-top: 1rem; }
  .hero .btn--lg { padding: .85rem 1.4rem; font-size: .98rem; }
}

/* ---------- Countdown --------------------------------------------------- */
.countdown { display: flex; flex-wrap: wrap; gap: .55rem; margin-top: 1.5rem; }
.count-unit {
  min-width: 74px; padding: .7rem .85rem; border-radius: var(--radius-sm);
  background: color-mix(in oklab, var(--ink) 55%, transparent);
  border: 1px solid color-mix(in oklab, var(--cream) 18%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); text-align: center;
}
.count-unit b {
  display: block; font-family: var(--display); font-weight: 800; font-size: 1.7rem;
  line-height: 1; font-variant-numeric: tabular-nums; color: var(--cream);
}
.count-unit small { font-size: .62rem; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }

/* ---------- Ticker ------------------------------------------------------ */
.ticker {
  background: var(--ember); color: #16101F; overflow: hidden; padding-block: .7rem;
  border-block: 1px solid color-mix(in oklab, #000 25%, transparent);
}
.ticker__track { display: flex; gap: 2.5rem; width: max-content; animation: marquee 38s linear infinite; }
.ticker__track span {
  font-family: var(--display); font-weight: 800; text-transform: uppercase;
  letter-spacing: .04em; font-size: .95rem; display: inline-flex; align-items: center; gap: 2.5rem;
}
.ticker__track span::after { content: "★"; opacity: .6; }
@keyframes marquee { to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) { .ticker__track { animation: none; } }

/* ---------- Cards / grids ---------------------------------------------- */
.grid { display: grid; gap: 1.2rem; }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }

.card {
  background: var(--card); border: 1px solid var(--hairline); border-radius: var(--radius);
  padding: 1.5rem; position: relative; overflow: hidden;
  transition: transform .3s cubic-bezier(.2,.8,.2,1), border-color .3s ease, box-shadow .3s ease;
}
.card:hover { transform: translateY(-4px); border-color: color-mix(in oklab, var(--amber) 45%, transparent); }
.card h3 { font-size: var(--step-1); margin-bottom: .5rem; }
.card p { color: var(--cream-dim); font-size: .97rem; }
.card__num {
  font-family: var(--display); font-weight: 900; font-size: 3.4rem; line-height: 1;
  color: #B0621F; margin-bottom: .3rem;
}

/* Photo cards */
.photo-card { border-radius: var(--radius); overflow: hidden; position: relative; isolation: isolate; }
.photo-card__media { aspect-ratio: 4 / 3; position: relative; background: linear-gradient(150deg, var(--ink-3), var(--ink-2)); }
.photo-card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s cubic-bezier(.2,.8,.2,1); }
.photo-card:hover .photo-card__media img { transform: scale(1.05); }
.photo-card__body {
  position: absolute; z-index: 2; inset-block-end: 0; inset-inline: 0; padding: 1.4rem 1.3rem 1.2rem;
  background: linear-gradient(transparent, rgb(8 7 22 / .55) 30%, rgb(8 7 22 / .93));
}
.photo-card__body h3 { font-size: var(--step-1); }
.photo-card__body p { font-size: .9rem; color: var(--cream-dim); margin-top: .25rem; }
.photo-card__tag {
  position: absolute; inset-block-start: .9rem; inset-inline-start: .9rem; z-index: 2;
  background: #120E22; color: #FFD277;
  font-family: var(--display); font-weight: 700; font-size: .68rem;
  letter-spacing: .13em; text-transform: uppercase; padding: .35rem .7rem; border-radius: 999px;
}

/* Image placeholder — a missing photo still looks designed, never broken. */
.ph { position: relative; background: linear-gradient(150deg, #3A2340, #241A34 55%, #1A1428); }
.ph::after {
  content: attr(data-ph); position: absolute; inset: 0; display: grid; place-content: center;
  text-align: center; padding: 1rem; font-family: var(--display); font-weight: 700;
  font-size: .72rem; letter-spacing: .16em; text-transform: uppercase;
  color: color-mix(in oklab, var(--sand) 55%, transparent);
}
.ph img { position: relative; z-index: 1; }
.ph img[hidden] { display: none; }

/* ---------- Light surfaces ---------------------------------------------- */
/* Two reviewers measured the same thing independently: navy is ~20% of the
   flyer but was running 60%+ of this site's scroll. These give the page an
   alternating rhythm of warm light bands with dark used as punctuation. */
.section--paper { background: var(--paper); color: var(--char); }
.section--paper h2, .section--paper h3, .section--paper h4 { color: var(--maroon); }
.section--paper p, .section--paper li, .section--paper .lede { color: #33262B; }
.section--paper .eyebrow { color: #9E3F14; }
.section--paper .eyebrow::before { background: linear-gradient(90deg, #9E3F14, transparent); }
.section--paper .eyebrow--center::after { background: linear-gradient(270deg, #9E3F14, transparent); }
.section--paper .card,
.section--paper .builder,
.section--paper .faq details { background: #FFFFFF; border-color: rgb(84 36 40 / .16); color: var(--char); }
.section--paper .card p { color: #4A3A3E; }
.section--paper .card__num { color: color-mix(in oklab, var(--rust) 34%, transparent); }
.section--paper .stats { background: rgb(84 36 40 / .16); border-color: rgb(84 36 40 / .18); }
.section--paper .stat { background: #FFFFFF; }
.section--paper .stat b { color: var(--rust); }
.section--paper .stat small { color: #6B575C; }
.section--paper .btn--ghost { --btn-fg: var(--maroon); border-color: rgb(84 36 40 / .42); }
.section--paper .btn--ghost:hover { background: rgb(84 36 40 / .08); }
.section--paper .tier ul { color: #4A3A3E; }
.section--paper .tier li::before { color: var(--rust); }
.section--paper .faq summary { color: var(--maroon); }
.section--paper .faq summary::after { color: var(--rust); }
.section--paper .faq p { color: #4A3A3E; }
.section--paper .seg-tabs button { border-color: rgb(84 36 40 / .35); color: #5A464B; }
.section--paper .seg-tabs button[aria-selected="true"] { background: var(--ember); border-color: var(--ember); color: #16101F; }
.section--paper .timeline time { color: var(--rust); }
.section--paper .chip { background: rgb(84 36 40 / .06); border-color: rgb(84 36 40 / .22); color: #4A3A3E; }
.section--paper .builder__out { background: rgb(84 36 40 / .05); border-color: rgb(84 36 40 / .25); color: #4A3A3E; }
.section--paper .builder__out b { color: var(--rust); }

/* ---------- Amber panel ------------------------------------------------- */
/* Their flyer is roughly 76% light: an amber sky over a flat amber panel that
   carries the date, the activity list and the venue in dark maroon. A wholly
   dark site drops the single largest surface of their identity, so one section
   reproduces it literally. Measured: maroon on amber 7.1:1, ink on amber 9.6:1. */
.section--amber { background: var(--amber); color: var(--maroon); }
.section--amber h2, .section--amber h3 { color: var(--maroon); }
.section--amber p, .section--amber .lede { color: color-mix(in oklab, var(--maroon) 90%, transparent); }
.section--amber .eyebrow { color: #8E2F14; }
.section--amber .eyebrow::before { background: linear-gradient(90deg, #A8331B, transparent); }
.section--amber .eyebrow--center::after { background: linear-gradient(270deg, #A8331B, transparent); }
.section--amber .btn--ghost { --btn-fg: var(--maroon); border-color: color-mix(in oklab, var(--maroon) 45%, transparent); }
.section--amber .btn--ghost:hover { background: color-mix(in oklab, var(--maroon) 10%, transparent); }
/* Dark photo cards on the light panel mirror the flyer's own contrast. */
.section--amber .photo-card { box-shadow: 0 18px 44px -22px rgb(84 36 40 / .6); }

/* Card captions sit on a dark photo gradient, so they stay light no matter what
   surface the section itself uses. */
.section--amber .photo-card__body h3, .section--paper .photo-card__body h3,
.section--amber .act__body h3,        .section--paper .act__body h3 { color: var(--cream); }
.section--amber .photo-card__body p,  .section--paper .photo-card__body p,
.section--amber .act__body p,         .section--paper .act__body p { color: var(--cream-dim); }
.section--amber .photo-card__tag, .section--paper .photo-card__tag { color: #FFD277; }


/* Amber needed the same completeness paper got; without it cards, list items,
   tabs, stats and FAQ rows kept dark-theme type and vanished on the panel. */
.section--amber li { color: #3A2A2E; }
.section--amber .card,
.section--amber .builder,
.section--amber .faq details { background: #FFF6E6; border-color: rgb(84 36 40 / .20); color: var(--char); }
.section--amber .card h3, .section--amber .card h4 { color: var(--maroon); }
.section--amber .card p, .section--amber .tier ul, .section--amber .faq p { color: #4A3A3E; }
.section--amber .card__num { color: color-mix(in oklab, var(--rust) 38%, transparent); }
.section--amber .tier li::before { color: var(--rust); }
.section--amber .stats { background: rgb(84 36 40 / .18); border-color: rgb(84 36 40 / .20); }
.section--amber .stat { background: #FFF6E6; }
.section--amber .stat b { color: var(--rust); }
.section--amber .stat small { color: #6B575C; }
.section--amber .faq summary { color: var(--maroon); }
.section--amber .faq summary::after { color: var(--rust); }
.section--amber .seg-tabs button { border-color: rgb(84 36 40 / .38); color: #5A464B; }
.section--amber .seg-tabs button[aria-selected="true"] { background: var(--maroon); border-color: var(--maroon); color: #FFE8C5; }
.section--amber .timeline time { color: var(--rust); }
.section--amber .chip { background: rgb(84 36 40 / .08); border-color: rgb(84 36 40 / .25); color: #4A3A3E; }
.section--amber .builder__out { background: rgb(84 36 40 / .06); border-color: rgb(84 36 40 / .28); color: #4A3A3E; }
.section--amber .btn--ghost { --btn-fg: var(--maroon); border-color: rgb(84 36 40 / .45); }
.section--amber .card .btn--ghost { --btn-fg: var(--maroon); }
.section--paper li { color: #3A2A2E; }

.section--paper a:not(.btn), .section--amber a:not(.btn) { color: #9E3F14; font-weight: 600; }

/* ---------- Split feature ---------------------------------------------- */
.split { display: grid; gap: clamp(1.6rem, 5vw, 4rem); align-items: center; }
@media (min-width: 900px) { .split { grid-template-columns: 1fr 1fr; } .split--rev > :first-child { order: 2; } }
.split__media { border-radius: var(--radius); overflow: hidden; aspect-ratio: 5 / 4; box-shadow: var(--shadow); }
.split__media img { width: 100%; height: 100%; object-fit: cover; }

/* ---------- Schedule ---------------------------------------------------- */
.seg-tabs { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 2rem; }
.seg-tabs button {
  padding: .7rem 1.3rem; border-radius: 999px; cursor: pointer;
  background: transparent; border: 1px solid var(--hairline); color: var(--cream-dim);
  font-family: var(--display); font-weight: 700; font-size: .92rem;
  transition: all .22s ease;
}
.seg-tabs button[aria-selected="true"] { background: var(--sun); color: var(--ink); border-color: var(--sun); }

.timeline { list-style: none; padding: 0; position: relative; }
/* ---------- Day builder ------------------------------------------------- */
.builder { background: var(--ink-2); border: 1px solid var(--hairline); border-radius: var(--radius); padding: clamp(1.4rem, 4vw, 2.6rem); }
.chip-grid { display: flex; flex-wrap: wrap; gap: .55rem; margin-block: 1.4rem; }
.chip {
  display: inline-flex; align-items: center; gap: .45rem; cursor: pointer;
  padding: .58rem 1rem; border-radius: 999px; font-size: .92rem;
  background: color-mix(in oklab, var(--cream) 6%, transparent);
  border: 1px solid var(--hairline); color: var(--cream-dim);
  transition: all .2s ease; user-select: none;
}
.chip input { position: absolute; opacity: 0; width: 0; height: 0; }
.chip:has(input:checked) { background: var(--ember); border-color: var(--ember); color: #fff; }
.chip:has(input:focus-visible) { box-shadow: var(--ring); }
.chip__x { opacity: 0; width: 0; transition: all .2s ease; }
.chip:has(input:checked) .chip__x { opacity: 1; width: .8em; }

.builder__out {
  margin-top: 1.2rem; padding: 1.2rem 1.4rem; border-radius: var(--radius-sm);
  background: color-mix(in oklab, var(--ink) 60%, transparent); border: 1px dashed var(--hairline);
  font-size: .96rem; color: var(--cream-dim);
}
.builder__out b { color: var(--sun); }

/* ---------- Stat band --------------------------------------------------- */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1px;
  background: var(--hairline); border: 1px solid var(--hairline); border-radius: var(--radius); overflow: hidden; }
.stat { background: var(--ink-2); padding: 1.6rem 1.2rem; text-align: center; }
.stat b { display: block; font-family: var(--display); font-weight: 900; font-size: clamp(1.7rem, 4vw, 2.6rem);
  line-height: 1; color: var(--sun); font-variant-numeric: tabular-nums; }
.stat small { display: block; margin-top: .5rem; font-size: .7rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--muted); }

/* ---------- Lineup ------------------------------------------------------ */
/* Five acts, not four (Petrina and JBthePreacher were split onto their own cards 2026-08-11).
   auto-fit at 240px wrapped to 4 + 1, which stranded the fifth card beside three empty tracks —
   the one layout on the site that reads as broken rather than designed. Explicit column counts
   keep every row full at each breakpoint. */
.lineup { display: grid; gap: 1rem; grid-template-columns: repeat(5, 1fr); }
@media (max-width: 1080px) { .lineup { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px)  { .lineup { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 420px)  { .lineup { grid-template-columns: 1fr; } }
.act { position: relative; border-radius: var(--radius); overflow: hidden; aspect-ratio: 3 / 4; background: var(--ink-3); }
.act img { width: 100%; height: 100%; object-fit: cover; filter: saturate(.9); transition: transform .6s cubic-bezier(.2,.8,.2,1), filter .4s; }
.act:hover img { transform: scale(1.06); filter: saturate(1.1); }
.act__body { position: absolute; z-index: 2; inset-block-end: 0; inset-inline: 0; padding: 1.6rem 1.2rem 1.1rem;
  background: linear-gradient(transparent, rgb(8 7 22 / .92)); }
.act__body h3 { font-size: 1.15rem; }
.act__body p { font-size: .8rem; letter-spacing: .1em; text-transform: uppercase; color: var(--amber); margin-top: .25rem; }

/* ---------- Tier cards -------------------------------------------------- */
.tier { display: flex; flex-direction: column; gap: 1rem; }
.tier--feature { border-color: color-mix(in oklab, var(--sun) 50%, transparent);
  background: linear-gradient(170deg, color-mix(in oklab, var(--ember) 18%, var(--ink-2)), var(--ink-2)); }
.tier ul { list-style: none; padding: 0; display: grid; gap: .55rem; font-size: .94rem; color: var(--cream-dim); }
.tier li { display: grid; grid-template-columns: 1.3em 1fr; gap: .5rem; align-items: start; }
.tier li::before { content: "✓"; color: var(--sun); font-weight: 700; }
.tier .btn { margin-top: auto; }
.badge { display: inline-block; padding: .3rem .7rem; border-radius: 999px; font-size: .66rem;
  font-family: var(--display); font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  background: var(--sun); color: var(--ink); }

/* ---------- Forms ------------------------------------------------------- */
.form { display: grid; gap: 1.1rem; }
.field { display: grid; gap: .4rem; }
.field label { font-size: .85rem; font-weight: 600; letter-spacing: .02em; color: var(--cream); }
.field input, .field select, .field textarea {
  width: 100%; padding: .85rem 1rem; border-radius: var(--radius-sm);
  background: color-mix(in oklab, var(--ink) 62%, transparent);
  border: 1px solid var(--hairline); color: var(--cream);
  transition: border-color .2s ease, background .2s ease;
}
.field input::placeholder, .field textarea::placeholder { color: color-mix(in oklab, var(--cream) 38%, transparent); }
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--amber); background: color-mix(in oklab, var(--ink) 40%, transparent); }
.field textarea { min-height: 130px; resize: vertical; }
.field--row { display: grid; gap: 1.1rem; }
@media (min-width: 640px) { .field--row { grid-template-columns: 1fr 1fr; } }
.form__note { font-size: .82rem; color: var(--muted); }
.form__ok {
  padding: 1rem 1.2rem; border-radius: var(--radius-sm); font-size: .95rem;
  background: color-mix(in oklab, var(--sun) 16%, transparent);
  border: 1px solid color-mix(in oklab, var(--sun) 45%, transparent); color: var(--cream);
}

/* ---------- FAQ --------------------------------------------------------- */
.faq { display: grid; gap: .7rem; }
.faq details {
  border: 1px solid var(--hairline); border-radius: var(--radius-sm);
  background: var(--ink-2); padding: 1rem 1.3rem; transition: border-color .2s ease;
}
.faq details[open] { border-color: color-mix(in oklab, var(--amber) 45%, transparent); }
.faq summary { cursor: pointer; font-family: var(--display); font-weight: 700; font-size: 1.02rem; list-style: none;
  display: flex; justify-content: space-between; gap: 1rem; align-items: center;
  /* the row itself was only ~27px of hit area inside a much taller-looking card */
  min-height: 44px; margin: -1rem -1.3rem; padding: 1rem 1.3rem; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--sun); font-size: 1.4rem; line-height: 1; transition: transform .25s ease; }
.faq details[open] summary::after { transform: rotate(45deg); }
.faq p { margin-top: 1.2rem; color: var(--cream-dim); font-size: .96rem; }

/* ---------- CTA band ---------------------------------------------------- */
.cta-band { position: relative; overflow: hidden; text-align: center;
  background: linear-gradient(180deg, #F6C078 0%, #F4B765 42%, #F0A24B 72%, #E8752A 100%); }
.cta-band h2 { font-size: var(--step-4); text-transform: uppercase; color: #4A1E28; }
.cta-band .lede { margin-inline: auto; color: #3D2A2E; }
.cta-band .btn-row { justify-content: center; margin-top: 1.8rem; }

/* ---------- Footer ------------------------------------------------------ */
.site-footer { background: #0A0920; border-top: 1px solid var(--hairline); padding-block: 3.5rem 2rem; }
/* Four known columns — pinned per breakpoint, not auto-fit (the same rule that bit the
   gallery and the lineup). 2×2 on tablet beats auto-fit's lopsided 3+1 wrap. */
.footer__grid { display: grid; gap: 2rem; grid-template-columns: repeat(4, 1fr); }
@media (max-width: 960px) { .footer__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .footer__grid { grid-template-columns: 1fr; } }
.footer__grid h4 { font-size: .74rem; letter-spacing: .16em; text-transform: uppercase; color: var(--amber); margin-bottom: .9rem; }
.footer__grid ul { list-style: none; padding: 0; display: grid; gap: .5rem; font-size: .93rem; }
.footer__grid a { color: var(--cream-dim); text-decoration: none; transition: color .2s ease; }
.footer__grid a:hover { color: var(--sun); }
.footer__bottom { margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid var(--hairline);
  display: flex; flex-wrap: wrap; gap: .8rem 1.5rem; justify-content: space-between;
  font-size: .82rem; color: var(--muted); }
.footer__bottom a { color: var(--cream-dim); }
.footer__built { display: inline-flex; align-items: center; gap: .4rem; }
.footer__built a {
  color: var(--sun); text-decoration: none; font-weight: 600;
  border-bottom: 1px solid color-mix(in oklab, var(--sun) 40%, transparent);
  transition: color .2s ease, border-color .2s ease;
}
.footer__built a:hover { color: var(--cream); border-color: var(--cream); }

/* ---------- Page hero (inner pages) ------------------------------------ */
.page-hero { position: relative; padding-block: clamp(8rem, 18vh, 11rem) clamp(2.5rem, 6vw, 4rem); isolation: isolate; }
.page-hero::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(90% 130% at 20% -10%, #DA2A21 0%, #542428 40%, var(--ink) 74%);
}
.page-hero h1 { font-size: var(--step-4); text-transform: uppercase; }

/* ---------- Reveal on scroll (JS adds .in) ----------------------------- */
.js .reveal { opacity: 0; transform: translateY(22px); transition: opacity .7s ease, transform .7s cubic-bezier(.2,.8,.2,1); }
.reveal.in { opacity: 1; transform: none; }
/* `.js .reveal` above is (0,2,0); a bare `.reveal` override loses on SPECIFICITY even though it
   comes later, so reveals kept animating under reduced motion. The .js twin restores the win. */
@media (prefers-reduced-motion: reduce) { .reveal, .js .reveal { opacity: 1; transform: none; transition: none; } }

/* ---------- Mobile nav -------------------------------------------------- */
@media (max-width: 980px) {
  /* The toggle must outrank the drawer or it slides over its own close button.
     display must be FLEX, not block — the base rule centres the icon with
     align-items/justify-content, which do nothing on a block box. It was sitting 3px
     off-centre in its own 46x46 button. */
  /* The drawer painted OVER the wordmark while the toggle sat above it, so the logo showed
     up sliced in half down its middle. The drawer's 6rem top padding was always meant to
     leave the header row visible — the brand just was never lifted into it. */
  .brand { position: relative; z-index: 2; }

  .nav__toggle {
    display: inline-flex; position: relative; z-index: 2;
    -webkit-tap-highlight-color: transparent;   /* iOS grey flash on tap */
    touch-action: manipulation;                 /* kill the legacy 300ms tap delay */
  }
  /* Drops DOWN from under the header, full width — owner's call 2026-08-11. It used to slide
     in from the right as a 320px side panel, which on a phone left a ~60px strip of backdrop and
     read like a desktop pattern shrunk down. A top sheet matches where the button actually is. */
  .nav__links {
    position: fixed; inset: 0 0 auto 0; width: 100%; z-index: 1;
    background: var(--ink-2); border-block-end: 1px solid var(--hairline);
    border-end-start-radius: var(--radius); border-end-end-radius: var(--radius);
    flex-direction: column; align-items: stretch; gap: .2rem;
    max-height: 100dvh;
    /* The home indicator on notched iPhones sits over the last ~34px, and landscape
       notches eat the right edge — env() keeps the final item tappable on both. */
    padding: calc(5.6rem + env(safe-area-inset-top)) 1.2rem 1.6rem;
    padding-inline-start: max(1.2rem, env(safe-area-inset-left));
    padding-inline-end: max(1.2rem, env(safe-area-inset-right));
    transform: translateY(-101%);
    /* visibility rides a 0s transition DELAYED past the slide, so the closed drawer is
       unfocusable (Tab used to land on 10 offscreen links) without snapping the animation. */
    visibility: hidden;
    transition: transform .32s cubic-bezier(.2,.8,.2,1), visibility 0s linear .32s;
    box-shadow: var(--shadow);
    overflow-y: auto; overscroll-behavior: contain;
  }
  .nav__links[data-open="true"] { transform: none; visibility: visible; transition-delay: 0s; }
  .nav__links a { padding: .85rem 1rem; font-size: 1.05rem; }
  .nav__links .btn { margin-top: .8rem; justify-content: center; }

  /* The drawer is full-height but the seven links only reach ~60% of it, leaving a large
     dead void under the RSVP button. Anchor the practical details to the bottom so the
     panel reads as designed rather than truncated. */
  .nav__meta { margin-top: 1rem; padding-top: 1.4rem; display: grid; gap: .3rem;
    border-top: 1px solid var(--hairline); font-size: .85rem; color: var(--muted); }
  .nav__meta strong { color: var(--cream); font-weight: 700; font-size: .92rem; }
  .nav__meta a { color: var(--sun); text-decoration: none; padding: .35rem 0; min-height: 32px;
    display: inline-flex; align-items: center; }

  /* Seven links + a button + the meta block came to ~780px, which overflows a 667px iPhone SE.
     The drawer scrolls, but a menu that needs scrolling to reach its own phone number is a
     worse menu. Tighten on short viewports instead. Measured, not guessed. */
  @media (max-height: 760px) {
    .nav__links { padding-top: 4.9rem; }
    .nav__links a:not(.btn) { padding-block: .58rem; font-size: 1rem; }
    .nav__links .btn { margin-top: .5rem; padding-block: .72rem; }
    .nav__meta { padding-top: .9rem; gap: .15rem; font-size: .8rem; }
    .nav__meta a { padding: .2rem 0; min-height: 28px; }
  }
  /* Below ~700px tall there is genuinely no room for the detail lines. Drop them rather than
     squeeze everything — on a screen that short the links already fill the panel, so the dead
     space this block exists to solve is not there anyway. Date + the two contacts survive. */
  @media (max-height: 700px) {
    .nav__meta > span { display: none; }
    .nav__meta { padding-top: .7rem; }
  }
  /* Under ~620px tall (a phone held sideways) even the trimmed block cannot earn its space —
     the seven links themselves have to scroll. Drop it entirely so there is less to scroll past.
     The drawer keeps overscroll-behavior:contain, so scrolling it never leaks to the page. */
  @media (max-height: 620px) { .nav__meta { display: none; } }

  /* Dim the page behind the open drawer; tapping it closes (handled in JS). */
  .nav__backdrop {
    position: fixed; inset: 0; z-index: 0; background: rgb(8 7 22 / .6);
    opacity: 0; pointer-events: none; transition: opacity .3s ease;
  }
  .nav__backdrop[data-open="true"] { opacity: 1; pointer-events: auto; }

  /* The drawer items arrive staggered behind the panel rather than all at once. Index is set
     inline by build.py so this needs no JS. */
  .nav__links[data-open="true"] li {
    /* delay is an inline animationDelay set in Nav.tsx — a CSS custom property here hydrated
       inconsistently between server and client and tripped React hydration error #418 */
    animation: navIn .42s cubic-bezier(.2,.9,.3,1) backwards;
  }
  @keyframes navIn { from { opacity: 0; transform: translateY(-10px); } }
}
@media (min-width: 981px) { .nav__backdrop { display: none; } }

/* Tabs were the only pill component on the site with no hover affordance. */
.seg-tabs button:not([aria-selected="true"]):hover { color: var(--cream); border-color: var(--amber); }
.section--amber .seg-tabs button:not([aria-selected="true"]):hover,
.section--paper .seg-tabs button:not([aria-selected="true"]):hover {
  color: var(--maroon); border-color: var(--maroon);
  background: color-mix(in oklab, var(--maroon) 8%, transparent); }
@media (max-width: 700px) { .seg-tabs button { padding: .85rem 1.3rem; } }

/* A static notice card was inheriting the hover lift meant for interactive cards. */
.card:not(a):hover { transform: none; }

/* Per-item accent so the three day-part lists aren't typographically identical. */
[role="tabpanel"] li { border-inline-start: 3px solid var(--ember); padding-inline-start: .75rem; }
[role="tabpanel"] li:nth-of-type(3n+2) { border-inline-start-color: var(--sun); }
[role="tabpanel"] li:nth-of-type(3n+3) { border-inline-start-color: var(--brick); }

/* The "set times to come" line had no container, unlike the equivalent notice on
   /schedule/ — it read as an afterthought rather than a decision. */
.tbd-note {
  display: block; width: max-content; max-width: 100%; margin: 1.7rem auto 0;
  padding: .55rem 1.15rem; border-radius: 999px; border: 1px dashed var(--hairline);
  color: var(--cream-dim); font-size: .88rem; text-align: center; }

/* BUG: the ghost button on the closing band measured 1.76:1 — pale cream on the
   amber gradient — on the exact sentence meant to close the sale. */
.cta-band .btn--ghost { --btn-fg: #4A1E28; border-color: color-mix(in oklab, #4A1E28 45%, transparent); }
.cta-band .btn--ghost:hover { background: color-mix(in oklab, #4A1E28 10%, transparent); }

/* "Still being finalised" was an apology buried mid-paragraph. As a tagged status
   callout it becomes "here is exactly what's pending" — and each page names a
   different pending item, so it doubles as a per-page differentiator. */
.status-note { display: flex; gap: .8rem; align-items: flex-start; margin-top: 1.2rem;
  padding: 1rem 1.2rem; border: 1px dashed var(--hairline); border-radius: var(--radius-sm);
  background: color-mix(in oklab, var(--ink) 60%, transparent); }
.status-note__tag { flex: none; font-family: var(--display); font-weight: 800; font-size: .64rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--sun);
  border: 1px solid color-mix(in oklab, var(--sun) 45%, transparent);
  border-radius: 999px; padding: .32rem .62rem; white-space: nowrap; }
.status-note p { margin: 0; }
.section--paper .status-note, .section--amber .status-note {
  background: rgb(84 36 40 / .05); border-color: rgb(84 36 40 / .28); }
.section--paper .status-note__tag, .section--amber .status-note__tag {
  color: var(--rust); border-color: color-mix(in oklab, var(--rust) 50%, transparent); }

.stat--lead b { font-size: clamp(2rem, 5vw, 3rem); }
.section--amber .stat small, .section--paper .stat small { font-weight: 600; }

/* BUG: .section--amber .card (0,2,0) outranks .tier--feature (0,1,0) regardless
   of source order, so the featured card silently lost its highlight on amber.
   Same family as the .nav__links a vs .btn bug fixed earlier. */
.section--amber .card.tier--feature {
  background: linear-gradient(170deg, color-mix(in oklab, var(--ember) 22%, #FFF6E6), #FFF6E6);
  border-color: color-mix(in oklab, var(--rust) 55%, transparent); }
.section--paper .card.tier--feature {
  background: linear-gradient(170deg, color-mix(in oklab, var(--ember) 18%, #FFFFFF), #FFFFFF);
  border-color: color-mix(in oklab, var(--rust) 50%, transparent); }

/* The media column was centred against a text column 218px taller, leaving dead
   space above and below the photo. Scoped so #location keeps centring. */
#what .split { align-items: start; }

/* The chips already carry their day-part in data-time for the JS; surfacing it
   visually costs nothing and makes a generic filter feel like this event.
   box-shadow not border, so nothing shifts. */
.chip:has(input[data-time="Morning"])   { box-shadow: inset 3px 0 0 var(--ember); }
.chip:has(input[data-time="Afternoon"]) { box-shadow: inset 3px 0 0 var(--sun); }
.chip:has(input[data-time="Evening"])   { box-shadow: inset 3px 0 0 var(--brick); }
.chip:has(input:checked) { box-shadow: none; }

/* Reuse the lineup's top-bar device so the three day-part cards differentiate. */
#glance .photo-card { position: relative; }
#glance .photo-card::before { content: ""; position: absolute; inset-inline: 0;
  inset-block-start: 0; height: 4px; z-index: 3; }
#glance .photo-card:nth-of-type(1)::before { background: var(--ember); }
#glance .photo-card:nth-of-type(2)::before { background: var(--sun); }
#glance .photo-card:nth-of-type(3)::before { background: var(--brick); }

/* Gold focus ring measured ~1.8:1 on light surfaces, under the 3:1 non-text floor. */
.section--paper :focus-visible, .section--amber :focus-visible {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--maroon) 60%, transparent); }
.section--amber .faq summary::after { color: #8E2F14; }

/* The ticker hard-clipped at both edges and ran too fast to read on a phone. */
.ticker { -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); }
@media (max-width: 600px) { .ticker__track { animation-duration: 56s; } }

/* Google's default red/blue POI pins fought the warm palette. */
iframe[title^="Map"] { filter: grayscale(.55) contrast(1.1) saturate(.85); }

/* ---------- Atmosphere / texture ---------------------------------------- */
/* Grain already ships globally on body::after, so the hero-scoped version is
   deliberately omitted here to avoid doubling it. */

/* The flyer has a torn brush seam; this bites an ember tooth-strip into the
   first cream section. .section is already position:relative. */
#what::before {
  content: ""; position: absolute; inset-inline: 0; inset-block-start: -1px; height: 11px;
  background: var(--ember);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='11'%3E%3Cpolygon points='0,0 0,3 7,11 14,2 21,11 28,3 28,0'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='11'%3E%3Cpolygon points='0,0 0,3 7,11 14,2 21,11 28,3 28,0'/%3E%3C/svg%3E");
  -webkit-mask-repeat: repeat-x;  mask-repeat: repeat-x;
  -webkit-mask-size: 28px 11px;   mask-size: 28px 11px;
}

/* Near-invisible at rest, blooms warm from the edges on hover.
   Layered as custom properties: the light-catch edge, the ember glow and any
   elevation used to be three competing box-shadow declarations that silently
   overrode each other (at rest the glow was dead; on hover the edge vanished).
   Now each layer has its own slot and they compose. */
.card {
  --card-edge: inset 0 1px 0 color-mix(in oklab, var(--cream) 10%, transparent);
  --card-glow: inset 0 0 46px -30px var(--ember);
  --card-drop: 0 0 rgb(0 0 0 / 0);
  box-shadow: var(--card-edge), var(--card-glow), var(--card-drop);
}
.card:hover { --card-glow: inset 0 0 64px -22px var(--ember); }
/* Only anchor cards (clickable) earn elevation; notice cards glow but stay put. */
a.card:hover { --card-drop: 0 22px 44px -26px rgb(0 0 0 / .5); }

/* Corner vignette — pulls the eye to the sun and the headline. */
.hero__scrim::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 85% at 50% 45%, transparent 55%,
    color-mix(in oklab, var(--ink) 90%, transparent) 100%);
}

/* Warm haze at the far/mid ridge boundary. Sitting above ~55% washes out the
   eyebrow line — the reviewer measured +17 luminance there. Do not raise it. */
.hero__scrim::after {
  content: ""; position: absolute; inset-inline: 0; inset-block-start: 59%; height: 9%;
  pointer-events: none; mix-blend-mode: screen;
  background: linear-gradient(180deg, transparent,
    color-mix(in oklab, var(--sun) 40%, transparent) 50%, transparent);
}

/* ---------- Craft pass --------------------------------------------------- */
/* Below 700px the sun sits behind the tagline: cream on gold, close in
   lightness. A soft local scrim separates them without dimming the sun. */
@media (max-width: 700px) {
  .hero__tagline { position: relative; isolation: isolate; }
  .hero__tagline::before {
    content: ""; position: absolute; inset: -.35em -.7em; z-index: -1;
    background: radial-gradient(closest-side, rgb(14 13 38 / .44), transparent 75%);
    filter: blur(7px); border-radius: 999px;
  }
}

/* Oversized 01/02 numerals were the one element that could be lifted onto any
   SaaS pricing page. A ring badge echoes the RWC crest instead. */
#why .card__num {
  width: 3.4rem; height: 3.4rem; display: grid; place-items: center;
  font-size: 1.3rem; border-radius: 50%; position: relative; margin-bottom: 1rem;
  box-shadow: inset 0 0 0 2.5px color-mix(in oklab, var(--rust) 60%, transparent);
}
#why .card__num::after {
  content: ""; position: absolute; inset: -7px; border-radius: 50%;
  border: 1px solid color-mix(in oklab, var(--rust) 22%, transparent);
}

/* Grain over the flat vector fills — the single biggest depth win site-wide. */
body::after {
  content: ""; position: fixed; inset: 0; z-index: 9999; pointer-events: none;
  opacity: .035; mix-blend-mode: overlay; background-size: 140px 140px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
@media print { body::after { display: none; } }

/* The footer just stopped; give it a closing beat that echoes the hero ridge. */
.site-footer { position: relative; }
.site-footer::before {
  content: ""; position: absolute; inset-inline: 0; inset-block-start: 0; height: 8px;
  background: linear-gradient(135deg, var(--ember) 25%, transparent 25%) 0 0/8px 8px,
              linear-gradient(225deg, var(--ember) 25%, transparent 25%) 0 0/8px 8px;
  opacity: .32;
}

/* The four lineup images are deliberately faceless stand-ins; without this they
   blur into one stock pack. */
.lineup .act { position: relative; }
.lineup .act.ph::before {
  content: ""; position: absolute; inset-inline: 0; inset-block-start: 0; height: 4px; z-index: 2;
  background: var(--ember);
}
.lineup .act.ph::before { background: var(--sun); }

/* Light-catch edge — the top highlight every polished dark UI has.
   (.card carries its edge via --card-edge above so the glow layer survives.) */
.builder, .faq details, .stat {
  box-shadow: inset 0 1px 0 color-mix(in oklab, var(--cream) 10%, transparent); }
.section--paper .card, .section--amber .card {
  --card-edge: inset 0 1px 0 rgb(255 255 255 / .55);
  --card-glow: 0 0 rgb(0 0 0 / 0); }   /* no ember bloom inside white cards */
.section--paper .builder, .section--paper .faq details, .section--amber .faq details {
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .55); }

/* Photos set into the layout rather than pasted on top. */
.photo-card__media, .act, .split__media { box-shadow: inset 0 0 0 1px rgb(255 255 255 / .08); }

/* ---------- Editorial polish -------------------------------------------- */
/* Display sizes need tighter tracking than the h1-h4 base; only the homepage
   hero had it. */
.page-hero h1, .cta-band h2 { letter-spacing: -.035em; }

/* Widow control was scoped to .lede; ordinary body copy could still orphan a word. */
.section p { text-wrap: pretty; }

/* Numerals appear in more places than the countdown and stat band. */
.eyebrow, .seg-tabs button, .photo-card__tag { font-variant-numeric: tabular-nums; }

/* One drop cap, on the site's actual editorial lede. */
#what .lede::first-letter {
  font-family: var(--display); font-weight: 900; float: left;
  font-size: 3.4em; line-height: .82; padding: .04em .1em 0 0; color: var(--rust);
}

/* Pull-quote mark, echoing the flyer's own accent-rule device. */
#why h2 { position: relative; padding-inline-start: 1.4em; }
#why h2::before { content: "\201C"; position: absolute; inset-inline-start: 0; inset-block-start: -.15em;
  font-family: var(--display); font-size: 1.5em; color: var(--rust); opacity: .55; }

/* Reuse .card__num's oversized-numeral device on the three day-parts rather
   than inventing a second motif. */
#panel-morning h2::before, #panel-afternoon h2::before, #panel-evening h2::before {
  display: block; font-family: var(--display); font-weight: 900; font-size: 3.4rem;
  line-height: 1; color: color-mix(in oklab, var(--rust) 40%, transparent); margin-bottom: .1rem;
}
#panel-morning h2::before   { content: "01"; }
#panel-afternoon h2::before { content: "02"; }
#panel-evening h2::before   { content: "03"; }

/* The day-part lists were the one flat text dump on a card-driven site. */
[role="tabpanel"] li { border-block-end: 1px solid rgb(84 36 40 / .16); padding-block: .5rem; }
[role="tabpanel"] li:last-child { border-block-end: none; }

/* auto-fit leaves the lone "More to be announced" tile stranded beside three
   empty tracks — the only spot that reads as broken rather than designed. */
.lineup .act--announce { grid-column: 1 / -1; aspect-ratio: auto; min-height: 9rem; }

/* "500-1,000+" was breaking mid-figure in the 2-col mobile grid. */
@media (max-width: 480px) {
  .stat b { white-space: nowrap; font-size: clamp(1.3rem, 5.5vw, 1.7rem); }
}
/* At <=700px the sun sits behind the headline: cream on gold, close in lightness. */
@media (max-width: 700px) {
  .hero__title, .hero__tagline { text-shadow: 0 2px 4px rgb(0 0 0 / .40), 0 10px 34px rgb(0 0 0 / .60); }
}

/* ---------- Motion polish ----------------------------------------------- */
/* Schedule panels used to hard-cut between segments — the flattest moment on
   the site, on the page whose whole job is walking someone through a day. */
[data-segment] { animation: panel-in .45s cubic-bezier(.2,.8,.2,1) both; }
@keyframes panel-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* The closing ask should arrive, not just be there. */
.js .cta-band.reveal { transform: translateY(36px) scale(.985); }
.cta-band.reveal.in { transform: none;
  transition: opacity .8s ease, transform .8s cubic-bezier(.2,.8,.2,1); }

/* Only the digit that actually changed moves. */
.count-unit b.tick { animation: digit-tick .32s cubic-bezier(.2,.8,.2,1); }
@keyframes digit-tick { 0% { transform: translateY(-6px); opacity: .45; } 100% { transform: none; opacity: 1; } }

/* Barely perceptible, which is the point. */
.hero__birds svg { animation: bird-drift 90s linear infinite alternate; }
@keyframes bird-drift { from { transform: translateX(0); } to { transform: translateX(-2.5%); } }

/* Ridge parallax, Chromium-only for now. Unsupported browsers render static —
   inert, not broken — so there is no fallback path to maintain. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .hero__ridge--far { animation: ridge-far 1 linear both; animation-timeline: scroll(root); animation-range: 0 100vh; }
    .hero__ridge--mid { animation: ridge-mid 1 linear both; animation-timeline: scroll(root); animation-range: 0 100vh; }
    @keyframes ridge-far { to { transform: translateY(-4%); } }
    @keyframes ridge-mid { to { transform: translateY(-8%); } }
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-segment], .count-unit b.tick, .hero__birds svg, .hero__scroll i { animation: none; }
  .cta-band.reveal, .js .cta-band.reveal, .cta-band.reveal.in { transform: none; transition: none; }
}

/* ---------- Print ------------------------------------------------------- */
@media print {
  .site-header, .ticker, .hero__scroll, .cta-band, .btn { display: none !important; }
  body { background: #fff; color: #000; }
}

/* ---------- Gallery ------------------------------------------------------ */
/* Square cells: the client's photos arrive in both orientations, and a square
   crop is the only ratio that treats a portrait and a landscape equally well. */
.gallery { display: grid; gap: .6rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr)); }
/* auto-fit fell to ONE column inside the mobile gutters, turning 12 squares into 4,800px of
   scrolling — measured on a 390px viewport. A proof wall wants to read as a wall, so pin the
   count instead of letting it collapse. */
@media (max-width: 720px) { .gallery { grid-template-columns: repeat(3, 1fr); gap: .45rem; } }
@media (max-width: 430px) { .gallery { grid-template-columns: repeat(2, 1fr); } }
.gallery figure { margin: 0; aspect-ratio: 1; overflow: hidden; position: relative;
  border-radius: calc(var(--radius) * .55);
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .08); background: var(--ink-3); }
.gallery img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .6s cubic-bezier(.2,.8,.2,1); }
.gallery figure:hover img, .gallery figure:focus-within img { transform: scale(1.06); }
@media (prefers-reduced-motion: reduce) { .gallery img { transition: none; } }

/* A wide media box for photos that must be seen whole. The venue exterior is the case that
   forced it: any cover-crop tighter than its native ratio cuts the building. */
.split__media--wide { aspect-ratio: 11 / 6; }

/* ---------- Touch targets ------------------------------------------------ */
/* Footer links rendered as 18px-tall text runs — fine with a mouse, fiddly with a thumb and under
   the 24px WCAG 2.5.8 floor. Padding the anchor rather than the <li> keeps the whole row tappable.
   Measured on a real 390px viewport, not guessed. */
/* WCAG 2.5.8 floor of 24px applies to every pointer, not just touch — the first pass only scoped
   this to (hover: none) and desktop was never measured. 24px everywhere, 44px where thumbs are. */
.footer__grid li > a { display: flex; align-items: center; min-height: 24px; }
.footer__built a { display: inline-flex; align-items: center; min-height: 24px; padding-inline: .2rem; }
.brand { min-height: 24px; }

@media (hover: none), (max-width: 720px) {
  .footer__grid ul { gap: .1rem; }
  .footer__grid li > a { padding-block: .62rem; min-height: 44px; }
  .nav__links a { min-height: 46px; display: flex; align-items: center; }
  .footer__built a { min-height: 34px; }
}

/* ---------- Partnership pricing ------------------------------------------ */
/* Added 2026-08-11 when the sponsor + community-partner packets arrived and the pages stopped
   being "call us, levels are still being set". Real tiers, real numbers, straight from the PDF. */
.tier__price { font-family: var(--display); font-weight: 900; font-size: clamp(1.9rem, 4vw, 2.5rem);
  line-height: 1; color: var(--sun); letter-spacing: -.02em; }
.tier__price small { display: block; font-family: var(--body); font-weight: 600; font-size: .74rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin-top: .45rem; }
.section--paper .tier__price, .section--amber .tier__price { color: var(--rust); }
.section--paper .tier__price small, .section--amber .tier__price small { color: #6B565A; }
.tier__addon { font-size: .86rem; padding: .6rem .75rem; border-radius: 10px;
  background: color-mix(in oklab, var(--sun) 12%, transparent);
  border: 1px dashed color-mix(in oklab, var(--sun) 45%, transparent); }

/* Pill list — "sponsor an experience" and the in-kind wish list are both flat enumerations that
   read better as scannable chips than as another bulleted column. */
.pills { display: flex; flex-wrap: wrap; gap: .5rem; padding: 0; margin: 0; list-style: none; }
.pills li { padding: .45rem .85rem; border-radius: 999px; font-size: .9rem; font-weight: 600;
  border: 1px solid var(--hairline); background: color-mix(in oklab, var(--cream) 6%, transparent); }
.section--paper .pills li, .section--amber .pills li {
  border-color: rgb(84 36 40 / .22); background: rgb(255 255 255 / .5); color: #4A3A3E; }

/* Value stack: a two-column figure list, not a real table — it is a price sheet, not data. */
.valuestack { display: grid; gap: 0; margin: 0; }
.valuestack div { display: flex; justify-content: space-between; gap: 1rem; align-items: baseline;
  padding: .7rem 0; border-block-end: 1px solid var(--hairline); font-size: .96rem; }
.valuestack div:last-child { border-block-end: none; border-block-start: 2px solid var(--sun);
  margin-block-start: .3rem; padding-block-start: .9rem; font-weight: 800; font-size: 1.08rem; }
.valuestack b { white-space: nowrap; color: var(--sun); font-weight: 800; }
.section--paper .valuestack div, .section--amber .valuestack div { border-color: rgb(84 36 40 / .16); }
.section--paper .valuestack b, .section--amber .valuestack b { color: var(--rust); }
.footnote { font-size: .82rem; color: var(--muted); margin-top: 1rem; max-width: 70ch; }
.section--paper .footnote, .section--amber .footnote { color: #6B565A; }

/* Client note 2026-08-11: the "Get started" buttons on the Co-op and Legacy cards read as greyed
   out / disabled. They were .btn--ghost, which is a transparent outline — on a dark card that is
   almost invisible and looks like a dead control. Give ghost buttons INSIDE a tier card a real
   surface so all three read as clickable, while the featured tier keeps the solid fill and stays
   the emphasis. */
.tier .btn--ghost {
  background: color-mix(in oklab, var(--cream) 11%, transparent);
  border-color: color-mix(in oklab, var(--cream) 34%, transparent);
  --btn-fg: var(--cream);
}
.tier .btn--ghost:hover {
  background: color-mix(in oklab, var(--sun) 22%, transparent);
  border-color: color-mix(in oklab, var(--sun) 62%, transparent);
}
.section--paper .tier .btn--ghost, .section--amber .tier .btn--ghost {
  background: rgb(84 36 40 / .07); border-color: rgb(84 36 40 / .38); --btn-fg: var(--maroon);
}
.section--paper .tier .btn--ghost:hover, .section--amber .tier .btn--ghost:hover {
  background: rgb(84 36 40 / .14);
}

/* ==========================================================================
   Design-system refresh (ticket 001) — shared-layer polish only.
   Everything below composes with the rules above; new animations carry their
   own reduced-motion overrides at the END of this block, and the global
   reduced-motion block stays last in the file.
   ========================================================================= */

/* ---------- Global finish ------------------------------------------------ */
:root { accent-color: var(--ember); }
::selection { background: var(--ember); color: #16101F; }
a { text-underline-offset: .15em; }
/* Branded scrollbar on the dark shell; falls back silently. */
@supports (scrollbar-color: auto) {
  html { scrollbar-color: color-mix(in oklab, var(--ember) 40%, var(--ink-2)) var(--ink); }
}

/* ---------- Buttons ------------------------------------------------------ */
/* Top-lit sheen on filled buttons — a white overlay, not a new colour.
   :where() keeps specificity at (0,1,0) so variants still win. */
.btn:where(:not(.btn--ghost)) {
  background-image: linear-gradient(180deg, rgb(255 255 255 / .2), rgb(255 255 255 / 0) 48%);
}
.btn:where(:not(.btn--ghost)):hover {
  box-shadow: 0 14px 34px -12px color-mix(in oklab, var(--btn-bg) 75%, transparent);
}
/* BUG FIX: the global :focus-visible ring (line ~95) lost to .btn's own
   box-shadow (same specificity, later in file) — keyboard focus was INVISIBLE
   on every filled button. These are last, so the ring wins again. */
.btn:focus-visible {
  box-shadow: var(--ring), 0 10px 30px -12px color-mix(in oklab, var(--btn-bg) 65%, transparent);
}
.section--paper .btn:focus-visible, .section--amber .btn:focus-visible {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--maroon) 60%, transparent);
}

/* ---------- Layout hardening --------------------------------------------- */
/* BUG FIX: grid items default to min-width:auto, so the square client photo in
   /sponsor/'s .split__media forced its track to the image's min-content width
   and dragged the layout viewport to 348px on a 320px phone (measured, 28px of
   horizontal scroll). Clamp every split child so photos can never do that. */
.split > * { min-width: 0; }
/* BUG FIX: .btn's white-space:nowrap made any long label an unbreakable box —
   "Community partner packet (PDF)" measured ~330px and dragged the /sponsor/
   layout viewport to 348px on a 320px phone. Let labels wrap on narrow
   screens; the centered two-line pill still reads as designed. */
@media (max-width: 480px) {
  .btn { white-space: normal; text-align: center; max-width: 100%; }
}

/* ---------- Cards / countdown ------------------------------------------- */
/* Interactive (anchor) cards on light surfaces cast a warm maroon shadow, not soot. */
.section--paper a.card:hover, .section--amber a.card:hover {
  --card-drop: 0 18px 40px -24px rgb(84 36 40 / .38);
}
.count-unit { box-shadow: inset 0 1px 0 rgb(255 255 255 / .12); }

/* ---------- Chips -------------------------------------------------------- */
/* Chips had a transition but no hover state to transition to. Checked chips
   keep their ember fill (.chip:has(input:checked) outranks this). */
.chip:hover {
  border-color: color-mix(in oklab, var(--cream) 32%, transparent);
  background: color-mix(in oklab, var(--cream) 10%, transparent);
}
.section--paper .chip:hover, .section--amber .chip:hover {
  border-color: rgb(84 36 40 / .45); background: rgb(84 36 40 / .10);
}

/* ---------- Forms -------------------------------------------------------- */
/* A soft halo instead of the hard gold ring, which fought the amber border. */
.field :is(input, select, textarea):focus-visible {
  border-color: var(--amber);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--amber) 30%, transparent);
}
.section--paper .field :is(input, select, textarea):focus-visible,
.section--amber .field :is(input, select, textarea):focus-visible {
  border-color: var(--maroon);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--maroon) 45%, transparent);
}

/* ---------- Header / drawer polish (visual only — logic untouched) ------- */
.nav__toggle { transition: border-color .2s ease, background .2s ease; }
.nav__toggle:hover {
  border-color: color-mix(in oklab, var(--cream) 32%, transparent);
  background: color-mix(in oklab, var(--cream) 7%, transparent);
}
@media (max-width: 980px) {
  /* Press feedback in the drawer — taps read as registered, not ignored. */
  .nav__links a:not(.btn):active {
    background: color-mix(in oklab, var(--cream) 9%, transparent);
    border-radius: 10px;
  }
}

/* ---------- Touch targets (≥44px where thumbs are) ----------------------- */
@media (hover: none), (max-width: 720px) {
  .btn { min-height: 44px; }              /* .btn--sm measured ~34px */
  .chip { min-height: 44px; }             /* measured ~35px */
  .seg-tabs button { min-height: 44px; }  /* measured ~42px */
  .brand { min-height: 44px; }
}

/* ---------- Scroll progress (decorative, guarded) ------------------------ */
/* scaleX(0) at rest: browsers without scroll timelines, and reduced-motion
   users, simply never see it. transform on this element is safe — it has no
   descendants, so no containing-block trap. */
.scroll-progress {
  position: fixed; inset-block-start: 0; inset-inline: 0; height: 3px; z-index: 110;
  pointer-events: none; transform: scaleX(0); transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--ember), var(--sun) 60%, var(--amber));
}
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .scroll-progress { animation: sd-progress 1 linear both; animation-timeline: scroll(root); }
    @keyframes sd-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  }
}

/* ---------- Scroll-driven reveals (progressive enhancement) -------------- */
/* Where view() timelines exist, the reveal becomes pure CSS and scroll-linked:
   the JS IntersectionObserver keeps toggling .in, but the animation owns
   opacity/transform (animations beat normal declarations), so the class flip
   is inert here and remains the mechanism everywhere else. Content can never
   be stranded invisible: no-JS gets the noscript !important override, no
   support gets the JS path, reduced motion gets the instant .in path. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .js .reveal {
      transition: none; opacity: 1; transform: none;
      animation: sd-reveal 1 both cubic-bezier(.2, .8, .2, 1);
      animation-timeline: view();
      animation-range: entry 8% entry 55%;
    }
    @keyframes sd-reveal { from { opacity: 0; transform: translateY(22px); } }
    /* The CTA band's special JS entrance (higher specificity) would otherwise
       leak translateY(36px) scale(.985) into sd-reveal's implicit `to` state
       and leave the band shifted until .in lands. Neutralise it here. */
    .js .cta-band.reveal { transform: none; transition: none; }
    /* Stagger flavour for this branch: siblings shift their range, so a row of
       cards cascades left-to-right instead of arriving as one slab. */
    .stagger > .reveal:nth-child(2) { animation-range: entry 14% entry 61%; }
    .stagger > .reveal:nth-child(3) { animation-range: entry 20% entry 67%; }
    .stagger > .reveal:nth-child(4) { animation-range: entry 26% entry 73%; }
    .stagger > .reveal:nth-child(5) { animation-range: entry 32% entry 79%; }
    .stagger > .reveal:nth-child(n+6) { animation-range: entry 38% entry 85%; }
  }
}

/* ==========================================================================
   OPT-IN UTILITIES for page agents (documented in the ticket report).
   ========================================================================== */

/* .stagger — put on a grid/row whose direct children carry .reveal; they enter
   with a small cascade. JS-transition flavour (the view() flavour is above). */
.js .stagger > .reveal:nth-child(2) { transition-delay: 70ms; }
.js .stagger > .reveal:nth-child(3) { transition-delay: 140ms; }
.js .stagger > .reveal:nth-child(4) { transition-delay: 210ms; }
.js .stagger > .reveal:nth-child(5) { transition-delay: 280ms; }
.js .stagger > .reveal:nth-child(n+6) { transition-delay: 350ms; }

/* .card--lift — feature-card variant: warm gradient wash, tinted border, real
   elevation. Combine with .card. Works on dark, paper and amber surfaces. */
.card--lift {
  border-color: color-mix(in oklab, var(--amber) 38%, transparent);
  background: linear-gradient(165deg, color-mix(in oklab, var(--ember) 14%, var(--card)), var(--card) 60%);
  --card-drop: 0 18px 40px -24px rgb(0 0 0 / .55);
}
.section--paper .card--lift {
  background: linear-gradient(165deg, color-mix(in oklab, var(--ember) 10%, #FFFFFF), #FFFFFF 60%);
  border-color: color-mix(in oklab, var(--rust) 40%, transparent);
  --card-drop: 0 16px 36px -22px rgb(84 36 40 / .30);
}
.section--amber .card--lift {
  background: linear-gradient(165deg, color-mix(in oklab, var(--ember) 12%, #FFF6E6), #FFF6E6 60%);
  border-color: color-mix(in oklab, var(--rust) 45%, transparent);
  --card-drop: 0 16px 36px -22px rgb(84 36 40 / .34);
}

/* .section--seam — the flyer's torn brush seam (generalised from #what) as an
   opt-in top edge for any .section. Recolour via --seam. Do not combine with
   a section that already uses its own ::before. */
.section--seam::before {
  content: ""; position: absolute; inset-inline: 0; inset-block-start: -1px; height: 11px;
  background: var(--seam, var(--ember));
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='11'%3E%3Cpolygon points='0,0 0,3 7,11 14,2 21,11 28,3 28,0'/%3E%3C/svg%3E");
          mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='11'%3E%3Cpolygon points='0,0 0,3 7,11 14,2 21,11 28,3 28,0'/%3E%3C/svg%3E");
  -webkit-mask-repeat: repeat-x;  mask-repeat: repeat-x;
  -webkit-mask-size: 28px 11px;   mask-size: 28px 11px;
}

/* ---------- Print safety for reveals ------------------------------------- */
/* Print has no scroll: unseen .reveal content would print invisible. */
@media print {
  .reveal { opacity: 1 !important; transform: none !important; animation: none !important; }
  .scroll-progress { display: none; }
}

/* ---------- Reduced-motion overrides for THIS block ---------------------- */
/* (The pre-existing global block below stays last, per the standing rule.) */
@media (prefers-reduced-motion: reduce) {
  .btn:hover, .btn:active { transform: none; }
  .brand:hover .brand__mark { transform: none; }
  .card:hover, a.card:hover, a.card--lift:hover { transform: none; }
  .photo-card:hover .photo-card__media img, .act:hover img,
  .gallery figure:hover img, .gallery figure:focus-within img { transform: none; }
  .scroll-progress { animation: none; }
  .js .stagger > .reveal { transition-delay: 0s; }
}

/* ======================= PAGE: index ======================= */
/* ---------- Page: index ---------- */
/* Every selector here is scoped to the home page: its section ids
   (#what/#glance/#concert/#why/#proof/#involved — verified unique across all
   seven _src fragments) or an .index-* class that exists only in index.html.
   No new animations are introduced; reveals and staggers come from the shared
   layer, which carries its own reduced-motion overrides. */

/* ---------- Section heads: one rhythm for every centered header ----------
   Replaces five per-section inline style="text-align:center;margin-bottom:…"
   blobs that had drifted to 2.2/2.4/2.6rem. One measure, one gap. */
.index-sechead { text-align: center; margin-bottom: clamp(2.1rem, 6vw, 2.6rem); }
.index-sechead h2 { font-size: var(--step-3); max-width: 30ch; margin-inline: auto; }
.index-sechead .lede { margin-inline: auto; max-width: 60ch; }

/* The two split sections share the same heading scale as the centered heads
   (was an inline font-size on each h2). */
#what h2, #location h2 { font-size: var(--step-3); }

/* ---------- Ticker --------------------------------------------------------
   Let a reader stop the marquee to actually read it. Reduced-motion users
   never see it move at all (shared layer already stops the animation). */
.index-ticker:hover .ticker__track { animation-play-state: paused; }

/* ---------- Day at a glance: 3 known cards --------------------------------
   Shared .grid--3 is auto-fit and wrapped 2+1 — a stranded Evening card
   beside an empty track — between ~660 and ~987px. Pinned instead:
   – ≥981px: three across (same card width auto-fit produced at its own
     3-column threshold).
   – 721–980px: Morning + Afternoon side by side, Evening spanning the full
     row in a wide crop. The section literally says "one build toward the
     night", so the Evening card earning the big frame is hierarchy, not a
     patch.
   – ≤720px: one comfortable centered column. */
#glance .grid--3 { grid-template-columns: repeat(3, 1fr); }
@media (min-width: 721px) and (max-width: 980px) {
  #glance .grid--3 { grid-template-columns: repeat(2, 1fr); }
  #glance .grid--3 .photo-card:nth-child(3) { grid-column: 1 / -1; }
  #glance .grid--3 .photo-card:nth-child(3) .photo-card__media { aspect-ratio: 21 / 9; }
}
@media (max-width: 720px) {
  #glance .grid--3 { grid-template-columns: 1fr; max-width: 33rem; margin-inline: auto; }
}

/* ---------- Lineup: 5 known acts -------------------------------------------
   The shared layer pins 5/3/2/1 (keep it). Two gaps remained:
   – 721–1080px: 5 acts in 3 columns = a stranded 3+2 row beside an empty
     track. A 6-track grid keeps both rows full: 3 across, then 2 wider.
   – 421–720px: 2 columns = 2+2+1 with the 5th act beside a hole. Give it the
     whole row as a wide cinematic closing frame instead. */
@media (min-width: 721px) and (max-width: 1080px) {
  #concert .lineup { grid-template-columns: repeat(6, 1fr); }
  #concert .lineup .act { grid-column: span 2; }
  #concert .lineup .act:nth-child(n+4) { grid-column: span 3; }
}
@media (min-width: 421px) and (max-width: 720px) {
  #concert .lineup .act:nth-child(5) { grid-column: 1 / -1; aspect-ratio: 3 / 2; }
}

/* ---------- Why this matters: 2 cards + 4 stats ---------------------------- */
#why .grid--2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 820px) { #why .grid--2 { grid-template-columns: 1fr; } }

/* Stat band: 4 known figures, all already stated on this page. Shared .stats
   is auto-fit (4→2→1, and a lone-column stack at 320px); pin 4→2 and keep two
   columns down to 320px — the cells just give up a little side padding so
   “300–500+” (nowrap below 480px) still fits its ~140px cell. */
#why .stats { margin-top: clamp(1.2rem, 3vw, 1.6rem); grid-template-columns: repeat(4, 1fr); }
@media (max-width: 720px) { #why .stats { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 400px) { #why .stat { padding: 1.2rem .5rem; } }

/* ---------- Gallery: 12 known squares ---------------------------------------
   auto-fit stranded 5+5+2 around ~1120px. 12 divides cleanly at 6/4/3/2, so
   every row is always full. The ≤720/≤430 rules restate the shared pins
   because this ID-scoped rule outranks them at every width. */
#proof .gallery { grid-template-columns: repeat(6, 1fr); }
@media (max-width: 1080px) { #proof .gallery { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 720px)  { #proof .gallery { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 430px)  { #proof .gallery { grid-template-columns: repeat(2, 1fr); } }

/* ---------- Get involved: 4 known tiers -------------------------------------
   auto-fit stranded a 3+1 row between ~700 and ~940px; 4→2→1 keeps rows full
   and the featured Sponsor card always sits in a complete row. */
#involved .grid--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1080px) { #involved .grid--4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { #involved .grid--4 { grid-template-columns: 1fr; } }

/* ---------- Closing CTA ------------------------------------------------------
   On small phones the two pills wrapped into an ambiguous side-by-side
   cluster. Stacked and stretched, RSVP reads unmistakably primary with
   Share directly beneath it. */
@media (max-width: 480px) {
  .index-cta .btn-row {
    flex-direction: column; align-items: stretch;
    max-width: 22rem; margin-inline: auto;
  }
}

/* ======================= PAGE: artists ======================= */
/* ---------- Page: artists ---------- */

/* Every .lineup override below is scoped .lineup.artists-lineup (0,2,0 → 0,3,0
   with the descendant), so it beats the shared .lineup rules regardless of
   where this file lands in the merged cascade, and cannot leak to the
   homepage's copy of the same grid. */

/* Section head — restores the h1 → h2 → h3 heading ladder (the act names are
   h3s and used to follow the hero's h1 directly) and gives the grid an
   editorial lead-in instead of starting cold under the hero. */
.artists-head { margin-bottom: clamp(1.8rem, 4vw, 2.6rem); }
.artists-head h2 { font-size: var(--step-3); margin-top: .7rem; }

/* Acts — a short sun keyline above each name, echoing the eyebrow's rule
   device, so the name plates read as set type rather than bare captions. */
.lineup.artists-lineup .act__body::before {
  content: ""; display: block; width: 1.7rem; height: 2px; margin-bottom: .5rem;
  border-radius: 2px; background: linear-gradient(90deg, var(--sun), transparent);
}
/* Names grow with the viewport but stay inside a 2-col card at 421px:
   "JBthePreacher" (the longest unbreakable name) measures ~130px at the clamp
   floor against ~147px of plate width there. */
.lineup.artists-lineup .act__body h3 {
  font-size: clamp(1.05rem, .9rem + .45vw, 1.35rem);
  letter-spacing: -.01em;
}

/* "More to be announced" — the fragment's inline-styled dashed box, promoted
   to a designed tile: amber-tinted dashed border and a faint ember floor glow
   from existing tokens. Same content, no new facts. */
.lineup.artists-lineup .act--announce {
  display: grid; place-content: center; text-align: center; padding: 1.5rem;
  border: 1px dashed color-mix(in oklab, var(--amber) 38%, transparent);
  background:
    radial-gradient(130% 95% at 50% 118%, color-mix(in oklab, var(--ember) 16%, transparent), transparent 60%),
    var(--ink-2);
  transition: border-color .3s ease;
}
.lineup.artists-lineup .act--announce:hover {
  border-color: color-mix(in oklab, var(--amber) 62%, transparent);
}
.artists-announce { display: grid; justify-items: center; gap: .4rem; }
.artists-announce__plus {
  font-family: var(--display); font-weight: 900; font-size: 2.6rem; line-height: 1;
  color: var(--ember);
}
.artists-announce h3 { font-size: 1.15rem; }
.artists-announce .btn { margin-top: .6rem; }

/* Grid arithmetic: 5 acts + the announce tile = 6 items. The shared .lineup
   pins 3 cols ≤1080px and 2 cols ≤720px — with the announce card IN the flow
   at those widths the grid is a perfect 2×3 and 3×2, so no row ever strands a
   card (the exact failure the full-width banner was papering over: at 2 cols,
   DJ Zay sat alone beside an empty track). Desktop (5 across) and single
   column (≤420px) keep the shared full-width banner treatment. */
@media (min-width: 421px) and (max-width: 1080px) {
  .lineup.artists-lineup .act--announce {
    grid-column: auto; aspect-ratio: 3 / 4; min-height: 0;
  }
}

/* No page-added animation beyond the shared .reveal/.stagger utilities, which
   carry their own reduced-motion overrides in site.css. The announce hover
   above transitions colour only — no motion, nothing to override. */

/* ======================= PAGE: schedule ======================= */
/* ---------- Page: schedule ---------- */
/* Scoping: #schedule-day is the id on the tabs section (set in app/schedule/page.tsx);
   .schedule-note / .schedule-arc__* are page-new classes. Shared classes are only
   overridden under one of those page-unique scopes, so nothing leaks to other pages. */

/* ===== Hero: the day arc =========================================================== */
/* A proportional strip of the three confirmed blocks (3h / 4.5h / 3.5h of an 11-hour day).
   Purely decorative (aria-hidden) — the same facts are in the eyebrow and the tabs.
   Colors follow the mapping the homepage chips established:
   Morning = ember, Afternoon = sun, Evening = brick. */
.page-hero .schedule-arc { margin-top: 2rem; max-width: 620px; }

.schedule-arc__ticks {
  position: relative; height: 1rem; margin-bottom: .45rem;
  font-family: var(--display); font-weight: 700; font-size: .66rem;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--cream-dim); font-variant-numeric: tabular-nums;
}
.schedule-arc__ticks span { position: absolute; top: 0; line-height: 1; }
/* Boundaries of an 11h day: 9AM = 0, 12PM = 3/11, 4:30 = 7.5/11, 8PM = 1. */
.schedule-arc__ticks span:nth-child(1) { left: 0; }
.schedule-arc__ticks span:nth-child(2) { left: 27.27%; translate: -50% 0; }
.schedule-arc__ticks span:nth-child(3) { left: 68.18%; translate: -50% 0; }
.schedule-arc__ticks span:nth-child(4) { right: 0; }

/* Three known segments — columns pinned, never auto-fit (project rule #6 / brief #4). */
.schedule-arc__track { display: grid; grid-template-columns: 6fr 9fr 7fr; gap: 3px; }
.schedule-arc__seg {
  display: block; height: 14px; border-radius: 999px;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .28), inset 0 -1px 0 rgb(0 0 0 / .18);
}
.schedule-arc__seg--morning   { background: linear-gradient(180deg, color-mix(in oklab, var(--ember) 80%, white), var(--ember)); }
.schedule-arc__seg--afternoon { background: linear-gradient(180deg, color-mix(in oklab, var(--sun) 82%, white), var(--sun)); }
.schedule-arc__seg--evening   { background: linear-gradient(180deg, color-mix(in oklab, var(--brick) 84%, white), var(--brick)); }

.schedule-arc__labels {
  display: grid; grid-template-columns: 6fr 9fr 7fr; gap: 3px; margin-top: .5rem;
}
.schedule-arc__labels span {
  text-align: center; font-family: var(--display); font-weight: 700;
  font-size: .8rem; letter-spacing: .02em; color: var(--cream);
}

/* The arc deserves a beat more air than the stack default before the CTAs. */
.page-hero .schedule-arc + .btn-row { margin-top: 1.9rem; }

/* Entrance: the day "fills in" left to right. Guarded by no-preference AND force-disabled
   in the reduced-motion block at the end of this file. */
@media (prefers-reduced-motion: no-preference) {
  .schedule-arc__seg {
    transform-origin: 0 50%;
    animation: schedule-arc-in .7s cubic-bezier(.2, .8, .2, 1) backwards;
  }
  .schedule-arc__seg--afternoon { animation-delay: .14s; }
  .schedule-arc__seg--evening   { animation-delay: .28s; }
  .schedule-arc__ticks span, .schedule-arc__labels span {
    animation: schedule-arc-fade .5s ease .45s backwards;
  }
}
@keyframes schedule-arc-in   { from { transform: scaleX(0); } }
@keyframes schedule-arc-fade { from { opacity: 0; } }

/* ===== Tabs section (#schedule-day, amber) ========================================= */
/* The section's top padding used to be an inline style on the JSX wrapper; it lives here now. */
#schedule-day { padding-block-start: clamp(2rem, 5vw, 3.5rem); }
#schedule-day .eyebrow { margin-bottom: 1.2rem; }

/* Segmented control. The three buttons form one recessed track — pinned 3 columns, never
   auto-fit. Labels are two lines ('name\ntime' from page.tsx): pre-line honours the \n and
   ::first-line styles the name line. If ::first-line is ever unsupported the whole label
   simply renders at the base style — smaller, but intact and centred. */
#schedule-day .seg-tabs {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: .25rem;
  max-width: 640px; margin-block: 0 1.7rem;
  padding: .3rem; border-radius: calc(var(--radius) - 2px);
  background: rgb(84 36 40 / .13);
  border: 1px solid rgb(84 36 40 / .18);
  box-shadow: inset 0 1px 4px rgb(84 36 40 / .16);
}
#schedule-day .seg-tabs button {
  display: block; width: 100%; min-height: 56px;
  padding: .55rem .3rem .6rem; border: 0;
  border-radius: calc(var(--radius) - 6px);
  background: transparent; cursor: pointer;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  white-space: pre-line; text-align: center; line-height: 1.45;
  font-family: var(--body); font-weight: 600; font-size: .74rem; letter-spacing: .01em;
  color: #5A464B;             /* 4.8:1 on amber — same ink site.css already uses here */
  font-variant-numeric: tabular-nums;
  transition: background .22s ease, color .22s ease, box-shadow .22s ease;
}
/* The name line. Mixed case on purpose: uppercase Montserrat 800 overflows a 3-up
   cell at 320px ("AFTERNOON" measures ~90px against ~80px of cell). */
#schedule-day .seg-tabs button::first-line {
  font-family: var(--display); font-weight: 800; font-size: .95rem;
  letter-spacing: -.01em; color: var(--maroon);
}
/* 320px: cells are ~80px; "Afternoon" at .95rem measures right at the edge. Ease off. */
@media (max-width: 350px) {
  #schedule-day .seg-tabs button::first-line { font-size: .88rem; }
}
#schedule-day .seg-tabs button:not([aria-selected="true"]):hover {
  background: rgb(255 246 230 / .55); color: #3F2F33;
}
#schedule-day .seg-tabs button[aria-selected="true"] {
  background: var(--maroon); color: var(--cream-dim);   /* 6.9:1 */
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .12), 0 3px 12px -3px rgb(84 36 40 / .6);
}
#schedule-day .seg-tabs button[aria-selected="true"]::first-line { color: var(--cream); }
/* These outrank .section--amber :focus-visible, so the ring must be restated here or
   keyboard focus goes invisible (same trap the design-system pass fixed on .btn). */
#schedule-day .seg-tabs button:focus-visible {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--maroon) 60%, transparent);
}
#schedule-day .seg-tabs button[aria-selected="true"]:focus-visible {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--maroon) 60%, transparent),
              inset 0 1px 0 rgb(255 255 255 / .12);
}

/* Panels become cards on the amber panel — the flyer's own light-on-amber surface. */
#schedule-day [role="tabpanel"] {
  background: #FFF6E6;
  border: 1px solid rgb(84 36 40 / .2);
  border-radius: var(--radius);
  padding: clamp(1.1rem, 3.5vw, 2.4rem);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .55), 0 22px 48px -30px rgb(84 36 40 / .55);
}
/* The tabpanel is focusable (tabindex=0); restate the ring for the same reason as above. */
#schedule-day [role="tabpanel"]:focus-visible {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--maroon) 60%, transparent),
              inset 0 1px 0 rgb(255 255 255 / .55);
}
/* Inside a padded card the split's site-wide gap reads oversized; photo shadow goes warm. */
#schedule-day .split { gap: clamp(1.2rem, 3vw, 2.75rem); }
#schedule-day .split__media {
  box-shadow: 0 16px 36px -20px rgb(84 36 40 / .5),
              inset 0 0 0 1px rgb(84 36 40 / .1);
}
/* Single-column phones: 5/4 pushed the list below the fold; 4/3 is a gentle crop of the
   square masters and buys back ~60px without touching the files. */
@media (max-width: 899px) { #schedule-day .split__media { aspect-ratio: 4 / 3; } }

/* List rows cascade in when a panel is shown (display:none -> shown restarts animations,
   so it replays on every tab switch alongside site.css's panel-in). */
@media (prefers-reduced-motion: no-preference) {
  #schedule-day [role="tabpanel"] li {
    animation: schedule-li-in .45s cubic-bezier(.2, .8, .2, 1) backwards;
  }
  #schedule-day [role="tabpanel"] li:nth-child(1) { animation-delay: .05s; }
  #schedule-day [role="tabpanel"] li:nth-child(2) { animation-delay: .1s; }
  #schedule-day [role="tabpanel"] li:nth-child(3) { animation-delay: .15s; }
  #schedule-day [role="tabpanel"] li:nth-child(4) { animation-delay: .2s; }
  #schedule-day [role="tabpanel"] li:nth-child(5) { animation-delay: .25s; }
  #schedule-day [role="tabpanel"] li:nth-child(n+6) { animation-delay: .3s; }
}
@keyframes schedule-li-in { from { opacity: 0; transform: translateX(-8px); } }

/* ===== "Set times" notice (paper section) ========================================== */
/* Amber seam: the section above is the amber panel, so its colour tears into the paper. */
.section.schedule-note { --seam: var(--amber); padding-block: clamp(2.5rem, 6vw, 4.5rem); }
.schedule-note .wrap { width: min(820px, 100% - var(--gutter) * 2); }
.schedule-note .card { text-align: center; padding: clamp(1.6rem, 5vw, 2.8rem); }
.schedule-note .card h2 { font-size: var(--step-2); margin-top: .9rem; }
.schedule-note .card p { margin-top: .7rem; max-width: 58ch; margin-inline: auto; }
.schedule-note .btn-row { justify-content: center; margin-top: 1.5rem; }

/* ===== Reduced motion for everything this file animates (kept LAST in this file) === */
@media (prefers-reduced-motion: reduce) {
  .schedule-arc__seg, .schedule-arc__ticks span, .schedule-arc__labels span,
  #schedule-day [role="tabpanel"] li { animation: none; }
}

/* ======================= PAGE: sponsor ======================= */
/* ---------- Page: sponsor ---------- */

/* ===== Hero entrance ============================================================
   Pure CSS, deliberately NOT the .reveal mechanism: the <h1> here is this page's
   LCP element and `.js .reveal` holds content at opacity:0 until hydration runs.
   A CSS animation starts at first paint instead, no JS in the path.
   Children: eyebrow, h1, lede, btn-row (4 known children — delays pinned). */
.sponsor-hero .stack > * {
  animation: sponsor-hero-rise .55s cubic-bezier(.2, .8, .2, 1) backwards;
}
.sponsor-hero .stack > :nth-child(2) { animation-delay: .07s; }
.sponsor-hero .stack > :nth-child(3) { animation-delay: .14s; }
.sponsor-hero .stack > :nth-child(4) { animation-delay: .21s; }
@keyframes sponsor-hero-rise {
  from { opacity: 0; transform: translateY(14px); }
}

/* ===== Seam colours (shared .section--seam utility) =============================
   Each seam reads as the PREVIOUS section tearing into this one: paper tears into
   the dark levels band, amber tears into the ink community-partners band. The
   stats band keeps the default ember accent, echoing the homepage's #what seam. */
#levels   { --seam: var(--paper); }
#partners { --seam: var(--amber); }

/* ===== Stat band: 4 known cells — columns pinned per breakpoint ================
   (auto-fit collapsed this to a 4-tall single column on a 320px phone.) */
.sponsor-stats .stats { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 999px) {
  .sponsor-stats .stats { grid-template-columns: repeat(2, 1fr); }
}
/* "300–500+" must fit a ~142px cell at 320px; trim cell padding, not the figure. */
@media (max-width: 400px) {
  .sponsor-stats .stat { padding: 1.15rem .65rem; }
}

/* ===== Tier grid: 3 known cards — columns pinned per breakpoint ================ */
#levels .sponsor-tiers { grid-template-columns: repeat(3, 1fr); gap: 1.3rem; }
@media (max-width: 999px) {
  #levels .sponsor-tiers {
    grid-template-columns: 1fr;
    max-width: 620px;
    margin-inline: auto;
  }
}

/* Ranking cues: a heat bar across the top of each card, warming with the tier.
   Co-op = quiet amber, Impact (the tier the content itself features via value
   framing + tier--feature) = full ember→sun gradient, Legacy = brick→maroon.
   .card is position:relative + overflow:hidden, so the bar sits flush. */
#levels .sponsor-tiers > .tier { padding-top: 1.85rem; }
#levels .sponsor-tiers > .tier::before {
  content: ""; position: absolute; inset-inline: 0; inset-block-start: 0; height: 4px;
}
#levels .sponsor-tiers > .tier:nth-child(1)::before {
  background: color-mix(in oklab, var(--amber) 65%, transparent);
}
#levels .sponsor-tiers > .tier:nth-child(2)::before {
  height: 5px;
  background: linear-gradient(90deg, var(--ember), var(--sun));
}
#levels .sponsor-tiers > .tier:nth-child(3)::before {
  background: linear-gradient(90deg, var(--brick), var(--maroon));
}

/* The featured tier stands a touch taller than its row on desktop — static
   margins, so it composes cleanly with the hover/reveal transforms. */
@media (min-width: 1000px) {
  #levels .sponsor-tiers > .tier--feature { margin-block: -12px; }
}
/* Featured card grows 12px past the grid's bottom edge; keep the footnote clear. */
#levels .footnote { margin-block-start: 1.8rem; }

/* Benefit-list scanability: a hairline seam between price and benefits, then one
   per row so eight-line lists (Legacy) read as rows, not a text slab. */
#levels .sponsor-tiers .tier ul {
  margin-block-start: .15rem;
  border-block-start: 1px solid var(--hairline);
  padding-block-start: 1rem;
}
#levels .sponsor-tiers .tier li {
  padding-block-end: .55rem;
  border-block-end: 1px solid color-mix(in oklab, var(--cream) 7%, transparent);
}
#levels .sponsor-tiers .tier li:last-child {
  border-block-end: none;
  padding-block-end: 0;
}

/* "Everything in X, plus:" is a divider label, not a benefit — drop its ✓ and
   set it as a small-caps rule so the list below scans as the actual additions. */
#levels .sponsor-tiers li.sponsor-tier__more { grid-template-columns: 1fr; }
#levels .sponsor-tiers li.sponsor-tier__more::before { content: none; }
#levels .sponsor-tiers .sponsor-tier__more strong {
  font-family: var(--display); font-weight: 800; font-size: .7rem;
  letter-spacing: .15em; text-transform: uppercase; color: var(--amber);
}

/* Full-width card CTAs: bigger thumb target, and the three tiers close on the
   same visual beat. (.tier .btn { margin-top: auto } already bottom-aligns.) */
#levels .sponsor-tiers .tier .btn { width: 100%; }

/* ===== Community partners: ask / receive lists =================================
   The literal "→ " prefixes moved out of the copy into a hanging-indent marker,
   so two-line items align under their first word instead of under the arrow. */
#partners .sponsor-asklabel {
  font-size: .78rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--amber); margin-top: .9rem;
}
#partners .sponsor-asklist {
  list-style: none; padding: 0; margin-top: .6rem; display: grid; gap: .55rem;
}
#partners .sponsor-asklist li {
  display: grid; grid-template-columns: 1.3em 1fr; gap: .5rem; align-items: start;
}
#partners .sponsor-asklist li::before {
  content: "\2192"; color: var(--sun); font-weight: 700;
}

/* ===== Closing CTA: tel/mailto buttons go full-width where thumbs are ========== */
@media (max-width: 480px) {
  #talk .btn { width: 100%; }
}

/* ===== Reduced motion (covers every animation added by THIS file) ============== */
@media (prefers-reduced-motion: reduce) {
  .sponsor-hero .stack > * { animation: none; }
}

/* ======================= PAGE: vendors ======================= */
/* ---------- Page: vendors ---------- */
/* No animations of its own — the stagger/reveal system (shared layer) carries the
   reduced-motion overrides. Everything below is static layout/finish. */

/* ---- Hero fact pills ----------------------------------------------------- */
/* .pills zeroes its own margin AFTER .stack's lobotomised-owl rule in the shared
   sheet, so the stack rhythm never reaches it — restate the gap explicitly. */
.pills.vendors-facts { margin-top: 1.1rem; }
.pills.vendors-facts li {
  background: rgb(14 13 38 / .5);
  border-color: color-mix(in oklab, var(--cream) 24%, transparent);
  font-variant-numeric: tabular-nums;
}

/* ---- Who sets up (paper) -------------------------------------------------- */
/* Tightened top padding: this section sits directly under the page hero
   (was an inline style; moved here). */
.vendors-types { padding-block-start: clamp(2.5rem, 6vw, 4rem); }
.vendors-types__head { margin-bottom: clamp(1.6rem, 4vw, 2.4rem); max-width: var(--measure); }
.vendors-types h2 { font-size: var(--step-3); }

/* 3 known photo cards — columns pinned per breakpoint (hard rule #4: never
   auto-fit with a known small count). Mid widths run 2-up with the third card
   spanning as a deliberate wide feature, not a stranded orphan. */
.vendors-types .grid--3 { grid-template-columns: 1fr; }
@media (min-width: 560px) {
  .vendors-types .grid--3 { grid-template-columns: repeat(2, 1fr); }
  .vendors-types .photo-card:nth-child(3) { grid-column: 1 / -1; }
  .vendors-types .photo-card:nth-child(3) .photo-card__media { aspect-ratio: 2 / 1; }
}
@media (min-width: 880px) {
  .vendors-types .grid--3 { grid-template-columns: repeat(3, 1fr); }
  .vendors-types .photo-card:nth-child(3) { grid-column: auto; }
  .vendors-types .photo-card:nth-child(3) .photo-card__media { aspect-ratio: 4 / 3; }
}

/* ---- Booths (dark) -------------------------------------------------------- */
/* (Inline text-align/margins/font-size from the old markup live here now.) */
.vendors-booths__head { text-align: center; margin-bottom: 2.4rem; }
.vendors-booths__head h2 { font-size: var(--step-3); }
.vendors-booths__head .lede { margin-inline: auto; }

/* 3 known tier cards — one centered readable column until all three fit. */
.vendors-booths .grid--3 { grid-template-columns: min(100%, 34rem); justify-content: center; }
@media (min-width: 960px) {
  .vendors-booths .grid--3 { grid-template-columns: repeat(3, 1fr); }
}

/* .tier is a column flex; without this the badge stretches into a full-width bar. */
.vendors-booths .badge { align-self: flex-start; }

/* Placement policy as a tagged note (same device volunteer uses), centered
   under the three cards rather than a full-width afterthought. */
.vendors-booths .status-note { margin-top: 1.9rem; max-width: 70ch; margin-inline: auto; }
@media (max-width: 380px) {
  .vendors-booths .status-note { flex-direction: column; gap: .55rem; }
}

/* ---- Worth knowing (amber upsell) ----------------------------------------- */
.vendors-upsell h2 { font-size: var(--step-3); }
/* The check-in photo reads better a touch wider than .split__media's 5:4
   (was an inline style; moved here). */
.vendors-upsell .split__media { aspect-ratio: 16 / 10; }
.vendors-upsell .btn-row { margin-top: 1.4rem; }

/* ---- Reserve CTA ----------------------------------------------------------- */
/* Amber eyebrow ink is invisible on the gold band (was an inline style). */
#reserve .eyebrow { color: var(--ink); }

/* ======================= PAGE: visit ======================= */
/* ---------- Page: visit ---------- */

/* == Hero essentials — Where / When / Cost as three big tappable cards ======
   This is the page people open on their phone on the way to the event, so the
   wayfinding block is pure CSS (no .reveal / JS observer): it can never be
   stranded invisible, and it animates in even before hydration. */
.page-hero .visit-essentials {
  margin-top: 1.9rem;
  display: grid;
  gap: .75rem;
  grid-template-columns: 1fr;   /* 3 known items: pinned per breakpoint, never auto-fit */
}
@media (min-width: 820px) {
  .page-hero .visit-essentials { grid-template-columns: repeat(3, 1fr); gap: 1rem; }
}

.visit-essential {
  display: grid;
  grid-template-columns: auto 1fr auto;   /* icon | text | chevron */
  align-items: center;
  gap: .95rem;
  padding: .95rem 1.1rem;
  min-height: 64px;                        /* whole card is the tap target */
  border-radius: var(--radius-sm);
  text-decoration: none;
  background: color-mix(in oklab, var(--ink) 58%, transparent);
  border: 1px solid var(--hairline);
  box-shadow: inset 0 1px 0 color-mix(in oklab, var(--cream) 10%, transparent);
  transition: transform .25s cubic-bezier(.2,.8,.2,1),
              border-color .25s ease, background .25s ease;
  animation: visit-essential-in .55s cubic-bezier(.2,.8,.2,1) backwards;
}
.visit-essential:nth-child(2) { animation-delay: 90ms; }
.visit-essential:nth-child(3) { animation-delay: 180ms; }
@keyframes visit-essential-in { from { opacity: 0; transform: translateY(14px); } }

.visit-essential:hover {
  transform: translateY(-3px);
  border-color: color-mix(in oklab, var(--amber) 45%, transparent);
  background: color-mix(in oklab, var(--ink) 70%, transparent);
}
.visit-essential:active { transform: translateY(-1px); }
/* The card's own box-shadow buries the global :focus-visible ring (same
   specificity, later in the cascade) — the exact bug site.css fixed for .btn.
   Restate both layers so keyboard focus stays visible. */
.visit-essential:focus-visible {
  box-shadow: var(--ring), inset 0 1px 0 color-mix(in oklab, var(--cream) 10%, transparent);
}

.visit-essential__icon  { width: 1.5rem; height: 1.5rem; flex: none; color: var(--sun); }
.visit-essential__text  { display: grid; gap: .16rem; min-width: 0; }  /* min-width:0 so the address can wrap at 320px */
.visit-essential__label {
  font-family: var(--display); font-weight: 800; font-size: .66rem;
  letter-spacing: .18em; text-transform: uppercase; color: var(--amber);
}
.visit-essential__value {
  font-family: var(--display); font-weight: 800; font-size: 1.04rem;
  line-height: 1.22; letter-spacing: -.01em; color: var(--cream); text-wrap: balance;
}
.visit-essential__meta { font-size: .9rem; color: var(--cream-dim); }
.visit-essential__go {
  margin-top: .28rem; font-family: var(--display); font-weight: 700;
  font-size: .82rem; color: var(--sun);
}
.visit-essential__arrow {
  width: 1.05rem; height: 1.05rem; flex: none; color: var(--cream-dim);
  transition: transform .25s cubic-bezier(.2,.8,.2,1), color .25s ease;
}
.visit-essential:hover .visit-essential__arrow { transform: translateX(3px); color: var(--sun); }
@media (max-width: 360px) {
  .visit-essential { padding: .85rem .95rem; gap: .8rem; }
}

/* == Location: framed map with an address bar ============================== */
/* The two paper sections (map, venue split) merged into one; the seam utility
   gives it the flyer's torn top edge. Keep the map compact enough that the
   address bar and the venue block are reachable in one small scroll. */
.visit-location { padding-block-start: clamp(2.4rem, 5vw, 3.8rem); }

.visit-map {
  border-radius: var(--radius);
  overflow: hidden;
  background: #FFFFFF;
  border: 1px solid rgb(84 36 40 / .18);
  box-shadow: 0 18px 44px -22px rgb(84 36 40 / .35), inset 0 1px 0 rgb(255 255 255 / .55);
  margin-block-end: clamp(2.6rem, 6vw, 4rem);
}
/* Height in CSS (not the attr) so phones get a shorter map; the shared
   iframe[title^="Map"] recolour keeps applying — no inline filter here. */
.visit-map__frame { display: block; border: 0; width: 100%; height: clamp(300px, 52svh, 440px); }

.visit-map__bar {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 0 1.2rem; padding: .35rem 1.15rem;
}
.visit-map__addr {
  display: inline-flex; align-items: center; min-height: 44px;
  font-weight: 600; font-size: .95rem; color: #4A3A3E;
}
/* colour + weight come from the shared .section--paper a:not(.btn) rule */
.visit-map__open {
  display: inline-flex; align-items: center; gap: .45rem;
  min-height: 44px; font-size: .95rem;
}
.visit-map__open svg { width: 1em; height: 1em; flex: none; transition: transform .25s cubic-bezier(.2,.8,.2,1); }
.visit-map__open:hover svg { transform: translateX(3px); }

/* == Venue split =========================================================== */
.visit-venue__title { font-size: var(--step-3); }
.visit-venue__actions { margin-top: .6rem; }

/* == FAQ ==================================================================== */
.visit-faq { --seam: var(--maroon); }   /* maroon teeth on amber, the flyer's own pairing */
.visit-faq .wrap--narrow { width: min(860px, 100% - var(--gutter) * 2); }
.visit-faq__head { text-align: center; margin-bottom: 2.2rem; }
.visit-faq__title { font-size: var(--step-3); }

/* == Reduced motion (page-scoped; the global block in site.css stays last) == */
@media (prefers-reduced-motion: reduce) {
  .visit-essential { animation: none; }
  .visit-essential:hover, .visit-essential:active { transform: none; }
  .visit-essential:hover .visit-essential__arrow { transform: none; }
  .visit-map__open:hover svg { transform: none; }
}

/* ======================= PAGE: volunteer ======================= */
/* ---------- Page: volunteer ---------- */

/* == Hero: staggered entrance (CSS-only, above the fold) ===================
   .reveal is scroll-in and the hero is already in view on load, so the hero
   gets its own keyframe cascade instead. `backwards` fill keeps children
   hidden through their delay. Guarded by no-preference AND overridden again
   in the reduced-motion block at the end of this file. */
@media (prefers-reduced-motion: no-preference) {
  .volunteer-hero .stack > * {
    animation: volunteer-rise .65s cubic-bezier(.2, .8, .2, 1) backwards;
  }
  .volunteer-hero .stack > :nth-child(2) { animation-delay: .08s; }
  .volunteer-hero .stack > :nth-child(3) { animation-delay: .16s; }
  .volunteer-hero .stack > :nth-child(4) { animation-delay: .24s; }
  @keyframes volunteer-rise {
    from { opacity: 0; transform: translateY(16px); }
  }
}

/* Warm sun bloom top-right, under the content (.page-hero is isolated; its
   shared ::before is untouched — this is the free ::after slot). */
.volunteer-hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: radial-gradient(56% 42% at 82% 16%,
    color-mix(in oklab, var(--sun) 24%, transparent), transparent 70%);
}

/* == Paper section (how to sign up) ======================================= */
/* Was an inline style; the hero above already provides the breathing room. */
.section.volunteer-how { padding-block-start: clamp(2.5rem, 6vw, 4rem); }
.volunteer-how h2 { font-size: var(--step-3); }
.volunteer-how .btn-row { margin-top: 1.6rem; }
/* Offset print-edge so the photo reads set into the paper, not pasted on.
   Box-shadow, not a pseudo — .split__media clips its children (overflow:hidden). */
.volunteer-how .split__media {
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / .08), var(--shadow),
              12px 12px 0 -2px color-mix(in oklab, var(--rust) 28%, transparent);
}

/* == Amber "three ways in" ================================================ */
.volunteer-ways { --seam: var(--maroon); }  /* maroon tooth-strip against amber, per the flyer */
.volunteer-ways__head { text-align: center; margin-bottom: 2.4rem; }
.volunteer-ways h2 { font-size: var(--step-3); }

/* Exactly 3 cards: columns pinned per breakpoint, never auto-fit (house rule).
   In the 2-col band the featured Volunteer card spans the full first row, so
   the page's one conversion keeps top billing instead of pairing off. */
.volunteer-ways .grid--3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 940px) {
  .volunteer-ways .grid--3 { grid-template-columns: repeat(2, 1fr); }
  .volunteer-ways .tier--feature { grid-column: 1 / -1; }
}
@media (max-width: 600px) {
  .volunteer-ways .grid--3 { grid-template-columns: 1fr; }
}

/* .tier is a stretch flex column; unpinned, the badge would run full width. */
.volunteer-ways .badge { align-self: flex-start; }
.volunteer-ways .tier--feature { padding: 1.9rem 1.6rem; }

/* == Sticky sign-up bar (phones only) =====================================
   position:sticky + bottom:0 as the LAST element in the fragment: it rides
   the viewport bottom for the whole scroll, then docks into its natural slot
   above the footer — so it can never cover footer links, and it needs no JS.
   z-index 90 stays under the fixed header (100), so the open drawer and its
   backdrop still paint over it. Not an ancestor of the drawer, so the
   backdrop-filter containing-block trap does not apply. */
.volunteer-bar { display: none; }
@media (max-width: 720px) {
  .volunteer-bar {
    position: sticky; inset-block-end: 0; z-index: 90;
    display: flex; align-items: center; gap: .9rem;
    padding: .7rem
             max(var(--gutter), env(safe-area-inset-right))
             calc(.7rem + env(safe-area-inset-bottom))
             max(var(--gutter), env(safe-area-inset-left));
    background: color-mix(in oklab, var(--ink) 86%, transparent);
    -webkit-backdrop-filter: saturate(1.3) blur(12px);
            backdrop-filter: saturate(1.3) blur(12px);
    border-block-start: 1px solid var(--hairline);
    box-shadow: 0 -14px 34px -18px rgb(0 0 0 / .55);
  }
  .volunteer-bar__note {
    margin: 0; flex: none; font-size: .78rem; line-height: 1.35; color: var(--cream-dim);
  }
  .volunteer-bar__note strong {
    display: block; font-family: var(--display); font-weight: 800;
    font-size: .9rem; letter-spacing: -.01em; color: var(--cream);
  }
  .volunteer-bar__cta { flex: 1 1 auto; min-height: 48px; }
}

/* Progressive enhancement: the bar slides in once the reader commits to the
   page (past ~a third of a viewport), instead of doubling the hero CTA on the
   first screen. Browsers without scroll timelines just show it from the start. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .volunteer-bar {
      animation: volunteer-bar-in 1 linear both;
      animation-timeline: scroll(root);
      animation-range: 30vh 110vh;
    }
    @keyframes volunteer-bar-in {
      from { transform: translateY(110%); opacity: 0; }
      to   { transform: none; opacity: 1; }
    }
  }
}

/* == Safety overrides for THIS page's animations ========================== */
@media (prefers-reduced-motion: reduce) {
  .volunteer-hero .stack > * { animation: none; }
  .volunteer-bar { animation: none; transform: none; opacity: 1; }
}
/* ======================= PAGE: donate ======================= */
.donate-card {
  background: var(--ink-2);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: clamp(1.8rem, 4.5vw, 3rem);
  box-shadow: var(--shadow);
  position: relative;
  overflow: hidden;
  margin-block-start: 1.5rem;
}
.donate-card::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0; height: 4px;
  background: linear-gradient(90deg, var(--sun), var(--ember), var(--brick));
}
.donate-card__head {
  margin-bottom: 2rem;
}
.donate-card__head h3 {
  font-size: var(--step-2);
  color: var(--cream);
  margin-bottom: .6rem;
}
.donate-card__head p {
  color: var(--cream-dim);
  font-size: var(--step-0);
  line-height: 1.6;
  max-width: 60ch;
}
.donate-card__actions {
  display: flex;
  flex-direction: column;
  gap: 1.4rem;
  align-items: stretch;
}
.donate-card__btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  font-size: 1.15rem;
  padding: 1.05rem 1.8rem;
  border-radius: var(--radius-sm);
  background: linear-gradient(135deg, var(--sun), var(--ember));
  color: var(--ink);
  font-family: var(--display);
  font-weight: 800;
  text-decoration: none;
  box-shadow: 0 12px 28px -10px rgb(243 122 47 / .5);
  transition: transform .2s ease, box-shadow .2s ease, filter .2s ease;
}
.donate-card__btn:hover {
  transform: translateY(-2px);
  filter: brightness(1.06);
  box-shadow: 0 16px 36px -10px rgb(243 122 47 / .65);
}
.donate-card__btn svg {
  width: 1.25em;
  height: 1.25em;
  flex: none;
}
.donate-trust {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 1.2rem 2rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--hairline);
  color: var(--muted);
  font-size: .88rem;
}
.donate-trust__item {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
}
.donate-trust__item svg {
  width: 1.15em;
  height: 1.15em;
  color: var(--sun);
  flex: none;
}

/* ---------- Reduced motion (must be LAST) -------------------------------- */
/* This lived next to .nav__burger, which put it BEFORE the mobile nav block — equal specificity,
   so the later rule won and the staggered entrance still ran for people who asked for no motion.
   Cascade order is the fix; keep this at the end of the file. */
@media (prefers-reduced-motion: reduce) {
  .nav__burger i { transition: none; }
  .nav__links { transition: none; }
  .nav__links[data-open="true"] li { animation: none; }
  .nav__backdrop { transition: none; }
}
