/* ============================================================
   cums.uk — "Manual Actuator, Unit 01"
   A decommissioned industrial control panel in a dark room.
   Gunmetal, hazard tape, amber LED readouts, one enormous
   red arcade button. Single deliberate look — no theme switch.
   Zero external assets: every texture is a gradient or an
   inline data: URI.
   ============================================================ */

/* ---- 1. Tokens ------------------------------------------- */

:root {
  /* Escalation, written by effects.js */
  --heat: 0;    /* 0..1 — sustained, from the tier      */

  /* There is deliberately no per-frame custom property here. A custom
     property written on :root invalidates every element that reads a
     var(), and the things that read one are full-viewport gradients and
     wide-blur box-shadows — i.e. the most expensive paints on the page.
     Writing one per frame repainted the whole viewport 60 times a
     second. Transient per-press bloom is carried by .flash instead,
     which animates opacity on its own layer and never repaints. */

  /* Room */
  --void:      #050706;
  --room:      #0d1210;
  --room-lift: #18211e;

  /* Machined metal */
  --steel-hi: #626b67;
  --steel:    #333b39;
  --steel-lo: #1b211f;
  --seam:     #080b0a;
  --chrome:   #8d9995;

  /* The button */
  --red-hi: #ff8a6a;
  --red:    #e2251a;
  --red-lo: #85100b;
  --red-pit:#3d0605;

  /* Signal colours */
  --amber:     #ffb128;
  --amber-dim: #7a5518;
  --hazard:    #f5c518;
  --paper:     #f3ecdc;
  --ash:       #8d9793;
  --ash-dim:   #5a6360;

  /* Type */
  --font-display: "Impact", "Haettenschweiler", "Franklin Gothic Bold",
                  "Arial Narrow Bold", "Anton", "Oswald", sans-serif;
  --font-mono: "Menlo", "Consolas", "DejaVu Sans Mono", "Liberation Mono",
               ui-monospace, monospace;

  /* Geometry.
     The button is the hero, so it is sized off the smaller viewport
     axis — but capped against viewport height as well, so the panel
     never grows taller than the screen it is sitting on. */
  --nut: clamp(150px, min(38vmin, 30vh), 400px);
  --depth: calc(var(--nut) * 0.078);
  --plate: calc(var(--nut) * 1.44);

  --ease-snap: cubic-bezier(0.2, 0.9, 0.25, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---- 2. Base --------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

/* The site is exactly one screen. It never scrolls, so there is
   nothing to rubber-band, pull-to-refresh, or accidentally shove
   off-screen while mashing the button. */
html, body {
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  margin: 0;
  background: var(--void);
  color: var(--ash);
  font-family: var(--font-mono);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  -webkit-text-size-adjust: 100%;
}

h1, p { margin: 0; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- 3. The room ----------------------------------------- */

.room {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(130% 100% at 50% 42%, var(--room-lift) 0%, var(--room) 48%, var(--void) 100%);
}

/* Heat bloom — grows with the tier, spikes on each press. */
.room__glow {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(85% 62% at 50% 58%,
      rgba(255, 62, 26, calc(0.05 + var(--heat) * 0.30)) 0%,
      rgba(255, 62, 26, 0) 62%),
    radial-gradient(140% 90% at 50% 112%,
      rgba(255, 138, 40, calc(var(--heat) * 0.22)) 0%,
      rgba(255, 138, 40, 0) 70%),
    radial-gradient(110% 70% at 50% -12%,
      rgba(255, 40, 20, calc(var(--heat) * 0.16)) 0%,
      rgba(255, 40, 20, 0) 65%);
  transition: background 900ms linear;
}

/* Film grain. Inline SVG turbulence — no network, no image file. */
.room__grain {
  position: absolute;
  inset: -20%;
  opacity: 0.15;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: grain-drift 5.5s steps(6, end) infinite;
}

@keyframes grain-drift {
  0%   { transform: translate3d(0, 0, 0); }
  20%  { transform: translate3d(-3%, 2%, 0); }
  40%  { transform: translate3d(2%, -3%, 0); }
  60%  { transform: translate3d(-2%, -2%, 0); }
  80%  { transform: translate3d(3%, 1%, 0); }
  100% { transform: translate3d(0, 0, 0); }
}

.room__scan {
  position: absolute;
  inset: 0;
  opacity: 0.5;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.24) 0 1px,
    rgba(0, 0, 0, 0) 1px 4px
  );
}

.room__vignette {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 46%,
    rgba(0, 0, 0, 0) 34%,
    rgba(0, 0, 0, 0.55) 78%,
    rgba(0, 0, 0, 0.88) 100%);
}

/* ---- 4. Particles + flash -------------------------------- */

/* The particle canvas. will-change lifts it onto its own compositor
   layer: without it the canvas shares the root layer, so every frame
   of sparks repainted the document's paint chunk along with it. */
.sparks {
  position: fixed;
  inset: 0;
  z-index: 40;
  width: 100%;
  height: 100%;
  pointer-events: none;
  will-change: transform;
}

/* The per-press bloom. Its gradient is static and only its opacity
   moves, so it composites on its own layer and never repaints — which
   is why it, and not a :root custom property, carries the transient. */
.flash {
  position: fixed;
  inset: 0;
  z-index: 45;
  pointer-events: none;
  opacity: 0;
  will-change: opacity;
  background: radial-gradient(circle at 50% 52%,
    rgba(255, 214, 180, 0.95) 0%,
    rgba(255, 90, 40, 0.55) 34%,
    rgba(255, 40, 10, 0) 72%);
}

/* ---- 5. Shell + layout ----------------------------------- */

/* .shell is the shake target. Everything inside moves together.
   svh, not vh: on mobile it is the height that is always visible,
   so nothing hides behind collapsing browser chrome. */
.shell {
  position: relative;
  z-index: 10;
  height: 100vh;
  height: 100svh;
  will-change: transform;
}

.stage {
  height: 100%;
  max-width: 1120px;
  margin: 0 auto;
  /* Notches, rounded corners and the iOS home indicator. */
  padding:
    max(clamp(16px, 3.2vw, 44px), env(safe-area-inset-top))
    max(clamp(16px, 4vw, 40px), env(safe-area-inset-right))
    max(clamp(16px, 3.2vw, 44px), env(safe-area-inset-bottom))
    max(clamp(16px, 4vw, 40px), env(safe-area-inset-left));
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: clamp(12px, 2.4vh, 32px);
}

/* ---- 6. Masthead ----------------------------------------- */

.masthead {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
}

.mark__word {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2rem, 5.6vw, 3.6rem);
  line-height: 0.82;
  letter-spacing: 0.01em;
  color: #e9efec;
  text-transform: uppercase;
  text-shadow:
    0 1px 0 rgba(0, 0, 0, 0.9),
    0 0 26px rgba(255, 90, 40, calc(0.12 + var(--heat) * 0.42));
  transition: text-shadow 700ms linear;
}

.mark__dot {
  color: var(--red);
  text-shadow: 0 0 16px rgba(226, 37, 26, 0.85);
}

.mark__sub {
  margin-top: 0.7em;
  font-size: 0.62rem;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  color: var(--ash-dim);
}

/* Mute switch — a small panel-mounted rocker. */
.switch {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 13px 9px 11px;
  border: 1px solid #3c4442;
  border-radius: 3px;
  cursor: pointer;
  font: inherit;
  color: var(--ash);
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
  /* Comfortable thumb target on touch. */
  min-height: 44px;
  background:
    linear-gradient(180deg, #333b39 0%, #232a28 52%, #1a201e 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.09),
    inset 0 -1px 0 rgba(0, 0, 0, 0.5),
    0 2px 6px rgba(0, 0, 0, 0.5);
  transition: transform 120ms var(--ease-snap), border-color 200ms ease;
}

.switch:hover { border-color: #56605d; }
.switch:active { transform: translateY(1px); }

.switch__led {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--amber);
  box-shadow: 0 0 10px rgba(255, 177, 40, 0.9), inset 0 -1px 2px rgba(0, 0, 0, 0.4);
  transition: background 180ms ease, box-shadow 180ms ease;
}

.switch[aria-pressed="true"] .switch__led {
  background: #4a3a1c;
  box-shadow: inset 0 -1px 2px rgba(0, 0, 0, 0.6);
}

.switch__text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.15;
}

.switch__key {
  font-size: 0.55rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ash-dim);
}

.switch__state {
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--amber);
}

.switch[aria-pressed="true"] .switch__state { color: var(--ash-dim); }

/* ---- 7. The panel ---------------------------------------- */

.panel {
  position: relative;
  align-self: center;
  display: grid;
  justify-items: center;
  gap: clamp(10px, 1.9vh, 22px);
  padding: clamp(20px, 3.2vw, 40px) clamp(18px, 4vw, 48px) clamp(16px, 2.4vw, 28px);
  border-radius: 6px;
  border: 1px solid #3a4240;
  background:
    /* corner screws */
    radial-gradient(circle at 18px 18px, #6a736f 0 2.5px, #262d2b 3px 6px, transparent 6.5px),
    radial-gradient(circle at calc(100% - 18px) 18px, #6a736f 0 2.5px, #262d2b 3px 6px, transparent 6.5px),
    radial-gradient(circle at 18px calc(100% - 18px), #6a736f 0 2.5px, #262d2b 3px 6px, transparent 6.5px),
    radial-gradient(circle at calc(100% - 18px) calc(100% - 18px), #6a736f 0 2.5px, #262d2b 3px 6px, transparent 6.5px),
    /* brushed vertical grain */
    repeating-linear-gradient(90deg,
      rgba(255, 255, 255, 0.016) 0 1px,
      rgba(0, 0, 0, 0.02) 1px 3px),
    /* plate shading */
    linear-gradient(168deg, #2c3432 0%, #212827 46%, #171d1c 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    inset 0 -2px 0 rgba(0, 0, 0, 0.55),
    0 30px 70px -20px rgba(0, 0, 0, 0.9);
}

/* Hazard tape across the top edge.

   The stripes crawl on `transform`, never `background-position`.
   background-position is a paint property: animating it forced a style
   recalc and a full-viewport repaint on every frame, for ever, even
   with the page untouched. Measured at 6x CPU throttle on a 390x844
   DPR3 viewport, that one animation cost 152ms of main-thread work per
   second at idle — 94% of the page's entire idle cost. Sliding an
   over-wide pseudo-element instead is compositor-only and costs the
   main thread nothing.

   The pseudo hangs one stripe-period (28.28px = 20px / cos45) off the
   left edge and travels exactly that far, so the strip is always
   covered end to end and the loop is seamless. */
.panel__hazard {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 6px;
  border-radius: 5px 5px 0 0;
  overflow: hidden;
  opacity: calc(0.5 + var(--heat) * 0.5);
  transition: opacity 700ms linear;
}

.panel__hazard::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: -28.28px;
  right: 0;
  background: repeating-linear-gradient(
    -45deg,
    var(--hazard) 0 10px,
    #191512 10px 20px
  );
  animation: hazard-crawl 2.4s linear infinite;
  will-change: transform;
}

@keyframes hazard-crawl {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(28.28px, 0, 0); }
}

.panel__serial {
  position: absolute;
  top: 14px;
  right: 16px;
  font-size: 0.52rem;
  letter-spacing: 0.26em;
  color: var(--ash-dim);
}

.panel__brief {
  font-family: var(--font-display);
  font-size: clamp(0.95rem, 2.1vw, 1.35rem);
  letter-spacing: 0.42em;
  text-indent: 0.42em;
  text-transform: uppercase;
  color: #b8c2be;
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.8);
}

.panel__plate {
  font-size: 0.58rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ash-dim);
  padding: 5px 12px;
  border: 1px solid #333b39;
  border-radius: 2px;
  background: linear-gradient(180deg, #1d2422 0%, #151a19 100%);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05);
}

/* ---- 8. The actuator ------------------------------------- */

.actuator {
  position: relative;
  width: var(--plate);
  height: var(--plate);
  display: grid;
  place-items: center;
  isolation: isolate;
}

/* Mounting collar: chrome ring bolted into the plate. */
.actuator::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    conic-gradient(from 210deg,
      #2a3230 0deg, #7c8783 42deg, #39413f 96deg, #98a29e 150deg,
      #2f3735 208deg, #6b7571 262deg, #333b39 318deg, #2a3230 360deg),
    #2a3230;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.10),
    inset 0 calc(var(--nut) * 0.02) calc(var(--nut) * 0.06) rgba(0, 0, 0, 0.75),
    0 calc(var(--nut) * 0.03) calc(var(--nut) * 0.1) rgba(0, 0, 0, 0.75);
  z-index: 0;
}

/* Inner bore — the dark well the button sits in. */
.actuator::after {
  content: "";
  position: absolute;
  width: calc(var(--nut) * 1.08);
  height: calc(var(--nut) * 1.08);
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 40%, var(--red-pit) 0%, #120302 70%, #070101 100%);
  box-shadow:
    inset 0 calc(var(--nut) * 0.035) calc(var(--nut) * 0.07) rgba(0, 0, 0, 0.95),
    0 0 calc(var(--nut) * 0.4) rgba(255, 60, 30, calc(0.10 + var(--heat) * 0.55));
  z-index: 1;
  transition: box-shadow 500ms linear;
}

.nut {
  position: relative;
  z-index: 2;
  width: var(--nut);
  height: var(--nut);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  outline: none;
  /* Touch hygiene. `manipulation` is the important one: it kills the
     double-tap-to-zoom gesture, so a fast double tap registers as two
     presses instead of a zoom. Rapid tapping IS the interaction. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.nut__cap {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background:
    /* rim darkening */
    radial-gradient(circle at 50% 50%,
      rgba(0, 0, 0, 0) 58%, rgba(90, 6, 4, 0.55) 84%, rgba(50, 2, 1, 0.9) 100%),
    /* body */
    radial-gradient(circle at 36% 28%,
      #ff9c80 0%, #f4402a 32%, var(--red) 50%, #b3140e 76%, var(--red-lo) 100%);
  box-shadow:
    /* solid extrusion — the button has real depth */
    0 var(--depth) 0 #6d0b07,
    0 calc(var(--depth) + 2px) 0 #4b0705,
    0 calc(var(--depth) * 1.7) calc(var(--depth) * 2.4) rgba(0, 0, 0, 0.75),
    /* bloom */
    0 0 calc(var(--nut) * 0.28) rgba(255, 60, 30, calc(0.18 + var(--heat) * 0.45)),
    inset 0 calc(var(--nut) * -0.05) calc(var(--nut) * 0.09) rgba(80, 4, 2, 0.6),
    inset 0 calc(var(--nut) * 0.03) calc(var(--nut) * 0.05) rgba(255, 190, 170, 0.28);
  transition:
    transform 190ms var(--ease-snap),
    box-shadow 190ms var(--ease-snap),
    filter 190ms var(--ease-snap);
  animation: nut-breathe 3.6s ease-in-out infinite;
}

/* Specular glare across the dome. */
.nut__cap::before {
  content: "";
  position: absolute;
  top: 7%;
  left: 15%;
  width: 52%;
  height: 34%;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%,
    rgba(255, 255, 255, 0.58) 0%,
    rgba(255, 220, 205, 0.22) 44%,
    rgba(255, 255, 255, 0) 74%);
  filter: blur(1px);
  pointer-events: none;
}

/* Bounce light off the collar, along the lower rim. */
.nut__cap::after {
  content: "";
  position: absolute;
  bottom: 8%;
  left: 24%;
  width: 52%;
  height: 16%;
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%,
    rgba(255, 130, 100, 0.30) 0%,
    rgba(255, 120, 90, 0) 72%);
  pointer-events: none;
}

@keyframes nut-breathe {
  0%, 100% { transform: translateY(0) scale(1); }
  50%      { transform: translateY(calc(var(--depth) * -0.06)) scale(1.004); }
}

.nut__label {
  position: relative;
  z-index: 1;
  font-family: var(--font-display);
  font-size: calc(var(--nut) * 0.29);
  line-height: 1;
  letter-spacing: 0.06em;
  text-indent: 0.06em;
  text-transform: uppercase;
  color: #fff1ec;
  /* engraved: light below, shadow above */
  text-shadow:
    0 calc(var(--nut) * -0.006) calc(var(--nut) * 0.008) rgba(88, 4, 2, 0.9),
    0 calc(var(--nut) * 0.008) 0 rgba(255, 200, 185, 0.45),
    0 0 calc(var(--nut) * 0.12) rgba(255, 140, 110, 0.5);
  mix-blend-mode: screen;
  pointer-events: none;
}

/* Depressed: the cap sinks into its own extrusion. */
.nut.is-down .nut__cap {
  transform: translateY(var(--depth));
  animation: none;
  filter: brightness(0.86) saturate(1.15);
  box-shadow:
    0 1px 0 #6d0b07,
    0 2px 0 #4b0705,
    0 3px 6px rgba(0, 0, 0, 0.7),
    0 0 calc(var(--nut) * 0.34) rgba(255, 70, 36, calc(0.34 + var(--heat) * 0.5)),
    inset 0 calc(var(--nut) * 0.06) calc(var(--nut) * 0.11) rgba(60, 2, 1, 0.75),
    inset 0 calc(var(--nut) * -0.02) calc(var(--nut) * 0.05) rgba(255, 170, 150, 0.16);
  transition-duration: 60ms;
}

/* Auto-fire engaged: the actuator is running away with itself.
   The cap stays down, and the bore behind it goes properly incandescent. */
.nut.is-firing .nut__cap {
  filter: brightness(1.04) saturate(1.22);
  box-shadow:
    0 1px 0 #6d0b07,
    0 2px 0 #4b0705,
    0 3px 6px rgba(0, 0, 0, 0.7),
    0 0 calc(var(--nut) * 0.55) rgba(255, 90, 40, calc(0.55 + var(--heat) * 0.45)),
    inset 0 calc(var(--nut) * 0.06) calc(var(--nut) * 0.11) rgba(60, 2, 1, 0.75),
    inset 0 calc(var(--nut) * -0.02) calc(var(--nut) * 0.05) rgba(255, 190, 170, 0.3);
}

.actuator:has(.nut.is-firing)::after {
  box-shadow:
    inset 0 calc(var(--nut) * 0.035) calc(var(--nut) * 0.07) rgba(0, 0, 0, 0.95),
    0 0 calc(var(--nut) * 0.75) rgba(255, 80, 34, calc(0.5 + var(--heat) * 0.5));
}

/* The combo cell reads AUTO while held, which is wider than "×12". */
.readout__combo { font-variant-numeric: tabular-nums; }

/* Keyboard focus: hazard ring, well clear of the button. */
.nut:focus-visible {
  outline: 3px dashed var(--hazard);
  outline-offset: calc(var(--nut) * 0.14);
  border-radius: 50%;
}

.nut:focus-visible + .nut__cap,
.nut:focus-visible .nut__cap {
  filter: brightness(1.06);
}

/* ---- 9. Readout ------------------------------------------ */

.readout {
  width: 100%;
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr;
  gap: 1px;
  margin-top: clamp(4px, 1vh, 12px);
  border: 1px solid #101514;
  border-radius: 4px;
  overflow: hidden;
  background: #101514;
  box-shadow:
    inset 0 2px 8px rgba(0, 0, 0, 0.85),
    0 1px 0 rgba(255, 255, 255, 0.04);
  /* Mashing the button must never start a text selection or pop the
     iOS copy/paste bubble over the readout. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

.readout__cell {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px clamp(10px, 1.6vw, 18px) 13px;
  background:
    repeating-linear-gradient(to bottom,
      rgba(255, 255, 255, 0.014) 0 1px,
      rgba(0, 0, 0, 0) 1px 3px),
    linear-gradient(180deg, #0d1211 0%, #070a09 100%);
}

.readout__key {
  font-size: 0.5rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--ash-dim);
}

.readout__count {
  font-family: var(--font-mono);
  font-size: clamp(1.9rem, 5.6vw, 3.1rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--amber);
  text-shadow:
    0 0 4px rgba(255, 177, 40, 0.8),
    0 0 22px rgba(255, 140, 20, calc(0.35 + var(--heat) * 0.5));
  transition: text-shadow 500ms linear;
}

.readout__status,
.readout__combo {
  font-family: var(--font-display);
  font-size: clamp(0.9rem, 2.2vw, 1.3rem);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  line-height: 1.1;
  color: var(--amber);
  text-shadow: 0 0 12px rgba(255, 177, 40, 0.45);
}

.readout__combo { color: #e9efec; }

/* Tier pips */
.pips {
  display: flex;
  gap: 4px;
  margin-top: auto;
  padding-top: 6px;
}

.pip {
  width: 100%;
  height: 4px;
  border-radius: 1px;
  background: #1e2523;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.6);
  transition: background 320ms ease, box-shadow 320ms ease;
}

.pips[data-tier="0"] .pip:nth-child(-n + 1),
.pips[data-tier="1"] .pip:nth-child(-n + 2),
.pips[data-tier="2"] .pip:nth-child(-n + 3),
.pips[data-tier="3"] .pip:nth-child(-n + 4),
.pips[data-tier="4"] .pip:nth-child(-n + 5),
.pips[data-tier="5"] .pip:nth-child(-n + 6) {
  background: var(--amber);
  box-shadow: 0 0 8px rgba(255, 177, 40, 0.7);
}

/* The last two pips run hot. */
.pips[data-tier="4"] .pip:nth-child(5),
.pips[data-tier="5"] .pip:nth-child(5),
.pips[data-tier="5"] .pip:nth-child(6) {
  background: var(--red);
  box-shadow: 0 0 9px rgba(226, 37, 26, 0.85);
}

/* Combo meter */
.meter {
  position: relative;
  margin-top: auto;
  height: 10px;
  border-radius: 2px;
  overflow: hidden;
  background: #161c1b;
  box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.85);
}

.meter__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0%;
  background: linear-gradient(90deg, var(--amber) 0%, #ff6a2a 68%, var(--red) 100%);
  box-shadow: 0 0 12px rgba(255, 140, 30, 0.65);
  transition: width 130ms var(--ease-out);
}

/* Segment gaps drawn over the fill. */
.meter__grid {
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    90deg,
    rgba(0, 0, 0, 0) 0 6px,
    #0d1211 6px 8px
  );
}

/* ---- 10. Rails + footer ---------------------------------- */

.rail {
  position: fixed;
  top: 50%;
  z-index: 12;
  transform: translateY(-50%);
  writing-mode: vertical-rl;
  font-size: 0.52rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: #3d4644;
  pointer-events: none;
  user-select: none;
}

.rail--left  { left: 16px; }
.rail--right { right: 16px; transform: translateY(-50%) rotate(180deg); }

.footer {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px 20px;
  font-size: 0.6rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ash-dim);
}

.footer__fine { color: #39423f; }

/* ---- 11. Milestone toast --------------------------------- */

.toast-slot {
  position: fixed;
  z-index: 60;
  top: clamp(14px, 3vh, 34px);
  left: 50%;
  transform: translateX(-50%);
  width: min(420px, calc(100vw - 28px));
  pointer-events: none;
}

.toast {
  position: relative;
  padding: 16px 18px 16px 26px;
  border-radius: 2px;
  color: #17130c;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23p)' opacity='0.055'/%3E%3C/svg%3E"),
    linear-gradient(172deg, #fbf5e7 0%, var(--paper) 52%, #e3d9c2 100%);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.6) inset,
    0 18px 40px -12px rgba(0, 0, 0, 0.85),
    0 0 0 1px rgba(0, 0, 0, 0.55);
  transform-origin: 50% 0%;
  animation: toast-in 420ms var(--ease-out) both;
}

/* Hazard tape down the binding edge. */
.toast::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 8px;
  background: repeating-linear-gradient(
    -45deg,
    var(--hazard) 0 7px,
    #1a1409 7px 14px
  );
}

.toast.is-out {
  animation: toast-out 340ms var(--ease-snap) both;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(-18px) rotate(-1.6deg) scale(0.95); }
  60%  { opacity: 1; transform: translateY(3px) rotate(-0.9deg) scale(1.005); }
  to   { opacity: 1; transform: translateY(0) rotate(-0.9deg) scale(1); }
}

@keyframes toast-out {
  from { opacity: 1; transform: translateY(0) rotate(-0.9deg); }
  to   { opacity: 0; transform: translateY(-14px) rotate(-2.4deg); }
}

.toast__meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 0.5rem;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: #8c7c56;
}

.toast__tag {
  margin: 5px 0 4px;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 5.2vw, 2.1rem);
  line-height: 0.94;
  letter-spacing: 0.015em;
  text-transform: uppercase;
  color: #14100a;
}

.toast__line {
  font-size: 0.76rem;
  line-height: 1.45;
  letter-spacing: 0.01em;
  color: #43392a;
}

/* ---- 12. Responsive -------------------------------------- */

@media (max-width: 1180px) {
  .rail { display: none; }
}

@media (max-width: 620px) {
  /* Phones have height to spare, so lean harder on the short axis. */
  :root { --nut: clamp(160px, min(54vmin, 32vh), 300px); }

  .stage { gap: 18px; }

  .masthead {
    align-items: center;
  }

  /* Sit the panel low in its row. On a phone the button wants to be
     under the thumb, not floating in the middle of the screen. */
  .panel { align-self: end; }

  .readout {
    grid-template-columns: 1fr 1fr;
  }

  .readout__cell--count {
    grid-column: 1 / -1;
  }

  /* Small type needs a floor on a handset held at arm's length. */
  .readout__key,
  .switch__key { font-size: 0.6rem; }

  /* Not enough width for the serial and the brief to coexist. */
  .panel__serial { display: none; }

  .toast__line { font-size: 0.84rem; }
  .toast__meta { font-size: 0.58rem; }

  .footer { justify-content: flex-start; font-size: 0.64rem; }
  .footer__fine { display: none; }
}

@media (max-width: 380px) {
  .mark__sub { letter-spacing: 0.2em; font-size: 0.55rem; }
  .switch__key { display: none; }
}

/* Short phones (SE-sized, or anything in landscape). The page must
   fit on one screen, so the trimmings go before the button does. */
@media (max-width: 620px) and (max-height: 730px) {
  :root { --nut: clamp(130px, min(50vmin, 26vh), 240px); }
  .mark__sub,
  .panel__plate,
  .footer { display: none; }
}

/* Keep the button heroic on very large displays. */
@media (min-width: 1600px) and (min-height: 900px) {
  :root { --nut: clamp(300px, min(32vmin, 34vh), 480px); }
  .stage { max-width: 1320px; }
}

/* Squat viewports: don't let the button push the readout off. */
@media (max-height: 620px) and (min-width: 621px) {
  :root { --nut: clamp(120px, 27vh, 220px); }
  .panel__plate { display: none; }
}

/* ---- 13. Reduced motion ---------------------------------- *
   Shake and particles are switched off in JS. Here we drop the
   ambient loops and shorten transitions. The machine still
   reads, still counts, still escalates its colour and still
   pops toasts — it simply stops moving.
   ---------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .room__grain,
  .panel__hazard::before,
  .nut__cap {
    animation: none !important;
  }

  .toast,
  .toast.is-out {
    animation-duration: 160ms;
    animation-name: toast-fade;
  }

  @keyframes toast-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
  }

  .toast.is-out { animation-name: toast-fade; animation-direction: reverse; }

  .nut__cap { transition-duration: 90ms; }
  .nut.is-down .nut__cap { transition-duration: 40ms; }

  .meter__fill { transition-duration: 0ms; }

  .room__glow,
  .readout__count,
  .mark__word,
  .actuator::after,
  .panel__hazard { transition-duration: 0ms; }

  /* No canvas, so no rAF loop, so nothing needs its own layer. */
  .shell, .flash, .sparks { will-change: auto; }

  .sparks, .flash { display: none; }
}

/* Users who want no motion at all still get the depress cue —
   it is essential feedback, so it stays, just fast and small. */
@media (prefers-reduced-motion: reduce) {
  .nut.is-down .nut__cap { transform: translateY(calc(var(--depth) * 0.55)); }
}
