/* gpdo — tokens layer.
   Ports 1:1 to Astro as src/styles/tokens.css, or map into tailwind theme.extend.
   Values marked INHERITED are carried verbatim from the app. Values marked INVENTED
   did not exist in the app and are authored here (see DESIGN-NOTES.md). */
:root{
/* Surface ladder — INHERITED. Depth is expressed by value only, never by shadow. */
--canvas:#000000;--card:#171717;--raised:#262626;--hairline:#404040;--inverted:#fafafa;--water:#0a0a0a;
--card-hover:#1f1f1f;/* INVENTED — one grey-ladder step up, the only hover treatment for cards */
/* Text ramp — INHERITED */
--text-1:#fafafa;--text-2:#a3a3a3;--text-3:#737373;--text-dim:#d4d4d4;--on-light:#000000;
/* Reserved hues — INHERITED. Already spoken for in the product; never reuse for anything else. */
--error:#f87171;--destructive:#ef4444;--spots-fill:#052e16;--spots-label:#4ade80;--receipt:#38bdf8;
/* Pure white — map pin fills and the active tab icon ONLY. Not the same token as --text-1. */
--pin:#ffffff;
/* Accent — INVENTED. Founder call: no yellow/orange anywhere. The accent IS white, so a primary
   button is a white fill on black. Same token still drives the focus ring. */
--accent:#ffffff;
/* Radius — INHERITED. 12px on everything; no radius-scales-with-size rule. */
--r:12px;--r-sm:8px;--r-lg:16px;--r-pill:9999px;
/* Space — INHERITED rhythm 4/8/12/16/24, extended with web-scale section steps */
--s1:4px;--s2:8px;--s3:12px;--s4:16px;--s6:24px;--s8:32px;--s12:48px;--s16:64px;--s24:96px;--s32:128px;
--gutter:24px;--maxw:1180px;
/* Type — REBUILT at web scale. Weights are binary: 700 or 400. 500 appears nowhere. */
--f:'Inter','Inter var',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
--t-display:clamp(38px,6.2vw,64px);--t-h2:clamp(29px,3.4vw,40px);--t-h3:20px;
--t-lead:21px;--t-body:17px;--t-meta:15px;--t-label:12px;
--lh-tight:1.05;--lh-h2:1.1;--lh-h3:1.3;--lh-body:1.6;
--track-label:8px;/* INHERITED — the app's one expressive gesture, amplified */
--track-display:-.02em;
/* Motion — ease-out-cubic, the team's own deliberate curve. No bounce, ever. */
--ease:cubic-bezier(0.215,0.61,0.355,1);--d-sm:200ms;--d-md:300ms;--d-lg:430ms;
/* Reveal curve — expo-out: fast arrival, long soft settle. Still zero overshoot. */
--ease-rv:cubic-bezier(.16,1,.3,1);
}
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{margin:0;background:var(--canvas);color:var(--text-1);font-family:var(--f);font-size:var(--t-body);line-height:var(--lh-body);font-weight:400;-webkit-font-smoothing:antialiased;text-wrap:pretty}
h1,h2,h3,h4,p,ul,ol,figure{margin:0}
ul{padding:0;list-style:none}
img,svg{display:block}
button,input{font:inherit;color:inherit}
/* Focus — INVENTED. The app has no focus concept; WCAG 2.1 AA / EAA requires one. */
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:2px}
/* Links — INVENTED. Underlines on for in-text links, off for nav and buttons. */
a{color:var(--text-1);text-decoration:underline;text-decoration-color:var(--hairline);text-underline-offset:3px;text-decoration-thickness:1px;transition:text-decoration-color var(--d-sm) var(--ease)}
a:hover{text-decoration-color:var(--accent)}
a.plain,a.plain:hover{text-decoration:none}
a.plain{transition:opacity var(--d-sm) var(--ease)}
a.plain:hover{opacity:.7}/* INHERITED — the app's only press feedback is an opacity dip to 0.7 */
.skip{position:absolute;left:var(--s4);top:-100px;z-index:99;background:var(--inverted);color:var(--on-light);font-weight:700;font-size:var(--t-meta);padding:var(--s3) var(--s4);border-radius:var(--r);text-decoration:none}
.skip:focus{top:var(--s4)}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
/* Layout */
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter)}
.sect{padding-block:var(--s24)}
/* Section header — INVENTED, one treatment used on every section: hairline rule,
   then the tracking-8px uppercase label, then the h2. Divider is #171717 on the black canvas. */
.rule{height:1px;background:var(--card);border:0;margin:0}
.lbl{font-size:var(--t-label);font-weight:700;line-height:1;letter-spacing:var(--track-label);text-transform:uppercase;color:var(--text-3);margin-top:var(--s6)}
h2,.h2{font-size:var(--t-h2);line-height:var(--lh-h2);font-weight:700;letter-spacing:var(--track-display);margin-top:var(--s3);max-width:20ch}
h3,.h3{font-size:var(--t-h3);line-height:var(--lh-h3);font-weight:700}
.lead{font-size:var(--t-lead);color:var(--text-2);max-width:52ch;margin-top:var(--s4)}
.meta{font-size:var(--t-meta);color:var(--text-3)}
/* Card — INHERITED. One recipe. #171717, 12px radius, 16px padding, zero elevation. */
.crd{background:var(--card);border-radius:var(--r);padding:var(--s6);transition:background var(--d-sm) var(--ease)}
.crd:hover{background:var(--card-hover)}
.tile{width:40px;height:40px;border-radius:var(--r-sm);background:var(--raised);display:grid;place-items:center;color:var(--text-1)}
/* Buttons */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);border:0;border-radius:var(--r);padding:var(--s4) var(--s6);font-size:var(--t-body);font-weight:700;cursor:pointer;text-decoration:none;transition:opacity var(--d-sm) var(--ease),transform 140ms var(--ease)}
.btn:hover{opacity:.7}
.btn:active{transform:scale(.97)}
.btn-pri{background:var(--accent);color:var(--on-light)}
.btn-sec{background:var(--raised);color:var(--text-1)}
.btn-out{background:transparent;border:1px solid var(--hairline);border-radius:var(--r-sm);padding:var(--s2) var(--s4);color:var(--text-1)}
/* Waitlist form — one field, email only */
.wl{display:flex;flex-wrap:wrap;gap:var(--s2);max-width:480px}
.wl input{flex:1 1 220px;min-width:0;background:var(--card);border:0;border-radius:var(--r);padding:var(--s4);font-size:var(--t-body);color:var(--text-1)}
.wl input::placeholder{color:var(--text-3)}
.wl .btn{flex:0 0 auto}
.wl-note{font-size:var(--t-meta);color:var(--text-3);margin-top:var(--s3);max-width:44ch}
/* Reveals — driven by IntersectionObserver (reveal.js), not a scroll timeline.
   The hidden state is gated on html.js, which the script only adds once it has an observer
   AND motion is allowed — so no-JS, old browsers and reduced-motion all render fully visible.
   Composited properties only. ease-out-cubic, no bounce. --d staggers siblings.
   Three variants: .rv rises, .rv-s rises and scales up (device frames, so a phone reads as
   arriving rather than sliding), and the observer assigns --d down list children itself. */
@keyframes rv{from{opacity:0;transform:translateY(20px)}to{opacity:1;transform:none}}
@keyframes rvs{from{opacity:0;transform:translateY(36px) scale(.96)}to{opacity:1;transform:none}}
html.js .rv{opacity:0;transform:translateY(20px)}
html.js .rv.in{animation:rv 640ms var(--ease-rv) forwards;animation-delay:var(--d,0ms)}
html.js .rv.rv-s{transform:translateY(36px) scale(.96)}
html.js .rv.rv-s.in{animation-name:rvs;animation-duration:920ms}
/* Cross-page transitions — same-origin MPA nav fades/rises where supported, inert elsewhere. */
@view-transition{navigation:auto}
@keyframes vtOut{to{opacity:0}}
@keyframes vtIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
::view-transition-old(root){animation:vtOut 180ms var(--ease) both}
::view-transition-new(root){animation:vtIn 420ms var(--ease-rv) both}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}::view-transition-old(root),::view-transition-new(root){animation:none}}
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:1ms!important;animation-iteration-count:1!important;transition-duration:1ms!important}}
