/* ============================================================================
   SALES UNIVERSITY — base.css  (tokens + primitives). v1 design pass.

   HOW THIS SYSTEM WORKS — read this before extending it
   1.  Everything that is a SIZE is a token in :root. Page CSS composes tokens
       only and contains ZERO raw px (the one exception: 1px hairlines).
   2.  Fluid tokens interpolate linearly between a 390px and a 1440px viewport
       as real clamp(MINpx, calc(INTERCEPTpx + SLOPEvw), MAXpx). The arithmetic
       is shown in the block below — never eyeball a new one, compute it.
   3.  Two layers of tokens: RAW STEPS (--t-*, --s-*, --r-*) which are the
       scale, and SEMANTIC ALIASES (--sec-y, --card-pad, --btn-pad, --gutter…)
       which are what page CSS should normally reach for. Add an alias rather
       than hard-coding a step in a page file.
   4.  Colour: ink does every job; accent does exactly ONE job on light ground
       (the .hl highlight) and ONE on dark ground (the primary button). Flat —
       no gradients, no blur glows, no semantic red/green.
   5.  Dark surfaces (.sec--panel, .panel, .apply-bar) work by REMAPPING the
       ink/paper/line tokens locally, so every primitive inside them inverts
       for free. Use --ink-abs / --paper-abs when you need the literal value.
   6.  Motion is class-driven: assets/js/motion.js adds .js to <html> and .is-in
       to elements; all animated states live under
       @media (prefers-reduced-motion:no-preference) and degrade to visible.

   FONTS — self-hosted from assets/fonts/, declared at the top of this file.
   Google Fonts made the critical path two extra round-trips deep; same-origin
   woff2 removes both. Put this exact preload set in every page <head> (the
   crossorigin keyword is required on font preloads even same-origin, or the
   preload is fetched twice):
   <link rel="preload" href="assets/fonts/archivo-black.woff2" as="font" type="font/woff2" crossorigin>
   <link rel="preload" href="assets/fonts/geist-var.woff2" as="font" type="font/woff2" crossorigin>
   <link rel="preload" href="assets/fonts/geist-mono-var.woff2" as="font" type="font/woff2" crossorigin>

   FLUID MATH — viewport 390 → 1440 (1050px of travel)
     slope(vw)     = (max - min) / (1440 - 390) * 100
     intercept(px) = min - slope * 390 / 100
     token         = clamp(MINpx, calc(INTERCEPTpx + SLOPEvw), MAXpx)
   Computed values (min→max ⇒ intercept + slope):
     t--2 12→13  11.6286 + 0.0952    s-1 4→6    3.2571 + 0.1905
     t--1 14→15  13.6286 + 0.0952    s-2 8→12   6.5143 + 0.381
     t-0  16→18  15.2571 + 0.1905    s-3 12→18  9.7714 + 0.5714
     t-1  18→22  16.5143 + 0.381     s-4 16→24  13.0286 + 0.7619
     t-2  20→26  17.7714 + 0.5714    s-5 24→36  19.5429 + 1.1429
     t-3  24→34  20.2857 + 0.9524    s-6 32→48  26.0571 + 1.5238
     t-4  32→56  23.0857 + 2.2857    s-7 48→72  39.0857 + 2.2857
     t-5  44→96  24.6857 + 4.9524    s-8 64→104 49.1429 + 3.8095
     t-6  56→128 29.2571 + 6.8571    s-9 96→160 72.2286 + 6.0952
     r-1  4→6    3.2571 + 0.1905     r-2 8→12   6.5143 + 0.381
     r-3  14→20  11.7714 + 0.5714    nav-h 60→76 54.0571 + 1.5238
============================================================================ */

/* ===========================================================  fonts  ==== */
/* Geist and Geist Mono are variable — one file each covers 100–900. */
@font-face{font-family:"Archivo Black";font-style:normal;font-weight:400;font-display:swap;src:url(../fonts/archivo-black.woff2) format("woff2")}
@font-face{font-family:"Geist";font-style:normal;font-weight:100 900;font-display:swap;src:url(../fonts/geist-var.woff2) format("woff2")}
@font-face{font-family:"Geist Mono";font-style:normal;font-weight:100 900;font-display:swap;src:url(../fonts/geist-mono-var.woff2) format("woff2")}

:root{
  /* ---- viewport range the fluid tokens are solved for ------------------- */
  --vw-min:390; --vw-max:1440;

  /* ---- Ground: cool stone, not cream ----------------------------------- */
  --paper:#F2F2EE;
  --paper-2:#E8E8E2;
  --paper-3:#DEDED6;    /* one step past paper-2 — for elements that must read against it */
  --surface:#FBFBF9;
  --ink:#121311;
  --ink-2:#4B4C48;
  --ink-3:#666761;      /* 5.09:1 on --paper, 4.64:1 on --paper-2 — AA at the 12-15px this token carries */
  --line:rgba(18,19,17,.12);
  --line-strong:rgba(18,19,17,.32);
  /* absolutes — never remapped by dark surfaces */
  --ink-abs:#121311;
  --paper-abs:#F2F2EE;

  /* ---- Accent scale: green (one job per ground) ------------------------ */
  --accent-200:#C4EDD9;
  --accent-400:#3ED694;
  --accent-500:#25BF7B;
  --accent-700:#0E6B42;

  /* ---- Dark panel ------------------------------------------------------ */
  --panel:#121311;
  --panel-2:#1B1C19;
  --panel-3:#232420;
  --panel-text:#F2F2EE;
  --panel-muted:#A6A79F;
  --panel-line:rgba(242,242,238,.14);
  --panel-line-strong:rgba(242,242,238,.32);

  /* ---- Type families --------------------------------------------------- */
  --f-display:"Archivo Black","Arial Black","Helvetica Neue",sans-serif;
  --f-body:"Geist",-apple-system,BlinkMacSystemFont,"Helvetica Neue",Arial,sans-serif;
  --f-mono:"Geist Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  /* ---- Type scale (fluid 390→1440) ------------------------------------- */
  --t--2:clamp(12px, calc(11.6286px + 0.0952vw), 13px);
  --t--1:clamp(14px, calc(13.6286px + 0.0952vw), 15px);
  --t-0: clamp(16px, calc(15.2571px + 0.1905vw), 18px);
  --t-1: clamp(18px, calc(16.5143px + 0.381vw), 22px);
  --t-2: clamp(20px, calc(17.7714px + 0.5714vw), 26px);
  --t-3: clamp(24px, calc(20.2857px + 0.9524vw), 34px);
  --t-4: clamp(32px, calc(23.0857px + 2.2857vw), 56px);
  --t-5: clamp(44px, calc(24.6857px + 4.9524vw), 96px);
  --t-6: clamp(56px, calc(29.2571px + 6.8571vw), 128px);

  /* ---- Space scale ----------------------------------------------------- */
  --s-1:clamp(4px,  calc(3.2571px + 0.1905vw), 6px);
  --s-2:clamp(8px,  calc(6.5143px + 0.381vw), 12px);
  --s-3:clamp(12px, calc(9.7714px + 0.5714vw), 18px);
  --s-4:clamp(16px, calc(13.0286px + 0.7619vw), 24px);
  --s-5:clamp(24px, calc(19.5429px + 1.1429vw), 36px);
  --s-6:clamp(32px, calc(26.0571px + 1.5238vw), 48px);
  --s-7:clamp(48px, calc(39.0857px + 2.2857vw), 72px);
  --s-8:clamp(64px, calc(49.1429px + 3.8095vw), 104px);
  --s-9:clamp(96px, calc(72.2286px + 6.0952vw), 160px);

  /* ---- Radius ---------------------------------------------------------- */
  --r-0:0px;
  --r-1:clamp(4px,  calc(3.2571px + 0.1905vw), 6px);
  --r-2:clamp(8px,  calc(6.5143px + 0.381vw), 12px);
  --r-3:clamp(14px, calc(11.7714px + 0.5714vw), 20px);

  /* ---- Measure / containers -------------------------------------------- */
  --measure-body:62ch;
  --measure-lede:38ch;
  --measure-h1:11ch;
  --measure-h2:18ch;
  --wrap:1200px;
  --wrap-narrow:760px;
  --gutter:var(--s-5);

  /* ---- Line-height / tracking ------------------------------------------ */
  --lh-display:.95;
  --lh-tight:1.05;
  --lh-snug:1.2;
  --lh-lede:1.35;
  --lh-body:1.55;
  --track-display:-.03em;
  --track-tight:-.015em;
  --track-caps:.14em;

  /* ---- Motion ---------------------------------------------------------- */
  --ease-out:cubic-bezier(.2,.7,.2,1);
  --ease-in-out:cubic-bezier(.6,0,.2,1);
  --dur-1:160ms;
  --dur-2:320ms;
  --dur-3:640ms;

  /* ---- Z --------------------------------------------------------------- */
  --z-below:-1;
  --z-base:1;
  --z-sticky:40;
  --z-nav:50;

  /* ---- Semantic aliases — what page CSS should use ---------------------- */
  --sec-y:var(--s-9);          /* section rhythm            */
  --sec-y-tight:var(--s-8);
  --sec-gap:var(--s-6);        /* head → body               */
  --head-gap:var(--s-7);
  --flow:var(--s-4);           /* paragraph rhythm          */
  --flow-lg:var(--s-5);
  --card-pad:var(--s-5);
  --card-gap:var(--s-4);
  --btn-pad:var(--s-3) var(--s-5);
  --btn-pad-sm:var(--s-2) var(--s-4);
  --grid-gap:var(--s-5);
  --rule:1px;                  /* hairline width            */
  --nav-h:clamp(60px, calc(54.0571px + 1.5238vw), 76px);
  --ticket-w:clamp(280px, 28vw, 380px);
  --deck-peek:clamp(28px, 3.5vw, 64px);   /* how far each dealt card lands right of the last — motion.js §6 computes the same */
  --ph-form-h:clamp(420px, calc(368px + 13.3333vw), 560px);
  --perf:5px;                  /* ticket perforation radius */
}

/* ===========================================================  reset  ==== */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:calc(var(--nav-h) + var(--s-4))}
body{
  margin:0;background:var(--paper);color:var(--ink-2);
  font-family:var(--f-body);font-size:var(--t-0);font-weight:400;line-height:var(--lh-body);
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  font-synthesis-weight:none;
}
img,svg,video,iframe{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
p,figure,dl,dd{margin:0}
button,input,select,textarea{font:inherit;color:inherit}
::selection{background:var(--accent-200);color:var(--ink-abs)}
:focus-visible{outline:2px solid var(--ink);outline-offset:3px}

/* ===========================================================  type  ===== */
h1,h2,h3,h4{
  margin:0;color:var(--ink);font-family:var(--f-display);font-weight:400;
  letter-spacing:var(--track-display);line-height:var(--lh-tight);text-wrap:balance;
}
h1{font-size:var(--t-5);line-height:var(--lh-display)}
h2{font-size:var(--t-4);line-height:1.02}
h3{font-size:var(--t-3);line-height:var(--lh-snug);letter-spacing:var(--track-tight)}
h4{font-size:var(--t-2);line-height:var(--lh-snug);letter-spacing:var(--track-tight)}
.t-display{font-size:var(--t-6);line-height:var(--lh-display)}
.mono{font-family:var(--f-mono);font-variant-numeric:tabular-nums}
.nowrap{white-space:nowrap}
.small{font-size:var(--t--1)}
.caption{font-size:var(--t--2);color:var(--ink-3)}
strong,b{font-weight:600;color:var(--ink)}

.eyebrow{
  display:block;font-family:var(--f-mono);font-size:var(--t--2);font-weight:500;
  letter-spacing:var(--track-caps);text-transform:uppercase;color:var(--ink-3);
  line-height:1.2;font-variant-numeric:tabular-nums;
}
.lede{
  font-size:var(--t-1);line-height:var(--lh-lede);color:var(--ink-2);
  max-width:var(--measure-lede);text-wrap:pretty;
}
.prose{max-width:var(--measure-body);display:grid;gap:var(--flow)}
.center .lede,.center .prose{margin-inline:auto}

/* the ONE accent object on light ground — wash + skewed stroke, drawable */
.hl{position:relative;z-index:0;white-space:nowrap}
/* hand-drawn ellipse ring — motion.js injects <svg class="hl-ring"> (path pathLength=1);
   no-JS gets the same ring as a static background image */
.hl .hl-ring{
  position:absolute;left:-.26em;right:-.44em;top:-.18em;bottom:-.12em;
  width:calc(100% + .7em);height:calc(100% + .3em);
  z-index:var(--z-below);pointer-events:none;overflow:visible;
}
.hl .hl-ring path{fill:none;stroke:var(--accent-500);stroke-width:8;stroke-linecap:round}
html:not(.js) .hl{
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 100' preserveAspectRatio='none'%3E%3Cpath d='M252 9 C150 -4 22 10 14 52 C8 92 152 105 266 93 C372 84 430 44 366 12 C346 3 322 2 300 5' fill='none' stroke='%2325BF7B' stroke-width='7' stroke-linecap='round'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
}

/* =========================================================  layout  ===== */
.wrap{width:min(var(--wrap),calc(100% - var(--gutter) * 2));margin-inline:auto}
.wrap--narrow{width:min(var(--wrap-narrow),calc(100% - var(--gutter) * 2));margin-inline:auto}
.sec{padding-block:var(--sec-y);position:relative}
.sec--alt{background:var(--paper-2)}
.sec--tight{padding-block:var(--sec-y-tight)}
.center{text-align:center}
.rel{position:relative}
.z{position:relative;z-index:var(--z-base)}

/* two-column section head: eyebrow + h2 left, lede right */
.sec__head{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
  grid-template-rows:auto auto;column-gap:var(--s-6);row-gap:0;
  align-items:end;text-align:left;
  margin-bottom:var(--head-gap);
}
/* eyebrow on its own row; headline and lede share a row and meet at the baseline */
.sec__head .eyebrow{grid-column:1 / -1;grid-row:1;margin-bottom:var(--s-4)}
.sec__head h2{grid-column:1;grid-row:2;max-width:var(--measure-h2);align-self:end}
.sec__head .lede{grid-column:2;grid-row:2;align-self:end;max-width:var(--measure-lede);justify-self:start;padding-bottom:.18em}
.sec__head > :only-child{grid-column:1 / -1}
/* loud variant — headline spans the full measure at display scale, lede beneath.
   Use once per page, on the section that carries the idea. */
.sec__head--stack{grid-template-columns:minmax(0,1fr);grid-template-rows:none;row-gap:var(--s-4)}
.sec__head--stack .eyebrow{margin-bottom:0}
.sec__head--stack h2{grid-column:1;grid-row:auto;font-size:var(--t-5);max-width:var(--measure-h1);line-height:var(--lh-display)}
.sec__head--stack .lede{grid-column:1;grid-row:auto;padding-bottom:0}
@media (max-width:768px){
  .sec__head{grid-template-columns:minmax(0,1fr);grid-template-rows:none;row-gap:var(--s-3)}
  .sec__head .eyebrow,.sec__head h2,.sec__head .lede{grid-column:1;grid-row:auto;padding-bottom:0}
  .sec__head .eyebrow{margin-bottom:0}
}

/* ======================================================  dark surfaces == */
/* token remap — every primitive inside inverts for free */
.sec--panel,.panel,.apply-bar{
  --paper:var(--panel);
  --paper-2:var(--panel-3);
  --paper-3:var(--panel-3);
  --surface:var(--panel-2);
  --ink:var(--panel-text);
  --ink-2:var(--panel-muted);
  --ink-3:var(--panel-muted);
  --line:var(--panel-line);
  --line-strong:var(--panel-line-strong);
  background:var(--panel);
  color:var(--panel-muted);
}
.sec--panel .hl .hl-ring path,.panel .hl .hl-ring path{stroke:var(--accent-400)}

/* =========================================================  buttons  ==== */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s-2);
  padding:var(--btn-pad);border:0;border-radius:var(--r-2);cursor:pointer;
  font-family:var(--f-body);font-size:var(--t-0);font-weight:600;line-height:1.1;
  letter-spacing:var(--track-tight);text-align:center;
  transition:background-color var(--dur-1) var(--ease-out),
             color var(--dur-1) var(--ease-out),
             box-shadow var(--dur-1) var(--ease-out),
             transform var(--dur-1) var(--ease-out);
}
.btn--primary{background:var(--ink);color:var(--paper)}
.btn--ghost{background:transparent;color:var(--ink);box-shadow:inset 0 0 0 var(--rule) var(--line-strong)}
.btn--sm{padding:var(--btn-pad-sm);font-size:var(--t--1);border-radius:var(--r-1)}
.btn--block{width:100%}
@media (hover:hover){
  .btn:hover{transform:translateY(-1px)}
  .btn--primary:hover{background:var(--panel-2)}
  .btn--ghost:hover{box-shadow:inset 0 0 0 var(--rule) var(--ink)}
}
/* the ONE accent object on dark ground */
.sec--panel .btn--primary,.panel .btn--primary,.apply-bar .btn--primary{
  background:var(--accent-500);color:var(--ink-abs);
}
@media (hover:hover){
  .sec--panel .btn--primary:hover,.panel .btn--primary:hover,.apply-bar .btn--primary:hover{
    background:var(--accent-400);
  }
}

/* ===========================================================  card  ===== */
.card{
  background:var(--surface);border:var(--rule) solid var(--line);
  border-radius:var(--r-2);padding:var(--card-pad);
  transition:border-color var(--dur-1) var(--ease-out),transform var(--dur-1) var(--ease-out);
}
@media (hover:hover){
  .card:hover{border-color:var(--line-strong);transform:translateY(-1px)}
}

/* =========================================================  lists  ====== */
.list{list-style:none;margin:0;padding:0;display:grid;gap:var(--s-3)}
.list li{display:grid;grid-template-columns:auto minmax(0,1fr);gap:var(--s-3);align-items:start;color:var(--ink-2)}
.list li::before{
  font-family:var(--f-mono);font-size:var(--t--1);line-height:var(--lh-body);font-weight:500;
}
.list--tick li::before{content:"✓";color:var(--ink)}
.list--cross li::before{content:"✕";color:var(--ink-3)}
.list--cross li{color:var(--ink-3)}
.list--plain li{grid-template-columns:minmax(0,1fr)}
.list--plain li::before{content:none}

/* ruled list block (What's inside pillars, comparison rows) */
.ruled{display:grid}
.ruled > * + *{border-top:var(--rule) solid var(--line)}

/* ===========================================================  faq  ====== */
.faq{display:grid;border-top:var(--rule) solid var(--line)}
.faq details{border-bottom:var(--rule) solid var(--line)}
.faq summary{
  cursor:pointer;list-style:none;display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:var(--s-4);align-items:baseline;padding-block:var(--s-4);
  color:var(--ink);font-size:var(--t-1);font-weight:500;line-height:var(--lh-snug);
  text-wrap:balance;
}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{
  content:"+";font-family:var(--f-mono);font-size:var(--t-1);color:var(--ink-3);
  line-height:1;transition:transform var(--dur-2) var(--ease-out);
}
.faq details[open] summary::after{transform:rotate(45deg)}
@media (hover:hover){.faq summary:hover{color:var(--ink)}.faq summary:hover::after{color:var(--ink)}}
/* animated answer wrapper: <div class="faq__body"><p>…</p></div> */
.faq__body{display:grid;grid-template-rows:1fr}
.faq__body > *{overflow:hidden;min-height:0}
.faq__body p{padding-bottom:var(--s-4);color:var(--ink-2);max-width:var(--measure-body)}
/* with JS: details stay open in the DOM, .is-open drives the animation */
.js .faq details .faq__body{
  grid-template-rows:0fr;transition:grid-template-rows var(--dur-2) var(--ease-in-out);
}
.js .faq details.is-open .faq__body{grid-template-rows:1fr}
/* padding must not survive the 0fr row (overflow clips at the padding box) */
.js .faq details .faq__body p{padding-bottom:0}
.js .faq details.is-open .faq__body p{padding-bottom:var(--s-4)}
.js .faq details summary::after{transform:none}
.js .faq details.is-open summary::after{transform:rotate(45deg)}

/* ===========================================================  nav  ====== */
.nav{
  position:sticky;top:0;z-index:var(--z-nav);
  background:var(--paper);
  background:color-mix(in srgb,var(--paper) 85%,transparent);
  -webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4);
  border-bottom:var(--rule) solid var(--line);
}
.nav__inner{display:flex;align-items:center;justify-content:space-between;gap:var(--s-4);height:var(--nav-h)}
/* inline-flex swallows the space between the words visually; it stays in the
   DOM so the link still reads "Sales University" to assistive tech */
.wordmark{
  display:inline-flex;align-items:baseline;font-family:var(--f-display);color:var(--ink);
  font-size:var(--t-1);letter-spacing:-.05em;line-height:1;
}
.wordmark span{position:relative;margin-left:.035em;font-family:var(--f-body);font-weight:900;color:var(--ink-2)}
/* green arc under "University" — geometry measured off the logo reference */
.wordmark span::after{
  content:"";position:absolute;left:10.5%;right:13.7%;top:calc(100% - .075em);height:.25em;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1400 100' preserveAspectRatio='none'%3E%3Cpath d='M17 80Q700 -42 1383 73' fill='none' stroke='%2325BF7B' stroke-width='34' stroke-linecap='round'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
  pointer-events:none;
}

/* =========================================================  footer  ===== */
.footer{
  border-top:var(--rule) solid var(--line);
  padding-block:var(--s-7) var(--s-6);
  font-family:var(--f-mono);font-size:var(--t--2);line-height:1.7;color:var(--ink-3);
}
.footer__row{
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr) minmax(0,1.4fr);
  gap:var(--s-5);align-items:start;
}
.footer__links{display:grid;gap:var(--s-2);align-content:start}
.footer__legal{max-width:var(--measure-body)}
.footer__legal + .footer__legal{margin-top:var(--s-3)}
.footer__quiet{color:var(--ink-3)}
@media (hover:hover){.footer a:hover{color:var(--ink)}}
@media (max-width:768px){.footer__row{grid-template-columns:minmax(0,1fr);gap:var(--s-4)}}

/* =========================================================  ticket  ===== */
/* seat ticket: .ticket > .ticket__media + .ticket__meta + .ticket__stub      */
.ticket{
  display:flex;flex-direction:column;background:var(--surface);
  border:var(--rule) solid var(--line);border-radius:var(--r-2);overflow:hidden;
  transition:border-color var(--dur-1) var(--ease-out),transform var(--dur-1) var(--ease-out);
}
@media (hover:hover){.ticket:hover{border-color:var(--line-strong);transform:translateY(-1px)}}
.ticket__media{position:relative;background:var(--paper-2)}
.ticket__media .ph-img{border:0;border-radius:0}
.ticket__meta{
  display:grid;gap:var(--s-2);padding:var(--card-pad);
  font-family:var(--f-mono);font-size:var(--t--1);font-variant-numeric:tabular-nums;
}
.ticket__meta > div{
  display:grid;grid-template-columns:minmax(0,auto) minmax(0,1fr);gap:var(--s-3);
  align-items:baseline;padding-bottom:var(--s-2);
  border-bottom:var(--rule) solid var(--line);
}
.ticket__meta > div:last-child{border-bottom:0;padding-bottom:0}
.ticket__meta dt{
  font-size:var(--t--2);letter-spacing:var(--track-caps);text-transform:uppercase;color:var(--ink-3);
}
.ticket__meta dd{color:var(--ink);text-align:right;text-wrap:pretty}
/* perforated edge — mask punches dots out of the stub, ticket ground shows through */
.ticket__stub{
  margin-top:auto;background:var(--paper-2);
  padding:var(--s-5) var(--card-pad) var(--card-pad);
  font-family:var(--f-mono);font-size:var(--t--1);color:var(--ink-2);
  -webkit-mask-image:radial-gradient(circle var(--perf) at var(--perf) 0,#0000 99%,#000 100%);
  mask-image:radial-gradient(circle var(--perf) at var(--perf) 0,#0000 99%,#000 100%);
  -webkit-mask-size:calc(var(--perf) * 4) 100%;mask-size:calc(var(--perf) * 4) 100%;
  -webkit-mask-repeat:repeat-x;mask-repeat:repeat-x;
}
.ticket__stub dt,.ticket__stub .eyebrow{color:var(--ink-3)}
/* on the alt ground the stub's paper-2 is the section colour and the tear-off
   vanishes — one step darker keeps it reading as part of the card. The dark
   remap points paper-3 at panel-3, so panel tickets are unaffected. */
.sec--alt .ticket__stub{background:var(--paper-3)}
.ticket__price{
  font-family:var(--f-display);font-variant-numeric:tabular-nums;color:var(--ink);
  font-size:var(--t-4);letter-spacing:var(--track-display);line-height:var(--lh-display);
}
.ticket__price{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--s-2)}
.ticket__per{font-family:var(--f-mono);font-size:var(--t--1);letter-spacing:0;color:var(--ink-3);white-space:nowrap}

/* ==================================================  seat mark / ambient  */
.seat-mark{
  display:inline-block;font-family:var(--f-mono);font-size:var(--t--2);font-weight:400;
  letter-spacing:var(--track-caps);text-transform:uppercase;color:var(--ink-3);line-height:1.2;
}
.ambient{
  position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:0;
  background:radial-gradient(60% 60% at 78% 12%,var(--accent-200) 0%,transparent 70%);
  opacity:.35;
}

/* ====================================================  placeholders  ==== */
.ph{color:var(--ink-3);font-style:italic}
.ph-img,.ph-video,.ph-form{
  display:flex;align-items:center;justify-content:center;text-align:center;
  padding:var(--s-4);width:100%;
  border:var(--rule) dashed var(--line-strong);border-radius:var(--r-2);
  background:var(--paper-2);color:var(--ink-3);
  font-family:var(--f-body);font-size:var(--t--1);font-style:italic;line-height:var(--lh-body);
}
.ph-video{aspect-ratio:16/9}
/* video frame — click-to-play facade; inherits panel tokens on dark surfaces.
   Nothing but a local poster loads until the play button is pressed: the mux
   player is 317KB of JS and preloads video segments on top of it. */
.video{
  position:relative;width:100%;aspect-ratio:16/9;overflow:hidden;
  border:var(--rule) solid var(--line);border-radius:var(--r-2);
  background-color:var(--paper-2);
}
.video__poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* the button is the whole frame — the badge is drawn, not laid out, so the hit
   area never depends on the badge size */
.video__play{
  position:absolute;inset:0;width:100%;height:100%;display:grid;place-items:center;
  margin:0;padding:0;border:0;background:none;cursor:pointer;color:var(--paper-abs);
}
.video__play svg{
  width:var(--s-5);height:var(--s-5);fill:currentColor;
  padding:var(--s-3);box-sizing:content-box;border-radius:50%;   /* 48→72px badge */
  background:var(--accent-500);
}
.video__play:hover svg{background:var(--accent-700)}
.video__play:focus-visible{outline:2px solid var(--ink);outline-offset:-4px}
.video mux-player{
  position:absolute;inset:0;width:100%;height:100%;display:block;
  --media-object-fit:cover;   /* fill the frame whatever the source aspect */
  --media-object-position:center;
}
/* click → the 317KB player script starts downloading; say so, because on a slow
   connection nothing else changes for several seconds */
.video.is-loading .video__play{opacity:.5;cursor:default}
.video.is-loading::after{
  content:"Loading…";position:absolute;inset:auto 0 var(--s-3) 0;text-align:center;
  font-family:var(--f-mono);font-size:var(--t--2);font-style:italic;color:var(--ink-3);
}
.ph-img{aspect-ratio:4/5}
.ph-form{min-height:var(--ph-form-h)}

/* ============================================================  deck  ==== */
/* testimonial deck — 6Four's ResultsStack, vanilla (motion.js §6).
   Every video is 16:9.
   Base (phones, tablets, reduced motion, no JS): a snap-aligned swipe row of
   upright cards — video on top, copy beneath — bleeding to the screen edges.
   Stacked (the @media block, which must match DECK_Q in motion.js): the
   section becomes a runway, its stage sticks for one viewport, and scrolling
   deals the cards in from the right. There the card turns landscape, video
   left and copy right, so it is only as tall as its video. motion.js writes
   transform on .case and opacity on .deck__shade, so neither may carry a
   transition of its own. */
.deck__track{
  display:flex;gap:var(--s-4);list-style:none;
  margin:0 calc(var(--gutter) * -1);padding:0 var(--gutter) var(--s-2);
  overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;
  scroll-snap-type:x mandatory;scroll-padding-inline:var(--gutter);
}
.deck__track::-webkit-scrollbar{display:none}
.case{
  position:relative;display:flex;flex-direction:column;flex:none;
  width:var(--ticket-w);overflow:hidden;scroll-snap-align:start;
  background:var(--surface);border:var(--rule) solid var(--line);border-radius:var(--r-2);
}
.case > .video,.case > .ph-video{flex:none;border:0;border-radius:0}   /* 16:9 comes from .video / .ph-video */
/* quote on top, who at the foot — the quote grows so names line up across cards */
.case__body{
  display:flex;flex-direction:column;flex:1;gap:var(--s-1);
  padding:var(--s-4);overflow-wrap:break-word;
}
.case__quote{
  flex:1 0 auto;margin-bottom:var(--s-4);
  font-family:var(--f-display);font-size:var(--t-0);line-height:var(--lh-snug);
  letter-spacing:var(--track-tight);color:var(--ink);text-wrap:balance;
}
.case h3{font-size:var(--t-2)}
.case__meta{font-size:var(--t--1);color:var(--ink-3)}
.deck__shade{display:none}

@media (min-width:1025px) and (prefers-reduced-motion:no-preference){
  /* the runway: one viewport of pin plus 50vh of scroll per card dealt */
  .js .deck{padding-block:0;height:calc(100vh + var(--deck-steps,0) * 50vh)}
  .js .deck__stage{
    position:sticky;top:0;height:100vh;height:100svh;
    display:flex;flex-direction:column;overflow:hidden;overflow:clip;   /* offstage cards */
    padding-block:calc(var(--nav-h) + var(--s-5)) var(--s-5);
  }
  .js .deck__inner{display:flex;flex-direction:column;justify-content:center;flex:1;min-height:0}
  .js .deck .sec__head{margin-bottom:0}   /* every px the head gives back goes to the cards */
  /* card height is whatever the viewport leaves; width follows from the 16:9
     video plus the copy column. The cap is that sum solved backwards: the
     tallest card whose stack of four (three peeks) still ends inside the wrap.
     On a tall screen the spare height splits above and below (the inner centres). */
  .js .deck__track{
    position:relative;display:block;flex:1 1 auto;min-height:0;
    max-height:calc((min(var(--wrap),100vw - var(--gutter) * 2) - var(--deck-peek) * 3 - var(--ticket-w)) * 9 / 16);
    margin:var(--s-6) 0 0;padding:0;overflow:visible;
  }
  .js .deck .case{
    position:absolute;top:0;bottom:0;left:0;flex-direction:row;width:auto;
    transform-origin:left center;
    box-shadow:calc(var(--s-5) * -1) 0 var(--s-7) calc(var(--s-4) * -1) color-mix(in srgb,var(--ink) 30%,transparent);
  }
  .js .deck .case > .video,.js .deck .case > .ph-video{width:auto;height:100%}
  .js .deck .case__body{flex:none;width:var(--ticket-w);padding:var(--s-6)}
  .js .deck .case__quote{font-size:var(--t-2)}
  .js .deck__shade{display:block;position:absolute;inset:0;z-index:2;background:var(--ink);opacity:0;pointer-events:none}
}

/* ======================================================  apply bar  ===== */
.apply-bar{
  position:fixed;left:0;right:0;bottom:0;z-index:var(--z-sticky);
  padding:var(--s-3) var(--gutter) calc(var(--s-3) + env(safe-area-inset-bottom,0px));
  border-top:var(--rule) solid var(--panel-line);
  transform:translateY(110%);visibility:hidden;
}
.apply-bar.is-in{transform:none;visibility:visible}
@media (min-width:769px){.apply-bar{display:none}}

/* =========================================================  motion  ===== */
@media (prefers-reduced-motion:no-preference){
  .apply-bar{
    transition:transform var(--dur-2) var(--ease-out),visibility 0s linear var(--dur-2);
  }
  .apply-bar.is-in{transition:transform var(--dur-2) var(--ease-out),visibility 0s}

  /* 1. hero line reveal — motion.js wraps words in .w > span and sets --i per line */
  /* vertical-align is load-bearing: an inline-block with overflow!=visible takes
     its bottom margin edge as its baseline, which inflates every line box — the
     h1 measured 385px while the mask was on and snapped back to 334px when
     .is-done reopened it. Aligning to the line-box top keeps the wrapped
     headline the exact height of the unwrapped one. */
  .js [data-reveal-lines] .w{
    display:inline-block;overflow:hidden;vertical-align:top;
    padding-bottom:.1em;margin-bottom:-.1em;
  }
  .js [data-reveal-lines] .w > span{
    display:block;transform:translateY(110%);
    transition:transform var(--dur-3) var(--ease-out);
    transition-delay:calc(var(--i,0) * 80ms);
  }
  .js [data-reveal-lines].is-in .w > span{transform:none}

  /* 1a. the wordmark's green arc draws in left→right on load, on the .hl ring's
     timing — a clip reveal, since the arc is a background image, not a path */
  .wordmark span::after{animation:wordmark-draw 700ms var(--ease-in-out) 300ms both}
  @keyframes wordmark-draw{from{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0)}}
  /* once lines have landed the masks open so the .hl ring can overflow them */
  .js [data-reveal-lines].is-done .w{overflow:visible}

  /* 1b. .hl ring draws on once its reveal container is in (path has pathLength=1) */
  .js [data-reveal-lines] .hl .hl-ring path,
  .js [data-reveal] .hl .hl-ring path{
    stroke-dasharray:1;stroke-dashoffset:1;
    transition:stroke-dashoffset 700ms var(--ease-in-out) 300ms;
  }
  .js [data-reveal].is-in .hl .hl-ring path,
  .js [data-reveal-lines].is-done .hl .hl-ring path{stroke-dashoffset:0}

  /* 2. scroll reveal */
  .js [data-reveal]{
    opacity:0;transform:translateY(12px);
    transition:opacity var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-out);
  }
  .js [data-reveal].is-in{opacity:1;transform:none}
  .js [data-reveal-stagger] > *{
    opacity:0;transform:translateY(12px);
    transition:opacity var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-out);
  }
  .js [data-reveal-stagger].is-in > *{opacity:1;transform:none}
  .js [data-reveal-stagger].is-in > *:nth-child(1){transition-delay:0ms}
  .js [data-reveal-stagger].is-in > *:nth-child(2){transition-delay:60ms}
  .js [data-reveal-stagger].is-in > *:nth-child(3){transition-delay:120ms}
  .js [data-reveal-stagger].is-in > *:nth-child(4){transition-delay:180ms}
  .js [data-reveal-stagger].is-in > *:nth-child(5){transition-delay:240ms}
  .js [data-reveal-stagger].is-in > *:nth-child(6){transition-delay:300ms}
  .js [data-reveal-stagger].is-in > *:nth-child(7){transition-delay:360ms}
  .js [data-reveal-stagger].is-in > *:nth-child(8){transition-delay:420ms}
  .js [data-reveal-stagger].is-in > *:nth-child(9){transition-delay:480ms}
  .js [data-reveal-stagger].is-in > *:nth-child(n+10){transition-delay:540ms}
}
