@font-face{
  font-family:'Black Ops One';font-style:normal;font-weight:400;font-display:swap;
  src:url('/assets/fonts/blackopsone.woff2') format('woff2');
}
@font-face{
  font-family:'Share Tech Mono';font-style:normal;font-weight:400;font-display:swap;
  src:url('/assets/fonts/sharetechmono.woff2') format('woff2');
}
:root{
  --toxic:#39ff14;
  --toxic-dim:#34a51f;
  --amber:#ffb000;
  --danger:#ff2d1a;
  --bg:#020503;
  /* PERVYI SNEG frost HUD */
  --frost:#8fa0c0;        /* labels */
  --frost-dim:#5a6a86;
  --ink:#dfe8f6;          /* primary readout ink */
  --cold:#bcd4ff;         /* cold accent */
  --sodium:#ffb45e;       /* lamp-warm accent */
  --panel:rgba(8,14,26,.55);
  --pline:rgba(143,160,192,.2);
  --mono:'Share Tech Mono', ui-monospace, 'Courier New', monospace;
  --display:'Black Ops One', 'Arial Black', sans-serif;
}
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%;overflow:hidden}
body{
  background:var(--bg);
  color:var(--frost);
  font-family:var(--mono);
  -webkit-font-smoothing:antialiased;
  cursor:crosshair;
}
a{color:var(--sodium);text-decoration:none}
a:hover{color:#fff;text-shadow:0 0 8px rgba(255,180,94,.6)}
button{cursor:crosshair;font-family:var(--mono)}
.hidden{display:none !important}

#game{position:fixed;inset:0;width:100%;height:100%;display:block}

/* ================= HUD (frost-blue over bright snow) ================= */
.z-hud{position:fixed;inset:0;z-index:5;pointer-events:none}
.z-corner{position:fixed;z-index:6}
.z-tl{top:22px;left:24px}
.z-tr{top:22px;right:24px;text-align:right}
.z-bl{bottom:24px;left:24px}
.z-br{bottom:24px;right:24px;text-align:right}
/* glass panels: the map corner stays chrome-free (it is a circle) */
.z-tr,.z-bl,.z-br{
  background:var(--panel);
  border:1px solid var(--pline);
  border-radius:10px;
  padding:10px 14px;
  backdrop-filter:blur(7px);-webkit-backdrop-filter:blur(7px);
  box-shadow:0 4px 18px rgba(4,8,18,.35);
}
.z-label{
  font-size:11px;letter-spacing:.28em;color:var(--frost);
  text-shadow:0 1px 4px rgba(6,10,20,.8);
}
.dim{color:var(--frost-dim)}
.z-clock{
  font-size:clamp(28px,3vw,44px);color:var(--ink);letter-spacing:.08em;
  text-shadow:0 0 14px rgba(188,212,255,.45), 0 1px 4px rgba(6,10,20,.8);
  font-variant-numeric:tabular-nums;
}
.z-clock.z-danger{color:#fff;text-shadow:0 0 16px rgba(255,45,26,.95);animation:zblink 1s steps(1) infinite}
@keyframes zblink{50%{opacity:.55}}
.z-sub{font-size:11px;letter-spacing:.2em;margin-top:4px;color:var(--frost)}

.z-map{
  width:clamp(170px,13vw,250px);height:auto;aspect-ratio:1;
  filter:drop-shadow(0 0 10px rgba(143,160,192,.3));
}
.z-map-n{margin-top:4px}

.z-dose{
  font-size:clamp(20px,2vw,30px);color:var(--ink);letter-spacing:.06em;
  text-shadow:0 0 10px rgba(188,212,255,.35), 0 1px 4px rgba(6,10,20,.8);
  font-variant-numeric:tabular-nums;
}
.z-dose.z-danger{color:#ffd2cc;text-shadow:0 0 14px rgba(255,45,26,.95)}
.z-speed{
  font-size:clamp(22px,2.2vw,34px);color:var(--ink);margin-bottom:8px;
  text-shadow:0 0 10px rgba(255,180,94,.55);
  font-variant-numeric:tabular-nums;
}

/* film-badge dose strip: pale emulsion that fogs dark as dose accumulates */
.z-badge{
  position:relative;overflow:hidden;
  width:clamp(150px,12vw,230px);height:10px;margin-top:6px;
  border:1px solid var(--pline);border-radius:2px;
  background:linear-gradient(90deg,#e8ecf4,#cfd6e2 35%,#bfc8d6 70%,#aab3c2);
}
.z-badge::before{
  content:"";position:absolute;inset:0;
  background:repeating-linear-gradient(90deg, rgba(20,28,44,.28) 0 2px, rgba(0,0,0,0) 2px 14px);
}
.z-badge-film{
  position:absolute;inset:0;background:#170f05;opacity:0;
  transition:opacity .6s linear;
}

.z-bar{
  width:clamp(150px,12vw,230px);height:8px;margin-top:6px;
  border:1px solid var(--pline);border-radius:2px;
  background:rgba(10,16,30,.6);
  box-shadow:0 0 8px rgba(143,160,192,.15);
}
.z-bar-fill{
  height:100%;transform-origin:left center;
  transition:transform .12s linear;
}
.z-health{background:linear-gradient(90deg,#5b8f66,#a9dfb4)}
.z-bar.z-danger{border-color:var(--danger);box-shadow:0 0 12px rgba(255,45,26,.5)}
.z-br .z-bar-fill{transform-origin:right center}

.z-objectives{
  position:fixed;top:128px;right:24px;z-index:6;max-width:330px;
  text-align:left;
  background:var(--panel);border:1px solid var(--pline);border-radius:10px;
  padding:10px 14px;
  backdrop-filter:blur(7px);-webkit-backdrop-filter:blur(7px);
}
.z-objlist{margin-top:8px}
.z-obj{
  display:flex;gap:8px;align-items:baseline;
  font-size:12.5px;letter-spacing:.1em;color:var(--frost);
  margin-bottom:6px;text-shadow:0 1px 3px rgba(6,10,20,.8);
}
.z-obj.active{color:var(--ink)}
.z-obj.done{color:#55617a;text-decoration:line-through}
.z-objmark{color:inherit}
.z-obj.z-checkpop{animation:zcheckpop .3s cubic-bezier(.34,1.56,.64,1)}
.z-obj.z-checkpop .z-objmark{animation:zmarkpop .3s ease-out;color:var(--cold)}
@keyframes zcheckpop{
  0%{transform:translateX(-6px) scale(.92);opacity:.2}
  60%{transform:translateX(1px) scale(1.06);opacity:1}
  100%{transform:none;opacity:1}
}
@keyframes zmarkpop{0%{transform:scale(.4)}55%{transform:scale(1.5)}100%{transform:scale(1)}}

/* ---- interact prompt: world-anchored glass pill + keycap ----
   .z-prompt is the positioning shell (JS drives style.transform when
   anchored); .z-pill is the visible capsule so the scale-in animation
   never fights the placement transform. */
.z-prompt{
  position:fixed;left:50%;bottom:20vh;transform:translateX(-50%);z-index:7;
  pointer-events:none;white-space:nowrap;
}
.z-prompt.z-anchored{left:0;top:0;right:auto;bottom:auto}
.z-pill{
  display:flex;align-items:center;gap:10px;
  padding:8px 18px 8px 10px;border-radius:999px;
  background:rgba(8,14,26,.6);
  border:1px solid rgba(143,160,192,.3);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  box-shadow:0 4px 18px rgba(4,8,18,.5), inset 0 1px 0 rgba(223,232,246,.08);
  color:var(--ink);font-size:13px;letter-spacing:.14em;
  text-shadow:0 1px 5px rgba(6,10,20,.85);
}
.z-prompt.z-in .z-pill{animation:zpillin .15s ease-out both}
@keyframes zpillin{0%{transform:scale(.82);opacity:0}100%{transform:scale(1);opacity:1}}
.z-keycap{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:24px;height:24px;padding:0 7px;border-radius:6px;
  background:linear-gradient(180deg,#3a4a6b,#232f47);
  border:1px solid rgba(223,232,246,.35);
  box-shadow:0 2px 0 rgba(10,18,34,.9), inset 0 1px 0 rgba(255,255,255,.18);
  color:#f2f6ff;font-size:12px;letter-spacing:.06em;
}
.z-parrow{
  display:inline-block;font-size:13px;line-height:1;color:var(--cold);
  text-shadow:0 0 8px rgba(188,212,255,.6);
  transition:transform .1s linear;
}
.z-prompt.z-clamped .z-pill{border-color:rgba(188,212,255,.45)}

/* subtitles + toasts: glass capsules so they read over the brightest snow */
.z-subtitle{
  position:fixed;left:50%;bottom:9vh;transform:translateX(-50%);z-index:7;
  max-width:min(760px,84vw);text-align:center;
  font-size:clamp(13px,1.25vw,17px);letter-spacing:.06em;line-height:1.65;
  color:#e6edf8;background:rgba(8,14,26,.6);
  border:1px solid var(--pline);border-radius:14px;
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  padding:10px 20px;
  text-shadow:0 1px 5px rgba(6,10,20,.85);
}
.z-toast{
  position:fixed;left:50%;top:12vh;transform:translateX(-50%);z-index:7;
  max-width:min(680px,80vw);text-align:center;
  font-size:clamp(12px,1.1vw,15px);letter-spacing:.14em;color:#ffd9a8;
  background:rgba(8,14,26,.6);border:1px solid rgba(255,180,94,.35);
  border-radius:14px;
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  padding:10px 20px;text-shadow:0 0 8px rgba(255,180,94,.45), 0 1px 4px rgba(6,10,20,.85);
}
.z-toast.z-pop{animation:ztoast .35s ease-out}
@keyframes ztoast{0%{transform:translate(-50%,-14px);opacity:0}100%{transform:translate(-50%,0);opacity:1}}
/* ================= reticles =================
   Two marks, one wrapper. The wrapper owns the fade and the shared knobs;
   ui.js only ever flips classes (z-on / z-fp / z-sprint / z-kick / z-lost)
   and writes the third-person anchor's translate. Everything that moves is
   a transform transition — no per-frame styling.

   --zspread is UNITLESS on purpose: the cross multiplies it by 1px, the ring
   folds it into a scale(), so one variable drives both marks.

   Readability rule: every stroke carries a 1 px near-black keyline via a
   zero-blur box-shadow spread. On lit snow the keyline is what you see; in
   an unlit basement the frost ink and the soft cold glow are. Neither
   background can swallow the mark. */
.z-retwrap{
  position:fixed;inset:0;z-index:6;pointer-events:none;
  opacity:0;transition:opacity .3s ease;
  --zgap:5px;    /* clear space from centre to the first pixel of an arm */
  --zlen:7px;    /* arm length */
  --zspread:0;   /* extra opening (unitless): sprint / strike */
  --zink:rgba(238,244,255,.95);
  --zkey:0 0 0 1px rgba(3,7,16,.75), 0 0 7px rgba(150,190,255,.45);
}
.z-retwrap.z-on{opacity:1}
/* sprinting: the cross breathes open and dims — you are not aiming, you are
   running. The strike kick is louder and brighter, and wins (declared last). */
.z-retwrap.z-sprint{--zspread:4;--zink:rgba(238,244,255,.7)}
.z-retwrap.z-kick{--zspread:9;--zink:#ffffff}

/* mode swap: exactly one mark is in the box at a time */
.z-ret-tp{display:none}
.z-retwrap:not(.z-fp) .z-ret-fp{display:none}
.z-retwrap:not(.z-fp) .z-ret-tp{display:block}

/* ---- first person: gap cross + centre dot, pinned to screen centre ---- */
.z-ret-fp{position:absolute;left:50%;top:50%;width:0;height:0}
.z-ret-arm{
  position:absolute;left:0;top:0;display:block;border-radius:1px;
  background:var(--zink);box-shadow:var(--zkey);
  transition:transform .13s cubic-bezier(.2,.85,.3,1),background-color .13s linear;
}
.z-ret-n,.z-ret-s{width:2px;height:var(--zlen);margin-left:-1px}
.z-ret-e,.z-ret-w{width:var(--zlen);height:2px;margin-top:-1px}
.z-ret-n{transform:translateY(calc(-1 * (var(--zgap) + var(--zspread) * 1px + var(--zlen))))}
.z-ret-s{transform:translateY(calc(var(--zgap) + var(--zspread) * 1px))}
.z-ret-w{transform:translateX(calc(-1 * (var(--zgap) + var(--zspread) * 1px + var(--zlen))))}
.z-ret-e{transform:translateX(calc(var(--zgap) + var(--zspread) * 1px))}
.z-ret-dot{
  position:absolute;left:0;top:0;width:2px;height:2px;margin:-1px 0 0 -1px;
  border-radius:50%;background:var(--zink);box-shadow:var(--zkey);
}

/* ---- third person: a ring/core pair with bracket ticks, parked on the
   point a punch or kick actually lands. Deliberately NOT a gun sight and
   deliberately NOT at screen centre — attacks fire along the body facing,
   which the camera does not follow. ui.js writes the translate. ---- */
.z-ret-tp{
  position:absolute;left:0;top:0;width:0;height:0;
  transform:translate(50vw,50vh);       /* until the first frame anchors it */
  transition:opacity .25s ease;
}
.z-retwrap.z-lost .z-ret-tp{opacity:0} /* strike point behind the camera */
.z-ret-ring{
  position:absolute;left:0;top:0;width:16px;height:16px;margin:-8px 0 0 -8px;
  border-radius:50%;border:1.5px solid var(--zink);opacity:.8;
  box-shadow:0 0 0 1px rgba(3,7,16,.6), inset 0 0 0 1px rgba(3,7,16,.5),
             0 0 10px rgba(150,190,255,.3);
  transform:scale(calc(1 + var(--zspread) * 0.055));
  transition:transform .13s cubic-bezier(.2,.85,.3,1),
             border-color .13s linear,opacity .13s linear;
}
.z-retwrap.z-kick .z-ret-ring{opacity:1}
.z-ret-core{
  position:absolute;left:0;top:0;width:3px;height:3px;margin:-1.5px 0 0 -1.5px;
  border-radius:50%;background:var(--zink);
  box-shadow:0 0 0 1px rgba(3,7,16,.75), 0 0 8px rgba(150,190,255,.5);
}
.z-ret-tp::before,.z-ret-tp::after{
  content:"";position:absolute;top:-1px;width:5px;height:2px;border-radius:1px;
  background:var(--zink);box-shadow:var(--zkey);opacity:.5;
  transition:transform .13s cubic-bezier(.2,.85,.3,1);
}
.z-ret-tp::before{left:0;transform:translateX(calc(-14px - var(--zspread) * 1px))}
.z-ret-tp::after{left:0;transform:translateX(calc(9px + var(--zspread) * 1px))}

/* ================= screens — "Night Over Pripyat" identity =================
   Boot/brief sit on the landing page's opaque night gradient with a CSS-only
   snowfall; pause and endings are frost-glass sheets over the live frame.
   The old toxic green survives only as the single .z-dot status dot. */
.z-screens{position:fixed;inset:0;z-index:20;pointer-events:none}
.z-screen{
  position:fixed;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:flex-start;text-align:center;
  padding:24px 16px;pointer-events:auto;overflow-y:auto;
  color:var(--frost);
}
/* safe vertical centering: auto margins center the content group when it
   fits, and never clip the top when the screen has to scroll */
.z-screen > :first-child{margin-top:auto}
.z-screen > :last-child{margin-bottom:auto}
.z-boot,.z-brief{
  background:
    radial-gradient(620px 620px at 82% 16%, rgba(205,220,255,.14), transparent 62%),
    linear-gradient(180deg,#04060d 0%,#0a1224 55%,#131c33 85%,#1a2440 100%);
}
/* CSS-only snowfall: two repeating dot sheets drifting straight down
   (vertical travel = one tile height, so the loop is seamless) */
.z-boot::before,.z-boot::after{
  content:"";position:fixed;inset:0;pointer-events:none;
}
.z-boot::before{
  background-image:
    radial-gradient(1.6px 1.6px at 22% 14%, rgba(223,232,246,.7), transparent 60%),
    radial-gradient(1.4px 1.4px at 64% 42%, rgba(223,232,246,.55), transparent 60%),
    radial-gradient(1.8px 1.8px at 41% 73%, rgba(223,232,246,.6), transparent 60%),
    radial-gradient(1.3px 1.3px at 86% 87%, rgba(223,232,246,.45), transparent 60%);
  background-size:290px 290px;
  animation:zsnowA 18s linear infinite;
}
.z-boot::after{
  background-image:
    radial-gradient(1.1px 1.1px at 12% 32%, rgba(188,212,255,.4), transparent 60%),
    radial-gradient(1px 1px at 55% 8%, rgba(188,212,255,.35), transparent 60%),
    radial-gradient(1.2px 1.2px at 78% 61%, rgba(188,212,255,.4), transparent 60%),
    radial-gradient(1px 1px at 33% 90%, rgba(188,212,255,.3), transparent 60%);
  background-size:430px 430px;
  animation:zsnowB 31s linear infinite;
}
@keyframes zsnowA{to{background-position:0 290px}}
@keyframes zsnowB{to{background-position:0 430px}}
.z-bootcol{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center}

.z-mark{
  font-size:30px;line-height:1;color:var(--frost);opacity:.7;
  margin-bottom:14px;user-select:none;-webkit-user-select:none;
}
.z-kicker{
  font-size:12px;letter-spacing:.35em;color:var(--frost);text-transform:uppercase;
}
.z-kicker-sm{font-size:10px;letter-spacing:.3em;color:var(--frost-dim)}
.z-title{
  margin-top:14px;font-family:var(--display);font-weight:normal;
  font-size:clamp(40px,7vw,92px);color:var(--ink);letter-spacing:.02em;
  text-shadow:0 0 40px rgba(120,150,220,.25);
}
.z-premise{
  margin-top:14px;max-width:min(560px,86vw);
  font-size:clamp(13px,1.2vw,15px);line-height:1.7;letter-spacing:.04em;
  color:#aab6cf;
}

/* load progress: thin sodium rule + mono status */
.z-loadwrap{margin-top:30px;width:min(420px,80vw)}
.z-loadrule{
  height:2px;border-radius:1px;overflow:hidden;
  background:rgba(143,160,192,.18);
}
.z-loadfill{
  height:100%;transform-origin:left center;transform:scaleX(0);
  background:linear-gradient(90deg,var(--sodium),#ffc178);
  box-shadow:0 0 8px rgba(255,180,94,.7);
  transition:transform .25s ease;
}
.z-loadrow{margin-top:10px;display:flex;align-items:center;justify-content:center;gap:8px}
.z-load{
  font-size:11px;letter-spacing:.3em;color:var(--frost);
  font-variant-numeric:tabular-nums;
}
/* the one green survivor: a tiny pulsing reactor status dot */
.z-dot{
  width:6px;height:6px;border-radius:50%;flex:none;
  background:#39ff14;box-shadow:0 0 6px rgba(57,255,20,.8);
  animation:zdot 2.4s ease-in-out infinite;
}
@keyframes zdot{0%,100%{opacity:1}50%{opacity:.35}}

/* sodium CTA — same family as the landing .btn-zone */
.z-cta{
  margin-top:30px;display:inline-flex;align-items:center;justify-content:center;
  font-family:var(--display);font-weight:normal;
  font-size:clamp(15px,2vw,20px);letter-spacing:.12em;
  color:#04060d;background:linear-gradient(180deg,#ffc178,#e8963c);
  border:0;border-radius:4px;padding:14px 42px;min-height:48px;
  box-shadow:0 0 24px rgba(255,180,92,.28), 0 2px 10px rgba(0,0,0,.4);
  transition:box-shadow .25s ease,transform .12s ease;
}
.z-cta:hover:not(:disabled){box-shadow:0 0 42px rgba(255,180,92,.5), 0 2px 12px rgba(0,0,0,.5)}
.z-cta:active:not(:disabled){transform:scale(.97)}
.z-cta:focus-visible{outline:2px solid var(--cold);outline-offset:3px}
.z-cta:disabled{opacity:.45;filter:saturate(.4);cursor:progress}
.z-cta-sm{font-size:clamp(14px,1.6vw,17px);padding:11px 34px;min-height:44px}
.z-ghost{
  margin-top:14px;display:inline-flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:12px;letter-spacing:.2em;
  color:var(--frost);background:transparent;
  border:1px solid var(--pline);border-radius:4px;padding:10px 22px;
  transition:color .2s,border-color .2s;
}
.z-ghost:hover{color:var(--ink);border-color:rgba(188,212,255,.45)}
.z-ghost:focus-visible{outline:2px solid var(--cold);outline-offset:3px}

/* glass cards (controls / objectives / settings) */
.z-card{
  margin-top:24px;width:min(460px,88vw);text-align:left;
  background:var(--panel);border:1px solid var(--pline);border-radius:10px;
  padding:14px 18px;
  backdrop-filter:blur(7px);-webkit-backdrop-filter:blur(7px);
}
.z-ctrlgrid{
  margin-top:10px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:6px 24px;
}
.z-ctrl{
  display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  font-size:11px;letter-spacing:.12em;
}
.z-ctrlkey{color:var(--ink);flex:none}
.z-ctrlact{color:var(--frost)}
.z-ctrlline{margin-top:8px;font-size:10px;letter-spacing:.18em;line-height:1.8;color:var(--frost)}

.z-fine{
  margin-top:22px;font-size:11px;letter-spacing:.2em;color:var(--frost-dim);
  max-width:80vw;line-height:2;
}
.z-link{pointer-events:auto;font-size:11px;letter-spacing:.2em;color:var(--sodium)}
.z-link:hover{color:var(--ink);text-shadow:none}

/* ---- pause: frost glass sheet over the live frame ---- */
.z-pause{
  background:rgba(4,6,13,.55);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
}
.z-psheet{display:flex;flex-direction:column;align-items:center;width:min(940px,96vw)}
.z-h2{
  margin-top:10px;font-family:var(--display);font-weight:normal;color:var(--ink);
  font-size:clamp(26px,4vw,44px);letter-spacing:.06em;
  text-shadow:0 0 30px rgba(120,150,220,.3);
}
.z-pcols{
  margin-top:8px;display:flex;gap:28px;align-items:flex-start;justify-content:center;
  flex-wrap:wrap;
}
.z-pcol{display:flex;flex-direction:column;align-items:center;width:min(440px,92vw)}
.z-setcard{width:100%}
.z-row{
  margin-top:12px;display:flex;gap:12px;align-items:center;flex-wrap:wrap;
}
.z-row:first-child{margin-top:0}
.z-rowlabel{font-size:11px;letter-spacing:.3em;color:var(--frost-dim);min-width:96px;text-align:right}
.z-rowopts{display:flex;gap:8px;flex-wrap:wrap}
.z-rownote{
  margin:6px 0 0 108px;font-size:9px;letter-spacing:.24em;color:var(--frost-dim);
}
.z-opt{
  background:transparent;border:1px solid rgba(143,160,192,.35);border-radius:4px;
  color:var(--frost);font-size:12px;letter-spacing:.18em;padding:7px 14px;
  transition:all .15s;
}
.z-opt:hover{border-color:rgba(188,212,255,.6);color:var(--ink);box-shadow:0 0 10px rgba(188,212,255,.2)}
.z-opt:focus-visible{outline:2px solid var(--cold);outline-offset:2px}
.z-opt.on{
  background:rgba(255,180,94,.14);border-color:rgba(255,180,94,.65);color:#ffd9a8;
  box-shadow:0 0 12px rgba(255,180,94,.3);
}
/* a button riding at the end of a slider row (the SOUND row's mute toggle) */
.z-opt-tail{flex:none}

/* ---- range sliders (mouse speed / master volume) ----
   A native <input type=range> repainted in the frost identity: pointer,
   touch, and arrow-key/Home/End handling come for free, and the pause
   screen is the one place the pointer is guaranteed unlocked. The filled
   part of the WebKit track is a gradient stop at --zfill, which ui.js sets
   through CSSOM (the CSP forbids inline style attributes). Gecko has a real
   ::-moz-range-progress and needs no variable. */
.z-srow{gap:10px}
.z-slider{
  -webkit-appearance:none;appearance:none;
  flex:1 1 140px;min-width:100px;max-width:220px;
  height:22px;margin:0;background:transparent;
  cursor:crosshair;touch-action:none;
}
.z-slider:focus{outline:none}
.z-slider:focus-visible{outline:2px solid var(--cold);outline-offset:4px;border-radius:4px}
.z-slider::-webkit-slider-runnable-track{
  height:4px;border-radius:2px;border:1px solid rgba(143,160,192,.35);
  background:linear-gradient(90deg,
    rgba(255,180,94,.7) 0, rgba(255,180,94,.7) var(--zfill,50%),
    rgba(143,160,192,.16) var(--zfill,50%), rgba(143,160,192,.16) 100%);
}
.z-slider::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:14px;height:14px;margin-top:-6px;border-radius:50%;
  background:linear-gradient(180deg,#ffc178,#e8963c);
  border:1px solid rgba(8,14,26,.8);
  box-shadow:0 0 10px rgba(255,180,92,.45), 0 1px 4px rgba(0,0,0,.5);
  transition:box-shadow .15s ease,transform .1s ease;
}
.z-slider:hover::-webkit-slider-thumb{box-shadow:0 0 18px rgba(255,180,92,.7), 0 1px 4px rgba(0,0,0,.5)}
.z-slider:active::-webkit-slider-thumb{transform:scale(1.14)}
.z-slider::-moz-range-track{
  height:4px;border-radius:2px;border:1px solid rgba(143,160,192,.35);
  background:rgba(143,160,192,.16);
}
.z-slider::-moz-range-progress{height:4px;border-radius:2px;background:rgba(255,180,94,.7)}
.z-slider::-moz-range-thumb{
  width:14px;height:14px;border-radius:50%;
  background:linear-gradient(180deg,#ffc178,#e8963c);
  border:1px solid rgba(8,14,26,.8);
  box-shadow:0 0 10px rgba(255,180,92,.45);
}
.z-slidval{
  flex:none;min-width:54px;text-align:right;
  font-size:12px;letter-spacing:.08em;color:var(--ink);
  font-variant-numeric:tabular-nums;
}

/* quality hint: the height is RESERVED (3 lines) so hovering a tier previews
   its description without reflowing the sheet under the cursor */
.z-hint{
  margin:8px 0 0 108px;min-height:50px;
  font-size:10px;letter-spacing:.08em;line-height:1.6;
  color:var(--cold);opacity:.72;
}
.z-pfoot{
  margin-top:26px;display:flex;gap:22px;align-items:baseline;
  font-size:12px;letter-spacing:.24em;color:var(--frost-dim);
  font-variant-numeric:tabular-nums;
}

/* ---- brief ---- */
.z-briefcard{width:min(680px,90vw);padding:22px 26px}
.z-brief .z-brieftext{
  margin-top:14px;text-align:left;
  font-size:clamp(13px,1.3vw,16px);line-height:1.8;letter-spacing:.04em;
  color:var(--ink);white-space:pre-line;min-height:11em;
}

/* ---- ending cards: dossier-style glass sheet ---- */
.z-end{
  background:rgba(4,6,13,.72);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
}
.z-endcard{
  width:min(560px,92vw);
  background:rgba(8,14,26,.6);
  border:1px solid var(--pline);border-top:2px solid var(--cold);
  border-radius:6px;padding:36px 34px 32px;
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
}
.z-endcard.z-end-sodium{border-top-color:var(--sodium)}
.z-endcard.z-end-red{border-top-color:var(--danger)}
.z-verdict{
  margin-top:14px;font-family:var(--display);font-weight:normal;
  font-size:clamp(38px,6vw,68px);line-height:1.05;letter-spacing:.03em;
  font-variant-numeric:tabular-nums;
}
.z-v-cold{color:var(--ink);text-shadow:0 0 26px rgba(188,212,255,.45)}
.z-v-sodium{color:var(--sodium);text-shadow:0 0 26px rgba(255,180,94,.5)}
.z-v-red{color:#ff5a48;text-shadow:0 0 26px rgba(255,45,26,.55)}
.z-endtext{
  margin-top:16px;
  font-size:clamp(13px,1.25vw,15px);line-height:1.8;letter-spacing:.04em;
  color:#aab6cf;
}
.z-end.z-bad .z-endtext{color:#c4b4b8}
.z-stats{margin-top:22px;width:100%;text-align:left}
.z-statrow{
  display:flex;align-items:baseline;justify-content:space-between;gap:24px;
  padding:10px 2px;border-bottom:1px dashed rgba(143,160,192,.16);
  font-size:11px;letter-spacing:.3em;color:var(--frost);
}
.z-statrow:last-child{border-bottom:0}
.z-statrow b{
  font-weight:normal;font-size:14px;letter-spacing:.1em;color:var(--ink);
  font-variant-numeric:tabular-nums;
}
.z-endlink{display:inline-block;margin-top:20px}

/* ambient motion off */
@media (prefers-reduced-motion: reduce){
  .z-boot::before,.z-boot::after{animation:none}
  .z-dot{animation:none}
  .z-loadfill{transition:none}
  .z-cta,.z-ghost,.z-opt{transition:none}
  /* reticles: the marks still swap and still spread (that is information),
     they just arrive instantly instead of easing */
  .z-retwrap,.z-ret-arm,.z-ret-ring,.z-ret-tp,
  .z-ret-tp::before,.z-ret-tp::after,
  .z-slider::-webkit-slider-thumb{transition:none}
}

/* ================= touch controls ================= */
.z-touch{position:absolute;inset:0;z-index:6;pointer-events:none}
.z-look{
  position:absolute;inset:0;pointer-events:auto;touch-action:none;
  -webkit-tap-highlight-color:transparent;
}
.z-stick{
  position:absolute;z-index:2;pointer-events:auto;touch-action:none;
  left:max(28px, env(safe-area-inset-left));
  bottom:max(72px, env(safe-area-inset-bottom));
  width:134px;height:134px;border-radius:50%;
  border:1px solid rgba(143,160,192,.45);
  background:rgba(8,14,26,.4);
  box-shadow:0 0 14px rgba(143,160,192,.15);
  -webkit-tap-highlight-color:transparent;
}
.z-stick-nub{
  position:absolute;left:50%;top:50%;width:54px;height:54px;
  margin:-27px 0 0 -27px;border-radius:50%;
  background:rgba(188,212,255,.22);border:1px solid var(--cold);
  pointer-events:none;
}
.z-tbtns{
  position:absolute;z-index:2;pointer-events:none;
  right:max(18px, env(safe-area-inset-right));
  bottom:max(18px, env(safe-area-inset-bottom));
  width:196px;height:206px;
}
/* only the buttons take taps — the container box must not swallow look-drags
   (pointer-events inherits, so the buttons opt back in explicitly) */
.z-tbtns .z-tbtn{pointer-events:auto}
.z-tbtns .z-tbtn{position:absolute}
.z-tbtns .z-tb-jump{right:0;bottom:0;width:80px;height:80px;font-size:12px}
.z-tbtns .z-tb-punch{right:88px;bottom:20px;width:66px;height:66px}
.z-tbtns .z-tb-crouch{right:4px;bottom:92px;width:62px;height:62px}
.z-tbtns .z-tb-kick{right:96px;bottom:96px;width:54px;height:54px}
.z-tbtns .z-tb-torch{right:44px;bottom:158px;width:46px;height:46px;font-size:9px}
.z-tbtn{
  width:72px;height:72px;border-radius:50%;touch-action:none;
  border:1px solid var(--pline);background:var(--panel);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  color:var(--ink);font-family:var(--mono);font-size:11px;letter-spacing:.08em;
  -webkit-tap-highlight-color:transparent;
  text-shadow:0 1px 4px rgba(6,10,20,.8);
}
.z-tbtn:active,.z-tbtn.on{
  background:rgba(188,212,255,.22);border-color:var(--cold);color:#fff;
}
.z-tbtn-sm{width:58px;height:58px;font-size:10px}
/* the tap target for interactions: visually the same glass pill family */
.z-tinteract{
  position:absolute;z-index:2;pointer-events:auto;
  right:max(120px, calc(env(safe-area-inset-right) + 116px));
  bottom:max(170px, calc(env(safe-area-inset-bottom) + 156px));
  width:92px;height:92px;font-size:14px;
  background:rgba(8,14,26,.6);
  color:#ffd9a8;border-color:rgba(255,180,94,.55);
  box-shadow:0 4px 18px rgba(4,8,18,.5), 0 0 18px rgba(255,180,94,.3),
    inset 0 1px 0 rgba(223,232,246,.08);
}
.z-tpause{
  position:absolute;z-index:2;pointer-events:auto;touch-action:none;
  top:max(12px, env(safe-area-inset-top));left:50%;transform:translateX(-50%);
  width:56px;height:38px;border:1px solid var(--pline);border-radius:8px;
  background:var(--panel);color:var(--frost);font-size:12px;
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  -webkit-tap-highlight-color:transparent;
}
/* camera-mode toggle: rides the top bar next to PAUSE, well clear of the
   move stick (bottom-left) and of the action thumb-arc (bottom-right) */
.z-tview{
  position:absolute;z-index:2;pointer-events:auto;touch-action:none;
  top:max(12px, env(safe-area-inset-top));left:50%;
  transform:translateX(calc(-50% + 62px));
  width:54px;height:38px;border:1px solid var(--pline);border-radius:8px;
  background:var(--panel);color:var(--frost);
  font-family:var(--mono);font-size:11px;letter-spacing:.06em;
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  -webkit-tap-highlight-color:transparent;
}
.z-tview:active{background:rgba(188,212,255,.22);border-color:var(--cold);color:#fff}
/* ---- compact touch HUD: everything shrinks and clears the thumb zones ---- */
body.touch .z-tr,body.touch .z-bl,body.touch .z-br,body.touch .z-objectives{
  padding:6px 9px;border-radius:8px;
}
body.touch .z-tl{top:max(10px, env(safe-area-inset-top));left:max(10px, env(safe-area-inset-left))}
body.touch .z-map{width:106px}
body.touch .z-map-n{display:none}
body.touch .z-tr{top:max(10px, env(safe-area-inset-top));right:max(12px, env(safe-area-inset-right))}
body.touch .z-tr .z-label{font-size:9px;letter-spacing:.2em}
body.touch .z-clock{font-size:20px}
body.touch .z-tr .z-sub{font-size:9px;margin-top:2px}
body.touch .z-objectives{top:70px;right:max(12px, env(safe-area-inset-right));max-width:46vw}
body.touch .z-obj{font-size:10px;margin-bottom:4px;letter-spacing:.06em}
body.touch .z-bl{left:max(20px, env(safe-area-inset-left));bottom:224px}
body.touch .z-bl .z-label{font-size:9px}
body.touch .z-dose{font-size:16px}
body.touch .z-bl .z-sub{font-size:9px}
body.touch .z-br{right:max(18px, env(safe-area-inset-right));bottom:238px}
body.touch .z-br .z-label{font-size:9px}
body.touch .z-speed{font-size:20px;margin-bottom:4px}
body.touch .z-bar{width:118px;height:6px;margin-top:4px}
/* :not() keeps this from outranking .z-prompt.z-anchored — without it the
   anchored shell keeps bottom:32vh, stretches from top:0 to it, and the
   pill's -130% self-translate hurls it off the top of the screen */
body.touch .z-prompt:not(.z-anchored){bottom:32vh}
body.touch .z-pill{font-size:11px;padding:6px 13px 6px 8px;gap:8px}
body.touch .z-keycap{min-width:20px;height:20px;font-size:10px}
body.touch .z-bl .z-badge,body.touch .z-bl .z-bar{width:118px}
body.touch .z-badge{height:7px;margin-top:4px}
body.touch .z-subtitle{bottom:236px;font-size:11px;max-width:70vw;padding:8px 12px}
body.touch .z-toast{top:52px;font-size:10px;max-width:74vw;padding:7px 12px}
body.touch .z-tinteract{
  right:auto;left:50%;transform:translateX(-50%);
  bottom:max(30px, env(safe-area-inset-bottom));
  width:84px;height:84px;font-size:13px;
}
/* ---- compact touch screens: boot / pause / endings fit a phone in landscape ---- */
body.touch .z-screen{padding:14px 12px}
body.touch .z-mark{font-size:22px;margin-bottom:8px}
body.touch .z-title{font-size:clamp(28px,7vw,44px);margin-top:8px}
body.touch .z-premise{margin-top:8px;font-size:12px;line-height:1.55}
body.touch .z-loadwrap{margin-top:16px}
body.touch .z-cta{margin-top:18px;padding:11px 28px;min-height:44px;font-size:15px}
body.touch .z-card{margin-top:14px;padding:10px 14px;width:min(420px,92vw)}
body.touch .z-fine{margin-top:10px;line-height:1.7}
body.touch .z-pcols{gap:12px;margin-top:4px}
/* fat-finger floor: every pause/menu control clears 40px on touch */
body.touch .z-opt{min-height:40px;padding:9px 16px}
/* sliders: a taller hit strip (the thumb is the same 14px, the invisible
   track box around it is what the thumb has to be grabbed inside) */
body.touch .z-slider{height:34px;flex:1 1 120px;min-width:92px}
body.touch .z-slider::-webkit-slider-thumb{width:18px;height:18px;margin-top:-8px}
body.touch .z-slider::-moz-range-thumb{width:18px;height:18px}
body.touch .z-slidval{min-width:46px;font-size:11px}
/* no hover on touch: the hint simply describes the SELECTED tier, so it
   does not need three reserved lines held open for a preview */
body.touch .z-hint{margin-left:0;min-height:0;font-size:9px;letter-spacing:.07em}
body.touch .z-ghost{min-height:40px}
body.touch .z-h2{margin-top:4px}
body.touch .z-pfoot{margin-top:12px}
body.touch .z-endcard{padding:20px 18px 18px;width:min(480px,94vw)}
body.touch .z-verdict{font-size:clamp(28px,6vw,40px);margin-top:8px}
body.touch .z-endtext{margin-top:10px;font-size:12px;line-height:1.6}
body.touch .z-statrow{padding:7px 2px}

/* ---- landscape phone (short viewport): repack the panels around the thumb
   zones. Portrait-tuned anchors (dosimeter bottom:224, objectives top:70 +
   the 820px block's bottom:120px) stretch or collide on a 375px-tall screen:
   the objectives panel lands on the TORCH/KICK/CROUCH arc and the dosimeter
   covers the minimap. Left column: map → dosimeter → stick; objectives sit
   between the map and the pause button along the top. ---- */
@media (orientation: landscape) and (max-height: 480px){
  body.touch .z-stick{bottom:max(16px, env(safe-area-inset-bottom))}
  body.touch .z-objectives{
    top:10px;bottom:auto;right:auto;
    left:158px;max-width:212px;
  }
  body.touch .z-bl{top:128px;bottom:auto;left:max(10px, env(safe-area-inset-left))}
  body.touch .z-subtitle{bottom:160px;max-width:54vw}
  body.touch .z-tpause{top:max(16px, env(safe-area-inset-top))}
  body.touch .z-tview{top:max(16px, env(safe-area-inset-top))}
  /* pause sheet: two columns fit side by side on a short viewport, halving
     the internal scroll distance */
  body.touch .z-pcol{width:min(380px,46vw)}
  /* 812x375 budget: at 46vw the settings card is ~345 px of usable width and
     the SOUND row now carries label + slider + readout + MUTE. Shrink the
     label gutter and the row rhythm so nothing wraps into the next row; the
     sheet keeps .z-screen's own overflow-y:auto for whatever still spills. */
  body.touch .z-row{margin-top:9px;gap:8px}
  body.touch .z-rowlabel{min-width:62px;font-size:10px;letter-spacing:.16em}
  body.touch .z-rownote{margin:5px 0 0 70px;font-size:8px;letter-spacing:.16em}
  body.touch .z-hint{margin-top:6px;font-size:9px;line-height:1.5}
  body.touch .z-slider{flex:1 1 96px;min-width:82px;height:30px}
  body.touch .z-slidval{min-width:40px;font-size:10px}
  body.touch .z-opt{min-height:36px;padding:7px 12px;font-size:11px}
  body.touch .z-opt-tail{padding:7px 9px;letter-spacing:.12em}
  /* width:100% is load-bearing, not tidying. The generic touch rule pins
     every card to min(420px, 92vw) = 420 px here, but this block narrows the
     pause COLUMN to min(380px, 46vw) = 373 px — so without this the settings
     card overhangs its column by ~46 px, sits at x=-4 and runs its quality
     hint under the objectives panel. Following the column makes the usable
     width 373 - 22 = ~351 px, which is what the row rhythm above is sized
     for. (The overhang predates the slider/hint rows; they only made it
     visible, because short option buttons never reached the card edge.) */
  body.touch .z-card{margin-top:10px;padding:9px 11px;width:100%}
  /* ending card: compact vertically so card + TRY AGAIN + link fit ~375px */
  body.touch .z-endcard{padding:12px 16px 12px}
  body.touch .z-verdict{font-size:24px;margin-top:4px}
  body.touch .z-endtext{margin-top:6px;font-size:11px;line-height:1.5}
  body.touch .z-stats{margin-top:10px}
  body.touch .z-statrow{padding:4px 2px}
  body.touch .z-endcard .z-cta{margin-top:12px}
  body.touch .z-endlink{margin-top:10px}
}

/* landscape is REQUIRED on a phone: portrait blocks play until rotated
   (iOS has no orientation-lock API; Android locks after fullscreen) */
@media (orientation: portrait){
  body.touch #ui::after{
    content:"⟳\A\A ROTATE TO LANDSCAPE";
    white-space:pre;
    position:fixed;inset:0;z-index:60;
    display:flex;align-items:center;justify-content:center;text-align:center;
    background:rgba(4,6,13,.94);
    font-size:20px;line-height:1.6;letter-spacing:.3em;color:var(--sodium);
    text-shadow:0 0 14px rgba(255,180,94,.5);
    pointer-events:auto;
  }
}

/* ================= fallbacks ================= */
#nogl,#nojs{
  position:fixed;inset:0;z-index:40;display:flex;align-items:center;justify-content:center;
  background:var(--bg);text-align:center;padding:24px;
}
#nogl .big,#nojs .big{font-size:64px;color:var(--sodium)}
#nogl h1,#nojs h1{font-family:var(--display);color:#fff;margin:12px 0;letter-spacing:.06em}
#nogl p,#nojs p{margin-top:10px;font-size:13px;letter-spacing:.12em}

@media (max-width:820px){
  .z-objectives{top:auto;bottom:120px;right:16px;max-width:60vw}
  .z-tl{top:14px;left:16px}
  .z-tr{top:14px;right:16px}
  .z-bl{bottom:16px;left:16px}
  .z-br{bottom:16px;right:16px}
  .z-map{width:120px}
}
