:root{
  --ground:#FFFFFF;
  --cream:#FFF3E0;
  --ink:#003A7F;
  --red:#EE4123;
  --orange:#F47524;
  --yellow:#FEC226;
  --accent:#C4360F;
  /* Sampled from assets/render-07.webp with PIL, not eyeballed.
     The illustration's own paper is #FDF2DE (modal edge colour, 8k+ px sample) and its
     ground band is #023A76 — both a hair off --cream/--ink. The hero ground and the
     full-bleed foot band use these exact values so the art has no cut line around it. */
  --cream-art:#FDF2DE;
  --navy-art:#023A76;
  --line:rgba(0,58,127,.16);
  --line-strong:rgba(0,58,127,.28);
  --ink-70:rgba(0,58,127,.72);
  --ink-55:rgba(0,58,127,.72);   /* 5.05:1 on #FFFFFF, 4.83:1 on #FFF3E0 — WCAG AA */
  --display:'Fraunces',Georgia,serif;
  --body:'Archivo',system-ui,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
/* Anchor jumps land clear of the 65px sticky header */
[id]{scroll-margin-top:88px}
body{
  background:var(--ground);color:var(--ink);
  font-family:var(--body);font-size:17px;line-height:1.55;
  letter-spacing:-.010em;font-weight:400;
  -webkit-font-smoothing:antialiased;position:relative;overflow-x:hidden;
}
/* ---------- grain ----------
   Was a viewport-sized position:fixed layer with mix-blend-mode:multiply. Two problems:
   the blend forced a full-viewport compositor readback on every scroll frame, and every
   header/section/footer sits at z-index:1 (see below), so the layer was occluded on all
   content anyway — and over plain white, multiply was a near no-op that only read as dirt.
   The texture now lives on the cream and navy surfaces, contained and composited cheaply. */
.surface-cream,.band{isolation:isolate}
.surface-cream::before,.band::before{
  content:'';position:absolute;inset:0;pointer-events:none;z-index:0;
  contain:strict;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.72' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='260' height='260' filter='url(%23n)'/%3E%3C/svg%3E");
}
.surface-cream::before{opacity:.075}
.band::before{opacity:.05}
h1,h2,h3,.display{font-family:var(--display);font-weight:500;font-variation-settings:'SOFT' 40,'WONK' 1}
h1{font-size:clamp(46px,6.4vw,86px);line-height:.98;letter-spacing:-.028em;text-wrap:balance}
h2{font-size:clamp(32px,4.2vw,56px);line-height:1.04;letter-spacing:-.022em}
h3{font-size:21px;line-height:1.2;letter-spacing:-.012em;font-weight:500}
p{max-width:62ch}
.wrap{width:min(1240px,90vw);margin-inline:auto}
.eyebrow{
  font-family:var(--body);font-size:12px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-55);
  display:inline-flex;align-items:center;gap:10px;
}
.eyebrow::before{content:'';width:26px;height:1px;background:var(--ink-55);display:block}
/* ---------- buttons ---------- */
.btn{
  display:inline-flex;align-items:center;gap:8px;
  padding:11px 20px 12px;min-height:44px;border-radius:6px;
  font-family:var(--body);font-size:15px;font-weight:500;letter-spacing:-.01em;
  border:1px solid transparent;cursor:pointer;text-decoration:none;
  transition:transform .1s ease-out,background-color .15s ease,border-color .15s ease,color .15s ease;
}
.btn--primary{background:var(--ink);color:var(--ground)}
.btn--secondary{background:transparent;color:var(--ink);border-color:var(--line-strong)}
.btn--tertiary{background:transparent;color:var(--accent);padding-inline:0}
.btn:hover{transform:translateY(-1px);filter:brightness(1.12)}
.btn--secondary:hover{border-color:var(--ink);filter:none}
.btn:active{transform:scale(.97)}
.btn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* ---------- nav ---------- */
header{
  position:sticky;top:0;z-index:50;background:rgba(255,255,255,.93);
  backdrop-filter:blur(6px);border-bottom:1px solid var(--line);
}
.nav{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:12px 0}
.nav img{height:58px;width:auto;display:block}
.nav ul{display:flex;gap:28px;list-style:none;align-items:center}
.nav a{color:var(--ink);text-decoration:none;font-size:15px;font-weight:500;letter-spacing:-.01em;display:inline-flex;align-items:center;min-height:32px}
.nav a:hover{color:var(--accent)}
.nav a.btn--primary{color:#fff}
.nav a.btn--primary:hover{color:#fff}
/* ---------- mobile nav disclosure ----------
   The base .navtoggle{display:none} MUST sit before the 860px media query: both are
   single-class selectors, so a media-query rule does not out-specify a plain one and
   source order decides. Declared after, it hid the hamburger at every width. */
.navtoggle{display:none;position:static}
@media(max-width:860px){
  .nav ul{display:none}
  .navtoggle{display:block}
  .nav > .btn--primary{display:none}
  .nav img{height:46px}
}
.navtoggle > summary{
  list-style:none;display:inline-flex;align-items:center;gap:8px;
  min-height:44px;padding:10px 14px;border:1px solid var(--line-strong);border-radius:6px;
  cursor:pointer;font-family:var(--body);font-size:15px;font-weight:500;color:var(--ink);
}
.navtoggle > summary::-webkit-details-marker{display:none}
.navtoggle > summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.navtoggle[open] > summary{background:var(--cream)}
.navtoggle .ico-close{display:none}
.navtoggle[open] .ico-open{display:none}
.navtoggle[open] .ico-close{display:block}
.navtoggle .navpanel{
  /* .wrap is 90vw at this breakpoint, so -5vw reaches both viewport edges */
  position:absolute;left:-5vw;right:-5vw;top:100%;background:var(--ground);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:8px 5vw 16px;max-height:calc(100svh - 84px);overflow-y:auto;
}
.navtoggle .navpanel a{
  display:block;min-height:48px;line-height:48px;font-size:17px;
  border-bottom:1px solid var(--line);color:var(--ink);text-decoration:none;
}
/* must beat .nav a.btn--primary (0,2,1) — same specificity, later in source order */
.navtoggle .navpanel a.btn--primary{color:var(--ground)}
.navtoggle .navpanel .btn{
  margin-top:14px;width:100%;justify-content:center;line-height:normal;border-bottom:0;
}
/* ---------- render placeholder ---------- */
.ph{
  position:relative;border:1.5px dashed var(--line-strong);border-radius:6px;
  background:
    repeating-linear-gradient(135deg,rgba(0,58,127,.035) 0 12px,transparent 12px 24px);
  display:flex;flex-direction:column;justify-content:center;
  padding:20px;gap:6px;min-height:120px;
}
.ph b{font-family:var(--body);font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--accent)}
.ph span{font-size:13px;color:var(--ink-70);line-height:1.4;max-width:44ch}
.ph i{font-style:normal;font-size:11px;color:var(--ink-55);letter-spacing:.02em}
/* ---------- hero ---------- */
.hero{
  display:grid;
  grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  gap:clamp(32px,5vw,72px);align-items:center;
  padding:clamp(64px,9vw,140px) 0 var(--hero-foot,clamp(56px,7vw,104px));
}
@media(max-width:900px){.hero{grid-template-columns:1fr;gap:36px}}
/* ---------- hero event block ----------
   Dates, hours, venue and admission in ONE bordered group so the when/where reads as a
   single prominent unit. Replaces the old .datestack eyebrow + .rule + .venue lines. */
.eventblock{border-top:1px solid var(--line-strong);border-bottom:1px solid var(--line-strong);padding:22px 0;margin:28px 0 24px;display:flex;flex-direction:column;gap:7px}
.eventblock__dates{font-family:var(--display);font-size:clamp(30px,3.6vw,46px);line-height:1.02;letter-spacing:-.022em;color:var(--ink);font-weight:500}
.eventblock__hours{font-size:16px;font-weight:600;color:var(--ink);letter-spacing:.01em}
.eventblock__venue{font-size:15px;color:var(--ink-70)}
.eventblock__venue strong{color:var(--ink)}
@media(max-width:600px){.eventblock{padding:18px 0}.eventblock__sep{display:none}.eventblock__hours .nowrap{display:block}}
.rule{height:1px;background:var(--line);margin:26px 0}
.venue{font-size:16px;color:var(--ink-70)}
.venue strong{font-weight:600;color:var(--ink)}
.cta-row{display:flex;gap:12px;flex-wrap:wrap;margin-top:28px}
.count{display:flex;gap:22px;margin-top:32px}
.count div{display:flex;flex-direction:column;gap:2px}
.count{gap:34px;margin-top:40px;padding-top:26px;border-top:1px solid var(--line)}
.count b{font-family:var(--display);font-size:42px;font-weight:500;line-height:1;letter-spacing:-.026em}
.count span{font-size:12px;text-transform:uppercase;letter-spacing:.12em;color:var(--ink-55);font-weight:600}
/* ---------- sunset (hand-coded SVG, hard edges) ----------
   No radius, no clip, no border: the illustration's own paper is the section ground, so a
   box around it would be a cut line. See .heroart::after for the foot band. */
.heroart{position:relative}
.heroart svg{width:100%;height:clamp(300px,34vw,470px);display:block}
.heroart img{width:100%;height:auto;display:block}
@media(max-width:900px){.heroart{margin-right:0}}
/* ---------- sections ---------- */
section{padding-block:clamp(64px,8vw,132px)}
.lede{font-size:clamp(21px,2.3vw,30px);line-height:1.32;letter-spacing:-.014em;font-family:var(--display);font-weight:400;max-width:22ch}
.two{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr);gap:clamp(32px,5vw,72px);align-items:start}
@media(max-width:860px){.two{grid-template-columns:1fr;gap:28px}}
/* ---------- toggle ---------- */
.toggle{display:inline-flex;border:1px solid var(--line-strong);border-radius:6px;padding:3px;gap:3px;margin-bottom:36px}
.toggle button{
  font-family:var(--body);font-size:14px;font-weight:500;letter-spacing:-.01em;
  padding:12px 18px;min-height:44px;border:0;border-radius:4px;background:transparent;color:var(--ink-70);cursor:pointer;
  transition:background-color .15s ease,color .15s ease;
}
.toggle button[aria-selected="true"]{background:var(--ink);color:var(--ground)}
.toggle button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.steps{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:20px}
@media(max-width:1000px){.steps{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:600px){.steps{grid-template-columns:1fr;gap:28px}}
.step{border-top:1px solid var(--ink);padding-top:20px;display:flex;flex-direction:column;gap:10px}
.step .num{font-family:var(--display);font-size:46px;line-height:.85;color:var(--accent);font-weight:600;
  letter-spacing:-.03em;-webkit-text-stroke:0}
.step h3{margin-top:-4px}
.step p{font-size:15px;color:var(--ink-70);max-width:34ch}
.surface-cream{background:var(--cream)}
/* ---------- keys band ---------- */
.band{position:relative;color:var(--ground);background:var(--ink);overflow:hidden}
.band .inner{position:relative;z-index:2;padding-block:clamp(64px,8vw,120px)}
.band h2{max-width:24ch}
.band p{color:rgba(255,243,224,.78);margin-top:18px;font-size:18px}
.band .ph{border-color:rgba(255,243,224,.35);background:repeating-linear-gradient(135deg,rgba(255,243,224,.06) 0 12px,transparent 12px 24px)}
.band .ph b{color:var(--yellow)}
.band .ph span,.band .ph i{color:rgba(255,243,224,.75)}
/* ---------- pricing ---------- */
.price-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px;max-width:none}
@media(max-width:900px){.price-grid{grid-template-columns:1fr}}
.price{border:1px solid var(--line);border-radius:6px;padding:32px 30px 34px;background:#fff}
.price--lead{border-color:var(--ink);border-width:1.5px}
.price .amt{font-family:var(--display);font-size:64px;line-height:.9;font-weight:500;letter-spacing:-.032em}
.price .amt sup{font-size:22px;vertical-align:super;font-weight:500}
.price h3{margin-bottom:12px}
.price ul{list-style:none;margin-top:18px;display:flex;flex-direction:column;gap:9px}
.price li{font-size:15px;color:var(--ink-70);display:flex;gap:10px;align-items:flex-start}
.tick{flex:none;margin-top:3px}
.note{font-size:14px;color:var(--ink-55);margin-top:16px}
/* ---------- faq ---------- */
.faq{border-top:1px solid var(--line)}
.faq details{border-bottom:1px solid var(--line)}
.faq summary{
  list-style:none;cursor:pointer;padding:24px 0;font-size:19px;font-weight:500;
  display:flex;justify-content:space-between;gap:20px;align-items:center;letter-spacing:-.012em;
}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--accent)}
.faq summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.faq .a{padding:0 0 20px;color:var(--ink-70);font-size:16px;max-width:66ch}
.faq .pm{flex:none;transition:transform .15s ease}
details[open] .pm{transform:rotate(45deg)}
/* ---------- footer ---------- */
footer{border-top:1px solid var(--line);padding-block:44px;font-size:14px;color:var(--ink-70)}
.foot{display:flex;justify-content:space-between;gap:32px;flex-wrap:wrap}
footer a{color:var(--ink-70);text-decoration:none;display:block;padding:11px 0;min-height:44px;line-height:22px}
footer a:hover{color:var(--accent)}
.foot h4{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-55);margin-bottom:10px;font-weight:600;font-family:var(--body)}
/* one modest copyright line, last thing in the footer on every page */
.footlegal{margin-top:32px;padding-top:20px;border-top:1px solid var(--line);font-size:13px;color:var(--ink-55)}
.plc{background:rgba(196,54,15,.07);border-left:2px solid var(--accent);padding:2px 6px;border-radius:2px}
@media(prefers-reduced-motion:reduce){*{transition-duration:.01ms!important;animation-duration:.01ms!important}}
/* ===== added for inner pages ===== */
.pagehead{padding:clamp(56px,8vw,110px) 0 clamp(32px,4vw,54px);border-bottom:1px solid var(--line)}
.pagehead h1{max-width:16ch}
.pagehead .lede{margin-top:20px;font-family:var(--body);font-size:19px;line-height:1.5;
  color:var(--ink-70);max-width:58ch;font-weight:400;letter-spacing:-.01em}
.prose{max-width:68ch}
.prose h2{margin:44px 0 14px}
.prose h3{margin:30px 0 8px}
.prose p{margin-bottom:16px;color:var(--ink-70)}
.prose ul{margin:0 0 18px 20px;color:var(--ink-70)}
.prose li{margin-bottom:8px}
.checklist{list-style:none;margin:0;display:grid;gap:0}
.checklist li{display:flex;gap:14px;align-items:flex-start;padding:16px 0;border-top:1px solid var(--line);color:var(--ink-70);margin:0}
.checklist li:last-child{border-bottom:1px solid var(--line)}
.checklist strong{color:var(--ink);font-weight:600;display:block;margin-bottom:2px}
.bignum{font-family:var(--display);font-size:44px;line-height:.85;color:var(--accent);font-weight:600;letter-spacing:-.03em;flex:none;width:64px}
.grid3{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(20px,3vw,36px)}
@media(max-width:860px){.grid3{grid-template-columns:1fr}}
.card{border-top:1px solid var(--ink);padding-top:20px}
.card p{font-size:15px;color:var(--ink-70);margin-top:8px}
.legal{font-size:15px;color:var(--ink-70)}
.legal h2{font-size:24px;margin:36px 0 10px}
.sunsetrule{display:block;width:100%;height:auto;margin:0}
.modalnote{border:1.5px dashed var(--line-strong);border-radius:6px;padding:24px;background:repeating-linear-gradient(135deg,rgba(0,58,127,.035) 0 12px,transparent 12px 24px)}

/* Content sits above the per-surface grain layer.
   `header` is deliberately NOT in this list: it declares position:sticky;z-index:50
   above, and this rule (same 0,0,1 specificity, later in source) was silently
   overriding both — the header was not actually sticky, and the mobile nav panel
   painted underneath the page content. */
section,footer,.band,.hero{position:relative}
.wrap{position:relative;z-index:1}
img{image-rendering:auto}

/* text-only step list — used where illustration was cut */
.steps--text{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:0}
.steps--text .step{
  border-top:1px solid var(--ink);border-right:1px solid var(--line);
  padding:22px 24px 26px 0;margin-right:24px;min-height:200px;
}
/* Clear ONLY the divider on the last visible step. padding-right/margin-right stay
   identical on every step so all content boxes are the same width (clearing them made
   the last box 49px wider, which grew its 4:3 image and pushed num/title down ~37px).
   The trailing empty 24px gutter it leaves is invisible. */
.steps--text .step:last-child{border-right:0}
.steps--text .step .num{font-size:52px;margin-bottom:2px}
@media(max-width:1000px){
  .steps--text{grid-template-columns:repeat(2,minmax(0,1fr))}
  .steps--text .step:nth-child(2n){border-right:0}
}
@media(max-width:600px){
  .steps--text{grid-template-columns:1fr}
  .steps--text .step{border-right:0;margin-right:0;padding-right:0;min-height:0}
}

/* ---------- three-step variant ----------
   index.html's sell and buy panels run three steps after Mel's round-1 rewrite;
   how-it-works.html still runs four and shares both .steps and .steps--text, so this is
   a modifier and never an edit to the base rules. It has the same specificity as .steps,
   so it must sit AFTER the base breakpoints above — source order is what decides — and
   it therefore has to restate its own 1000px and 600px collapses. */
.steps--3{grid-template-columns:repeat(3,minmax(0,1fr))}
.steps--text.steps--3{grid-template-columns:repeat(3,minmax(0,1fr))}
/* The buy panel's last child is the RSVP block, not a step, so `.steps--text .step:last-child`
   never matches and step 3 would carry a divider with nothing to its right. Step 3 has no
   right-hand neighbour at three columns, at two, or at one — so clear it unconditionally.
   The RSVP block itself spans the row via .rsvp--panel{grid-column:1/-1}. */
.steps--text.steps--3 .step:nth-child(3){border-right:0}
/* Three columns never divide into two without orphaning the third step on its own row,
   so the 3-step variant goes straight from 3 columns to 1 at 1000px. The base 4-step
   .steps/.steps--text keep their 2x2 tablet layout — that rule is untouched.
   In one column no step has a right-hand neighbour, so every divider is cleared. */
@media(max-width:1000px){
  .steps--3{grid-template-columns:1fr}
  .steps--text.steps--3{grid-template-columns:1fr}
  .steps--text.steps--3 .step{border-right:0}
}
@media(max-width:600px){
  .steps--3{grid-template-columns:1fr}
  .steps--text.steps--3{grid-template-columns:1fr}
}

/* ---------- pull-quote band ----------
   Mel's paragraph B, standing alone between the hero and the ticker. Display type on the
   page's own ground, no quotation marks added — her text is the whole element. */

/* ============================================================
   Utilities and components added in the v5 upgrade pass
   ============================================================ */

/* utility: must win over any layout rule above, including .steps--text */
[hidden]{display:none!important}
/* .hide is the tab-panel toggle. Gated on .js so that with JavaScript disabled both
   step panels render stacked and Mel's buyer steps stay reachable. */
.js .hide{display:none!important}

/* utility: keep a phrase whole. Line breaking is allowed after an en-dash, so the hero
   hours line broke as "Sunday 9am–" / "4pm" at 390px; wrapping each day in .nowrap
   leaves the space beside the separator dot as the only break opportunity. */
.nowrap{white-space:nowrap}

/* skip link + screen-reader-only helper */
.skiplink{
  position:absolute;left:-9999px;top:0;z-index:100;
  background:var(--ink);color:var(--ground);
  font-family:var(--body);font-size:15px;font-weight:500;
  padding:12px 18px;border-radius:0 0 6px 0;text-decoration:none;
}
.skiplink:focus{left:0}
/* ---------- focus ring, one ring everywhere ----------
   Buttons, the nav disclosure, the FAQ summaries and the poster link already used
   2px solid var(--accent) at 2px offset. Header nav links, the logo link, footer
   links and the skip link fell back to the UA default, which is invisible against
   the navy header on several browsers. Same ring, same offset, everywhere. */
.skiplink:focus-visible,
.nav a:focus-visible,
.navpanel a:focus-visible,
footer a:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* The skip link sits flush to the viewport edge when focused, so pull its ring
   inside rather than letting it clip off-screen. */
.skiplink:focus-visible{outline-offset:-2px}
/* Tabpanels take focus from the tablist. The UA default draws a box around the
   whole step grid; this keeps the same ring as everything else, held further off
   so it reads as a region boundary rather than a control. */
.steps:focus-visible{outline:2px solid var(--accent);outline-offset:6px}
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}

/* ---------- spots remaining ---------- */
.spots{font-size:15px;color:var(--ink-70);font-weight:500}
.spots b{font-weight:600;color:var(--ink)}
.spots[data-spots-state="low"] b{color:var(--accent)}
.spots[data-spots-state="full"] b{color:var(--accent)}
.note.spots{font-size:14px}

/* ---------- add to calendar ---------- */
.addcal{display:flex;gap:12px;flex-wrap:wrap;align-items:center;margin-top:18px}
.addcal__btn svg{flex:none}
.addcal__alt{font-size:14px}
footer .addcal{margin-top:14px}
footer .addcal .btn{font-size:14px;min-height:44px;display:inline-flex}
footer .addcal a{padding-block:11px}
@media(max-width:520px){
  .addcal{gap:8px}
  .addcal__btn{width:100%;justify-content:center}
}

/* ============================================================
   Mobile composition pass — 600px and below
   Tightens vertical rhythm so the homepage reads as composed rather than
   a shrunken desktop page. No new colours, shadows or radii.
   ============================================================ */
@media(max-width:600px){
  section{padding-block:clamp(48px,12vw,64px)}
  .hero{padding:clamp(40px,11vw,56px) 0 var(--hero-foot,clamp(56px,7vw,104px));gap:30px}
  .pagehead{padding:clamp(44px,11vw,60px) 0 clamp(26px,7vw,36px)}
  /* hero art runs the full viewport width, under the text, uncropped */
  .heroart{margin-inline:calc((100vw - min(1240px,90vw))/-2)}
  .heroart img{width:100%;height:auto}
  /* countdown numerals step down so three columns breathe at 390px */
  .count{gap:20px;margin-top:30px;padding-top:22px}
  .count b{font-size:33px}
  .count span{font-size:11px;letter-spacing:.10em}
  .rule{margin:20px 0}
  .cta-row{margin-top:22px;gap:10px}
  .cta-row .btn{flex:1 1 100%;justify-content:center}
  h2{font-size:clamp(30px,8.6vw,38px)}
  /* one step per row, with rhythm rather than a hard 20px grid gap */
  .steps{gap:30px}
  .steps--text .step{padding:20px 0 4px;min-height:0}
  .step{padding-top:18px}
  .checklist li{padding:14px 0}
  .price{padding:26px 22px 28px}
  .price-grid{gap:16px}
  .foot{gap:22px}
  .two{gap:24px}
  .grid3{gap:24px}
}

/* ============================================================
   v6 — "alive and lived-in" hero pass
   Three moves, no new ornament: the art is unboxed onto its own paper, its ground band
   runs full bleed as the section's foot, and a slow ticker rail sits under it.
   Palette, radius, borders and the no-shadow rule are unchanged.
   ============================================================ */

/* ---------- hero ground ----------
   overflow-x:clip (not hidden) lets the foot band run past the section's box without
   creating a scroll container, so nothing can produce a horizontal scrollbar. */
.hero-sec{
  position:relative;isolation:isolate;overflow-x:clip;
  background:var(--cream-art);
  --hero-foot:clamp(80px,7.5vw,118px);
}
/* One grain plane over the WHOLE hero — ground, illustration and foot band alike.
   Textured ground against flat art is exactly what would read as a seam, so the grain
   sits above the content (z-index:3) rather than behind it. */
.hero-sec::after{
  content:'';position:absolute;inset:0;z-index:3;pointer-events:none;contain:strict;
  opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='260'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.72' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='260' height='260' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- the foot band ----------
   render-07.webp is 1264x848 and its navy ground starts at y=701 => 82.66% of the image
   box. Anchoring the band to that percentage of .heroart keeps the join exact at every
   width without JS. The art hangs var(--hero-foot) below the grid row so the band lands
   flush with the bottom of the section, and the text column clears it. */
.heroart{align-self:end;margin-bottom:calc(-1 * var(--hero-foot))}
/* Two columns only: the art runs out past the 1240px measure toward the right trim, the
   way a poster is printed. Capped at 190px so the foot band (11.633% of the art's width)
   can never grow taller than --hero-foot and reach the countdown. Because the art's paper
   and the ground are the same colour, where it stops is invisible. */
@media(min-width:901px){
  .heroart{margin-right:calc(-1 * min((100vw - min(1240px,90vw)) / 2, 190px))}
}
.heroart::after{
  content:'';position:absolute;z-index:-1;
  top:82.66%;bottom:0;left:-100vw;right:-100vw;
  background:var(--navy-art);
}

/* ---------- entrance, once, on load ----------
   Opacity/transform only, no bounce, nothing on scroll, last group lands at 670ms.
   The transform is on the <img>, not .heroart — moving .heroart would drag the foot
   band with it. Gated on no-preference so reduced motion gets no animation at all. */
@keyframes heroRise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@keyframes heroArtRise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:no-preference){
  .hero [data-enter]{animation:heroRise .46s cubic-bezier(.22,.61,.36,1) both}
  .hero [data-enter="2"]{animation-delay:.07s}
  .hero [data-enter="3"]{animation-delay:.14s}
  .hero [data-enter="4"]{animation-delay:.21s}
  .hero .heroart img{animation:heroArtRise .6s cubic-bezier(.22,.61,.36,1) .06s both}
}

/* ---------- spots badge ----------
   Same element, same data-spots hooks spots.js writes into — only the skin changed. */
.spotsbadge{
  display:inline-flex;align-items:baseline;gap:.4em;
  margin-top:20px;padding:7px 11px 6px;
  border:1px solid var(--accent);border-radius:6px;
  font-family:var(--body);font-size:11px;font-weight:600;line-height:1;
  letter-spacing:.13em;text-transform:uppercase;color:var(--accent);
}
.spotsbadge b{font-weight:600}
.spotsbadge[data-spots-state="full"]{border-color:var(--line-strong);color:var(--ink-70)}
/* Static copy in the same pill — no spots.js hooks, so it only needs its own
   vertical rhythm under a section subheader. */
.spotsbadge--static{margin-top:16px;margin-bottom:32px}

/* ---------- ticker rail ----------
   White ground so the navy foot band gets a hard bottom edge and the poster stops where
   the page starts. Hairlines top and bottom; the top one falls on navy and just reads as
   the band's own edge. */
.ticker{
  position:relative;overflow:hidden;background:var(--ground);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  padding-block:11px;
}
.ticker__track{display:flex;width:max-content;animation:tickerRun 72s linear infinite}
.ticker:hover .ticker__track,.ticker:focus-within .ticker__track{animation-play-state:paused}
@keyframes tickerRun{from{transform:translateX(0)}to{transform:translateX(-50%)}}
.ticker__seg{display:flex;align-items:center;flex:none}
.ticker__seg span{
  font-family:var(--body);font-size:12px;font-weight:600;line-height:1;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink);
  white-space:nowrap;padding-inline:18px;
}
.ticker__sun{flex:none;display:block}
@media(prefers-reduced-motion:reduce){
  /* One instance, parked. animation:none beats the global animation-duration override
     because it clears the animation-name, so getAnimations() returns nothing. */
  .ticker__track{animation:none;width:auto}
  .ticker__seg[aria-hidden]{display:none}
  /* The one remaining copy wraps and centres instead of being clipped at the trim, so the
     line stays fully readable at 390px without a scrollbar. */
  .ticker{padding-inline:max(20px,calc((100% - min(1240px,90vw)) / 2))}
  .ticker__seg{flex:1 1 auto;min-width:0;flex-wrap:wrap;justify-content:center;row-gap:5px}
  .ticker__seg span{white-space:normal}
}

@media(max-width:600px){
  .hero-sec{--hero-foot:clamp(44px,11vw,58px)}
  .ticker{padding-block:9px}
  .ticker__seg span{font-size:11px;letter-spacing:.12em;padding-inline:13px}
  .spotsbadge{margin-top:18px;letter-spacing:.11em}
}

/* ============================================================
   v7 — site-wide motion system
   The same language as the hero entrance, extended past the fold: things
   arrive from 10px below, once, ease-out, and then they are simply there.

   Three gates, all of which must pass before a single pixel is hidden:

     1. `.js` on <html>, set by an inline script in <head>. With JavaScript off
        the attribute selectors below never match, so nothing is ever hidden
        and every page is complete on first paint.
     2. prefers-reduced-motion: no-preference. Under `reduce` these rules do
        not exist — not "run instantly", do not exist — so no element carries a
        hidden initial state and document.getAnimations() stays empty.
     3. opacity and transform only. Neither affects layout, so the initial
        state contributes exactly zero CLS and every frame is compositor-only.

   The one deliberate exception is the header compress and the <details> open,
   both of which animate a box property; both are noted where they appear.
   ============================================================ */
@media(prefers-reduced-motion:no-preference){

  /* ---------- 1. scroll reveal ----------
     motion.js adds .inview once and unobserves, so this never plays twice. */
  .js [data-reveal]{
    opacity:0;transform:translateY(10px);
    transition:opacity .45s cubic-bezier(.22,.61,.36,1),
               transform .45s cubic-bezier(.22,.61,.36,1);
  }
  .js [data-reveal].inview{opacity:1;transform:none}
  /* Stagger by position among siblings. Every reveal group on this site is
     either all-reveal (step grids, price cards, footer columns) or a heading
     block whose eyebrow/h2 are the first children of their box, so nth-child
     lands on the right ordinal without a wrapper element. Capped at the fifth
     so a long column never waits more than 280ms to start. */
  .js [data-reveal]:nth-child(2){transition-delay:70ms}
  .js [data-reveal]:nth-child(3){transition-delay:140ms}
  .js [data-reveal]:nth-child(4){transition-delay:210ms}
  .js [data-reveal]:nth-child(n+5){transition-delay:280ms}

  /* ---------- 2. the sunset rule sweep ----------
     The signature moment. Four bands scale out from alternating edges, 90ms
     apart, so the rule draws itself like a sunrise rather than fading in.
     transform-box:fill-box makes `left`/`right` resolve against each rect's own
     box; the svg keeps preserveAspectRatio="none", so this is still one
     compositor-only scale per band. The cream backing rect is not animated,
     which is what keeps the reserved 120px band from flashing empty. */
  .js .sunsetrule g rect{
    transform:scaleX(0);transform-box:fill-box;
    transition:transform .6s cubic-bezier(.22,.61,.36,1);
  }
  .js .sunsetrule g rect:nth-child(odd){transform-origin:left center}
  .js .sunsetrule g rect:nth-child(even){transform-origin:right center}
  .js .sunsetrule g rect:nth-child(2){transition-delay:90ms}
  .js .sunsetrule g rect:nth-child(3){transition-delay:180ms}
  .js .sunsetrule g rect:nth-child(4){transition-delay:270ms}
  .js .sunsetrule.inview g rect{transform:none}

  /* ---------- 3. countdown tick ----------
     Added by the countdown updater in index.html only when a digit's value
     actually changes, never on the first fill. .count b is a flex item, so it
     is blockified and the translate applies. */
  @keyframes cdTick{from{opacity:.4;transform:translateY(6px)}to{opacity:1;transform:none}}
  .count b.tick{animation:cdTick .2s cubic-bezier(.22,.61,.36,1)}

  /* ---------- 4. FAQ smooth open ----------
     Pure CSS on the native disclosure. No script touches <details>, so the
     summary stays keyboard-toggleable, the open attribute stays authoritative,
     and with JS off the panel opens instantly as it always did. block-size is
     a layout property — unavoidable for a real height reveal, and acceptable
     here because it is one short-lived 250ms transition on one small subtree.
     Scoped to .faq so the mobile nav disclosure is untouched. */
  @supports (interpolate-size:allow-keywords){
    .js .faq details{interpolate-size:allow-keywords}
    .js .faq details::details-content{
      block-size:0;overflow:clip;
      transition:block-size .25s cubic-bezier(.22,.61,.36,1),
                 content-visibility .25s cubic-bezier(.22,.61,.36,1) allow-discrete;
    }
    .js .faq details[open]::details-content{block-size:auto}
  }
  /* Where ::details-content is not available, the answer fades in instead of
     the box growing. Still no JS, still nothing that can break semantics. */
  @supports not (interpolate-size:allow-keywords){
    @keyframes faqIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
    .js .faq details[open] .a{animation:faqIn .25s cubic-bezier(.22,.61,.36,1)}
  }

  /* ---------- 5. header compress ----------
     The header is position:sticky, which means it still occupies its slot in
     normal flow — so shrinking it would pull the entire document up by the
     same amount, a ~18px lurch on every crossing of the 80px line. motion.js
     measures the height the bar gives up and hands exactly that back as
     margin-bottom, transitioned on the same curve and duration so the two
     cancel on every frame and the page body never moves. The reclaimed strip
     sits between the header's border and the content, which in the compressed
     state is always scrolled up behind the stuck bar, so it is never seen.

     It has to be measured rather than written down here: the compressed bar is
     as tall as its tallest child, and past 860px that is the "Register your
     car" button, not the logo — a number that moves with the webfont. */
  .js header{transition:margin-bottom .25s cubic-bezier(.22,.61,.36,1)}
  .js header .nav{transition:padding-block .25s cubic-bezier(.22,.61,.36,1)}
  .js header .nav img{transition:height .25s cubic-bezier(.22,.61,.36,1)}
}

/* The compressed state itself is a state, not an animation: motion.js only
   applies it when motion is allowed, so these sit outside the media query
   purely so the transition above and the target values read together. */
.js header.scrolled .nav{padding-block:8px}
.js header.scrolled .nav img{height:46px}

/* Held for the two frames in which motion.js measures the compressed height,
   so the measurement reads the settled values and no transition is visible. */
.js header.measuring,.js header.measuring *{transition:none!important}

/* ============================================================
   Buyer RSVP — v8
   The one conversion the site was missing. Four placements share one block:
   the buy.html page head, the buyer tab panel and the final CTA on index, and
   the footer strip on every page. Markup is identical in all of them; only the
   modifier class changes, so rsvp.js has exactly one shape to reason about.

   With JavaScript off the <form> still carries method="POST" and an action of
   its own page path, which is what Netlify Forms expects — the enhancement in
   rsvp.js only replaces the full page reload with a fetch.
   ============================================================ */
.rsvp{max-width:520px}
.rsvp__row{display:flex;gap:10px;flex-wrap:wrap;align-items:stretch}
.rsvp__input{
  flex:1 1 220px;min-width:0;height:44px;padding:0 12px;
  font-family:var(--body);font-size:16px;line-height:1.2;
  color:var(--ink);letter-spacing:-.01em;
  background:var(--ground);border:1px solid var(--line-strong);border-radius:6px;
}
.rsvp__input::placeholder{color:var(--ink-55)}
.rsvp__input:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-color:var(--ink)}
.rsvp__row .btn{flex:0 0 auto;min-height:44px}
.rsvp__note{font-size:13px;line-height:1.45;color:var(--ink-55);margin-top:10px;max-width:44ch}
/* The live region is present from first paint and stays put when the form is
   hidden, so assistive tech announces the change instead of a node swap. */
.rsvp__msg{font-size:14px;line-height:1.5;max-width:44ch;margin:0}
.rsvp__msg:empty{display:none}
.rsvp__msg--ok{color:var(--ink);font-weight:600}
.rsvp__msg--ok strong{font-weight:600}
.rsvp__msg-addr{word-break:break-word}
.rsvp__msg--err{color:var(--accent)}
.rsvp__msg a{color:var(--accent);text-decoration:underline;text-underline-offset:2px}
/* honeypot: off-canvas, out of the tab order, still submitted */
.rsvp__hp{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
@media(max-width:420px){
  .rsvp__row .btn{flex:1 1 100%;justify-content:center}
}

/* index — inside the buyer tab panel. Spans the whole step grid at every column count
   (the panel is .steps--text.steps--3), so it always lands on its own full-width row. */
.rsvp--panel{
  grid-column:1/-1;max-width:560px;
  border-top:1px solid var(--ink);padding-top:22px;margin-top:4px;
}
.rsvp--panel .rsvp__lead{font-family:var(--display);font-size:21px;line-height:1.2;letter-spacing:-.012em;margin-bottom:14px}

/* index — final CTA */
.ctarsvp{display:flex;flex-direction:column;align-items:flex-start;gap:18px}
.ctarsvp .cta-row{margin:0}

/* buy.html — page head */
.rsvp--head{margin-top:26px}

/* footer strip, every page */
.footrsvp{
  display:flex;align-items:flex-start;justify-content:space-between;
  gap:24px 40px;flex-wrap:wrap;
  padding-bottom:30px;margin-bottom:30px;border-bottom:1px solid var(--line);
}
.footrsvp h4{
  font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--ink-55);
  margin-bottom:8px;font-weight:600;font-family:var(--body);
}
.footrsvp__lead{font-size:14px;color:var(--ink-70);max-width:34ch;margin:0}
.rsvp--inline{flex:0 1 460px}
/* footer a{display:block;padding:11px 0;min-height:44px} would wreck both the
   submit button and the mailto link in the failure message. */
footer .rsvp__msg a{display:inline;padding:0;min-height:0;line-height:inherit}
@media(max-width:700px){
  .footrsvp{display:block}
  .footrsvp__copy{margin-bottom:14px}
  .rsvp--inline{max-width:none}
}

/* 404 — the concentric sunset. Sized in ch-free absolutes so the arcs keep
   their hard butt caps at every width; it never exceeds the measure. */
.wrongturn{display:block;width:min(400px,100%);height:auto;border-radius:6px}

/* about — the downloadable event poster. Two columns that collapse to one; the
   art is a link as well as the button so the whole thing is one target. */
.poster{display:grid;grid-template-columns:280px 1fr;gap:clamp(24px,4vw,56px);align-items:center}
.poster__art{display:block;border-radius:6px;overflow:hidden;border:1px solid var(--line)}
.poster__art img{width:100%;height:auto;display:block}
.poster__art:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
@media(max-width:720px){
  .poster{grid-template-columns:1fr}
  .poster__art{max-width:280px}
}
