@font-face{font-family:Inter;src:url(vendor/inter.woff2)format('woff2');font-weight:300 700;font-display:swap}

:root{
  color-scheme:dark;
  --brand:#4f7cff;
  --bg:#08090c; --surface:#0e1015; --surface2:#13161d; --line:#1e222c; --line2:#2a3040;
  --text:#e7e9ee; --muted:#9aa0b0; --dim:#6b7080;
  --sans:Inter,ui-sans-serif,system-ui,-apple-system,'Segoe UI',sans-serif;
  --mono:ui-monospace,'SF Mono',Menlo,Consolas,monospace;
  --r:14px;
  /* One 8px rhythm. Every gap below is a multiple of it. */
  --s1:8px; --s2:16px; --s3:24px; --s4:40px; --s5:64px; --s6:104px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{
  margin:0;background:var(--bg);color:var(--text);font:400 16px/1.6 var(--sans);
  -webkit-font-smoothing:antialiased;overflow-x:hidden;
}
h1,h2,h3{margin:0;font-weight:600;letter-spacing:-.022em;line-height:1.08}
p{margin:0}
a{color:inherit}
:focus-visible{outline:2px solid var(--brand);outline-offset:3px;border-radius:6px}

.wrap{max-width:1240px;margin:0 auto;padding:0 var(--s3)}
.eyebrow{font:500 11px/1 var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--dim)}
.lede{color:var(--muted);font-size:17px;max-width:62ch}
.num{font-variant-numeric:tabular-nums}

/* ---------- top bar ---------- */
.bar{
  position:sticky;top:0;z-index:60;display:flex;align-items:center;gap:var(--s3);
  padding:10px var(--s3);border-bottom:1px solid var(--line);
  background:color-mix(in srgb,var(--bg) 82%,transparent);backdrop-filter:blur(14px) saturate(1.4);
}
.mark{display:flex;align-items:center;gap:9px;font:600 14px var(--sans);letter-spacing:-.01em}
.mark i{width:11px;height:11px;border-radius:3px;background:var(--brand);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--brand) 22%,transparent);display:block}
.bar .grow{flex:1}
.ctl{display:flex;align-items:center;gap:10px}
.ctl>span{font:500 11px var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--dim)}
.sw{display:flex;gap:6px}
.sw button{
  width:26px;height:26px;border-radius:8px;border:1px solid var(--line2);cursor:pointer;
  padding:0;background:var(--c);transition:transform .18s,box-shadow .18s;
}
.sw button:hover{transform:translateY(-2px)}
.sw button[aria-pressed=true]{box-shadow:0 0 0 2px var(--bg),0 0 0 4px var(--c)}
input[type=color]{width:26px;height:26px;padding:0;border:1px solid var(--line2);border-radius:8px;background:none;cursor:pointer}
input[type=color]::-webkit-color-swatch-wrapper{padding:2px}
input[type=color]::-webkit-color-swatch{border:none;border-radius:5px}
input[type=range]{width:104px;accent-color:var(--brand)}
@media(max-width:880px){.bar .hideSm{display:none}}

/* ---------- hero ---------- */
.hero{position:relative;min-height:clamp(520px,84svh,860px);display:flex;align-items:flex-end;
  border-bottom:1px solid var(--line);overflow:hidden}
.hero canvas,.hero video{position:absolute;inset:0;width:100%;height:100%;display:block;object-fit:cover}
/* The plate starts hidden and is cross-faded in by GSAP. Both layers stay mounted so the
   swap is an opacity change, not a teardown — going back to the shader must not cost a
   WebGL context re-create, which is the one expensive thing on this page. */
.hero video{opacity:0}
/* Scrim, not opacity on the canvas: dimming the plate itself also dims its highlights, which
   is the only part carrying the shape. A gradient over the top keeps the field intact. */
.hero .scrim{position:absolute;inset:0;background:
  linear-gradient(to top,var(--bg) 1%,color-mix(in srgb,var(--bg) 78%,transparent) 42%,color-mix(in srgb,var(--bg) 28%,transparent) 80%),
  /* Weighted to the lower left, where the copy sits. A uniform scrim has to be heavy enough
     for the worst spot, which flattens the whole plate; a directional one keeps the top-right
     of the field bright and still clears the text. */
  linear-gradient(105deg,color-mix(in srgb,var(--bg) 88%,transparent) 0%,color-mix(in srgb,var(--bg) 40%,transparent) 46%,transparent 78%)}
.hero .inner{position:relative;padding:var(--s6) 0 var(--s5);width:100%}
.hero h1{font-size:clamp(40px,7.4vw,88px);max-width:16ch;font-weight:600}
.hero h1 em{font-style:normal;color:color-mix(in srgb,var(--brand) 42%,#ffffff);
  text-shadow:0 2px 40px color-mix(in srgb,var(--bg) 70%,transparent)}
.hero .lede{margin-top:var(--s3)}
.stats{display:flex;flex-wrap:wrap;gap:var(--s4);margin-top:var(--s4)}
.stat b{display:block;font:600 clamp(24px,3.4vw,34px)/1 var(--sans);letter-spacing:-.03em}
.stat span{display:block;margin-top:7px;font:500 11px var(--mono);letter-spacing:.14em;
  text-transform:uppercase;color:var(--dim)}

/* ---------- sections ---------- */
section{padding:var(--s6) 0;border-bottom:1px solid var(--line)}
.head{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--s3);margin-bottom:var(--s4);flex-wrap:wrap}
.head h2{font-size:clamp(26px,3.6vw,40px)}
.head p{margin-top:12px}

/* ---------- bento ---------- */
/* Six columns, and every row must sum to exactly six or the grid ends ragged with dead
   space on the right. Spans are assigned so they tile: 4+2, then 2+2+2, then 2+2+2. */
.bento{display:grid;gap:var(--s2);grid-template-columns:repeat(6,1fr)}
.cell{grid-column:span 2}
.cell.wide{grid-column:span 3}
.cell.w4{grid-column:span 4}
.cell.w6{grid-column:span 6}
/* Wider cell, shorter frame. Holding 16:10 on a two-thirds-width card makes a 700px-tall
   image that swamps the row; a wide card wants a cinematic crop, not a taller one. */
.cell.w4 .view{aspect-ratio:2.25/1}
.cell.w6 .view{aspect-ratio:3.4/1}
.cell.wide .view{aspect-ratio:2/1}
@media(max-width:980px){
  .bento{grid-template-columns:repeat(2,1fr)}
  .cell,.cell.wide,.cell.w4,.cell.w6{grid-column:span 1}
  .cell.w4 .view,.cell.w6 .view,.cell.wide .view{aspect-ratio:16/10}
}
@media(max-width:600px){.bento{grid-template-columns:1fr}}

.card{
  position:relative;border:1px solid var(--line);border-radius:var(--r);background:var(--surface);
  overflow:hidden;display:flex;flex-direction:column;
  transition:border-color .25s,background .25s;
}
.card:hover{border-color:var(--line2);background:var(--surface2)}
.card .view{position:relative;aspect-ratio:16/10;background:#06070a;overflow:hidden}
/* Transparency has to be SHOWN, not asserted. A transparent field over a near-black card
   looks exactly like an opaque one; a checker behind it is the only way the difference is
   visible at all. The tint keeps it from reading as a missing image. */
body.alpha .card .view,
body.alpha .hero{
  background:
    linear-gradient(color-mix(in srgb,var(--brand) 10%,transparent),color-mix(in srgb,var(--brand) 10%,transparent)),
    repeating-conic-gradient(#20242e 0 25%, #2b3140 0 50%) 0 0/22px 22px;
}
body.alpha .hero .scrim{opacity:.55}
.card canvas,.card video,.card img{position:absolute;inset:0;width:100%;height:100%;display:block;object-fit:cover}
.card .body{padding:14px 16px 16px;display:flex;flex-direction:column;gap:8px;flex:1}
.card h3{font-size:15.5px;letter-spacing:-.012em}
.card .meta{font:500 11px var(--mono);letter-spacing:.09em;text-transform:uppercase;color:var(--dim)}
.card p{color:var(--muted);font-size:13.5px;line-height:1.5}
.card .foot{margin-top:auto;padding-top:10px;display:flex;align-items:center;gap:10px;
  border-top:1px solid var(--line);justify-content:space-between}
.kb{font:500 12px var(--mono);color:var(--text)}
.kb small{color:var(--dim);font-size:11px}

.tag{display:inline-flex;align-items:center;gap:5px;padding:3px 8px;border-radius:999px;
  font:500 10.5px var(--mono);letter-spacing:.09em;text-transform:uppercase;
  border:1px solid var(--line2);color:var(--muted);background:#0b0d12}
.tag.live{color:var(--brand);border-color:color-mix(in srgb,var(--brand) 45%,var(--line2))}
.tag.dot::before{content:'';width:5px;height:5px;border-radius:50%;background:currentColor}

.btn{
  appearance:none;border:1px solid var(--line2);background:#0b0d12;color:var(--text);
  font:500 12px var(--sans);padding:7px 13px;border-radius:9px;cursor:pointer;
  transition:border-color .2s,background .2s,color .2s;white-space:nowrap;
}
.btn:hover{border-color:var(--brand);color:var(--brand)}
.btn.solid{background:var(--brand);border-color:var(--brand);color:#05070d;font-weight:600}
.btn.solid:hover{filter:brightness(1.12);color:#05070d}
.btn[data-ok=1]{border-color:#3ddc97;color:#3ddc97}

/* ---------- vocabulary ---------- */
.vocab{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
.vrow{display:grid;grid-template-columns:104px 116px 92px 88px 1fr;gap:var(--s2);align-items:center;
  padding:11px 18px;background:var(--surface);transition:background .2s;cursor:pointer}
.vrow:hover{background:var(--surface2)}
.vrow .thumb{position:relative;aspect-ratio:16/9;border-radius:7px;overflow:hidden;
  background:#06070a;border:1px solid var(--line2)}
.vrow .thumb video,.vrow .thumb img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* No plate for this move yet — say so rather than leaving a black rectangle that reads
   as a broken video. */
.vrow .thumb.empty::after{content:'—';position:absolute;inset:0;display:grid;place-items:center;
  color:var(--dim);font:500 12px var(--mono)}
.vrow.flash{background:color-mix(in srgb,var(--brand) 14%,var(--surface))}
.vrow b{font:600 14px var(--mono);letter-spacing:-.01em}
.vrow .topo{font:500 10.5px var(--mono);letter-spacing:.1em;text-transform:uppercase}
.vrow .topo.cycle{color:#7bd88f}
.vrow .topo.pingpong{color:#e0a75e}
.vrow .opt{font:500 12px var(--mono);color:var(--dim)}
.vrow p{color:var(--muted);font-size:13.5px}
@media(max-width:820px){.vrow{grid-template-columns:1fr 1fr;row-gap:6px}.vrow p{grid-column:1/-1}}

/* ---------- weights ---------- */
.weights{display:grid;gap:12px}
.wrow{display:grid;grid-template-columns:190px 1fr 104px;gap:var(--s2);align-items:center}
.wbar{height:9px;border-radius:999px;background:#12151d;overflow:hidden}
.wbar i{display:block;height:100%;border-radius:999px;background:linear-gradient(90deg,
  color-mix(in srgb,var(--brand) 55%,#000),var(--brand));width:0}
.wrow .lbl{font:500 13px var(--sans)}
.wrow .lbl small{display:block;color:var(--dim);font:500 11px var(--mono);margin-top:3px}
.wrow .val{text-align:right;font:600 13px var(--mono)}
.wrow.dead .lbl,.wrow.dead .val{color:var(--dim);text-decoration:line-through}
.wrow.dead .wbar i{background:#3a3f4d}
@media(max-width:700px){.wrow{grid-template-columns:1fr 90px}.wbar{grid-column:1/-1;order:3}}

/* ---------- snippet ---------- */
.snip{border:1px solid var(--line);border-radius:var(--r);background:#06070a;overflow:hidden}
.snip .top{display:flex;align-items:center;justify-content:space-between;gap:var(--s2);
  padding:10px 14px;border-bottom:1px solid var(--line);background:var(--surface)}
.snip pre{margin:0;padding:18px;overflow-x:auto;font:400 12.5px/1.75 var(--mono);color:#c8cedd}
.snip .k{color:var(--brand)}
.snip .s{color:#7bd88f}
.snip .c{color:#5c6272;font-style:italic}

footer{padding:var(--s5) 0 var(--s6);color:var(--dim);font-size:13px}
footer a{color:var(--muted);text-decoration-color:var(--line2);text-underline-offset:3px}
footer a:hover{color:var(--brand)}
.credits{display:grid;gap:6px;margin-top:var(--s2)}

/* Motion is opt-in. Anything GSAP will animate starts hidden ONLY when motion is allowed —
   otherwise a reduced-motion user is left staring at a permanently invisible page. */
@media (prefers-reduced-motion:no-preference){
  /* .js is set by an inline script in <head>. Gating on it means a failed or blocked script
     leaves the content visible instead of hiding it behind a reveal that will never run. */
  html.js .rise{opacity:0;transform:translateY(18px)}
}
