/* One dark world: a full-screen 3D floor under a thin typewriter HUD, like a prison intake form laid over the scene. */
:root {
  --night: #0c0f17;
  --panel: rgba(14, 17, 26, 0.86);
  --paper: #e8e2d2;
  --dim: #8f97a8;
  --amber: #f2b84b;
  --alarm: #e5484d;
  --font-display: "Special Elite", "Courier New", monospace;
  --font-ui: "Courier Prime", "Courier New", monospace;
  color-scheme: dark;
}
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
body { margin: 0; }
html, body { height: 100%; overflow: hidden; }
body { background: var(--night); color: var(--paper); font-family: var(--font-ui); -webkit-user-select: none; user-select: none; }
canvas#view { position: fixed; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }

.hud-top {
  position: fixed; top: 0; left: 0; right: 0; z-index: 5; pointer-events: none;
  display: flex; justify-content: space-between; align-items: flex-start; gap: 12px;
  padding: calc(10px + env(safe-area-inset-top, 0px)) max(16px, env(safe-area-inset-right, 0px)) 0 max(16px, env(safe-area-inset-left, 0px));
}
.tag { font-family: var(--font-display); font-size: 15px; letter-spacing: 0.06em; text-transform: uppercase; line-height: 1.25; text-shadow: 0 0 4px #000, 0 1px 2px #000; }
.tag small { display: block; font-family: var(--font-ui); font-size: 13px; color: #b3bac8; letter-spacing: 0.08em; }
/* a faint dark band behind the top line, so it holds over a lit floor */
.hud-top::before { content: ""; position: absolute; inset: 0 0 auto 0; height: calc(90px + env(safe-area-inset-top, 0px)); background: linear-gradient(rgba(7, 9, 14, 0.8), transparent); z-index: -1; }
@media (min-width: 900px) { .tag { font-size: 19px; } .tag small { font-size: 14px; } }
.right { text-align: right; }
#floor-tag { pointer-events: auto; cursor: pointer; } /* tap it to read the floor's tip again */
.num { font-variant-numeric: tabular-nums; }

.hud-bottom {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 5;
  display: flex; flex-direction: column; gap: 10px; align-items: stretch;
  padding: 0 max(16px, env(safe-area-inset-right, 0px)) calc(14px + var(--random-nav-h, env(safe-area-inset-bottom, 0px))) max(16px, env(safe-area-inset-left, 0px));
  pointer-events: none;
}
.hint {
  align-self: center; max-width: min(100%, 40ch); text-wrap: balance; font-size: 14px; color: #c3c9d4; text-align: center; min-height: 1.3em; transition: color .2s;
  background: var(--panel); border-radius: 6px; padding: 5px 12px;
}
.hint:empty { visibility: hidden; }
/* over the floor the chrome is light: the hint is type with a shadow, the
   buttons are outlines (the cards keep their panels) */
.hud-bottom .hint { background: none; padding: 2px 8px; color: var(--paper); text-shadow: 0 0 4px #000, 0 1px 2px #000, 0 0 10px #000; }
.hud-bottom .hint.lit { color: var(--amber); }
.hud-bottom .hint.bad { color: var(--alarm); }
.hud-bottom .buttons button { background: rgba(7, 9, 14, 0.35); border-color: rgba(232, 226, 210, 0.35); }
.carded .hud-bottom { opacity: 0; } /* a card open: nothing of the HUD shows through under it */
.hint.lit { color: var(--amber); }
.hint.bad { color: var(--alarm); }
.buttons { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
button {
  pointer-events: auto; font: 700 13px/1 var(--font-ui); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--paper); background: var(--panel); border: 1px solid #3a4152; border-radius: 3px;
  padding: 10px 16px; min-height: 44px; min-width: 44px; cursor: pointer;
}
/* a toggle shows a small box, filled when it's on: amber stays for the one
   main button on a card, and for light */
button[aria-pressed] { display: inline-flex; align-items: center; justify-content: center; gap: 8px; }
button[aria-pressed]::before { content: ""; flex: none; width: 12px; height: 12px; border: 2px solid currentColor; border-radius: 2px; }
button[aria-pressed="true"] { border-color: #8a8577; }
button[aria-pressed="true"]::before { background: currentColor; }
@media (forced-colors: active) {
  button[aria-pressed]::before { forced-color-adjust: none; border-color: ButtonText; }
  button[aria-pressed="true"]::before { background: Highlight; }
}
/* focus is paper, never a second amber box next to the one main button */
button:focus-visible { outline: 2px solid var(--paper); outline-offset: 2px; }

.card-wrap {
  position: fixed; inset: 0; z-index: 10; display: flex; flex-direction: column; overflow-y: auto; overscroll-behavior: contain;
  padding: calc(16px + env(safe-area-inset-top, 0px)) max(16px, env(safe-area-inset-right, 0px)) calc(16px + var(--random-nav-h, env(safe-area-inset-bottom, 0px))) max(16px, env(safe-area-inset-left, 0px));
  background: rgba(6, 8, 12, 0.55);
}
.card-wrap > .card { margin: auto; flex-shrink: 0; } /* centered when it fits, scrolls when it doesn't */
.card {
  width: min(380px, 100%); background: #151925; border: 1px solid #3a4152; border-radius: 4px;
  padding: 22px 20px 20px; display: flex; flex-direction: column; gap: 14px;
  box-shadow: 0 20px 60px rgba(0,0,0,.5);
}
/* the same rubber stamp as CAUGHT, smaller: red for danger, paper for a
   floor cleared and for the record (amber is the card's main button) */
.card .stamp { font: 700 12px/1 var(--font-ui); letter-spacing: 0.16em; color: #ea5a5e; /* the alarm red, a shade lighter to read at 12px */ text-transform: uppercase; border: 2px solid currentColor; border-radius: 3px; align-self: flex-start; padding: 5px 8px; transform: rotate(-3deg); }
.card .stamp.paper { color: var(--paper); }
.card h1 { font: 400 30px/1.05 var(--font-display); margin: 0; text-wrap: balance; }
.card p { margin: 0; font-size: 14px; line-height: 1.5; color: #c9c4b6; }
.card ul { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; font-size: 14px; line-height: 1.45; color: #c9c4b6; }
.card .go { align-self: stretch; padding: 14px; font-size: 14px; border-color: var(--amber); color: var(--amber); }
.card #share, .card #brief-share { align-self: stretch; padding: 12px; font-size: 13px; margin-top: -4px; }
.card .meta { font-size: 12px; color: var(--dim); letter-spacing: 0.04em; }
/* a vignette: the corners of the frame go to black, and in Scout the edge of
   the floor goes with them, so it sits in the dark rather than on a card */
.vignette { position: fixed; inset: 0; z-index: 3; pointer-events: none; background: radial-gradient(ellipse 75% 70% at 50% 50%, transparent 55%, rgba(3,4,7,.55) 85%, rgba(3,4,7,.85) 100%); transition: opacity .4s; }
.vignette::after { content: ''; position: absolute; inset: 0; opacity: 0; transition: opacity .4s; background: radial-gradient(ellipse 80% 72% at 50% 50%, transparent 78%, #030407 100%); }
.scouting .vignette::after { opacity: 1; }
/* Night vision, for the fly-over: the game turns the light up (game.js, setNV) and this makes it a green phosphor picture,
   scanned and grainy, the corners only a touch darker. It snaps on with the fly-over and fades off as play starts. */
canvas#view { transition: filter .35s; }
.night-vision canvas#view { filter: grayscale(1) contrast(1.55) brightness(1.1) sepia(1) hue-rotate(52deg) saturate(3.2); transition: none; }
.nv { position: fixed; inset: 0; z-index: 3; pointer-events: none; opacity: 0; transition: opacity .35s;
  background:
    radial-gradient(ellipse 75% 70% at 50% 50%, transparent 80%, rgba(1,6,2,.28) 100%),
    repeating-linear-gradient(0deg, rgba(0,0,0,.22) 0 1px, transparent 1px 3px),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .6 0 0 0 0 1 0 0 0 0 .6 0 0 0 .5 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E"); }
.night-vision .nv { opacity: 1; transition: none; animation: nv-grain .24s steps(3) infinite; }
.night-vision .vignette { opacity: 0; }
@keyframes nv-grain { 0% { background-position: 0 0, 0 0, 0 0; } 33% { background-position: 0 0, 0 1px, -40px 22px; } 66% { background-position: 0 0, 0 2px, 31px -57px; } }
.nv-tag { position: absolute; left: 50%; bottom: calc(var(--random-nav-h, 0px) + 150px); transform: translateX(-50%); font: 700 11px/1 var(--font-ui); letter-spacing: .3em; color: #9dff9a; text-shadow: 0 0 6px #3cff6a; opacity: .8; }
@media (prefers-reduced-motion: reduce) { .night-vision .nv { animation: none; } }
.fade { position: fixed; inset: 0; background: #000; opacity: 0; pointer-events: none; z-index: 8; transition: opacity .5s; }
.fade.on { opacity: 1; }
.fade.quick { transition: opacity .18s; }
/* reduced motion: a reframe is a cut out of black */
.fade.blink { animation: blink .22s ease-out; }
@keyframes blink { from { opacity: .55; } to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .fade, .fade.quick { transition: none; } }

.card .row { display: flex; gap: 8px; flex-wrap: wrap; }
.card .row button { flex: 1 1 140px; }
.card .row button[aria-pressed] { padding-inline: 10px; font-size: 12px; white-space: nowrap; } /* the box and its label on one line */
.floors { display: flex; flex-direction: column; gap: 6px; max-height: 42vh; overflow-y: auto; padding: 4px; margin: -4px; scroll-padding-bottom: 36px; }
/* more below: its last few pixels fade until you reach the end (never over
   a row you've tabbed to) */
.floors.more:not(:focus-within) { -webkit-mask-image: linear-gradient(#000 calc(100% - 32px), transparent); mask-image: linear-gradient(#000 calc(100% - 32px), transparent); }
.floors { gap: 0; }
/* the scorecard as a ruled list: hairlines between floors, the one you're
   on marked with a paper rule */
.floors button { border: 0; border-bottom: 1px solid #2a3040; border-radius: 0; background: transparent; }
.floors button.here { box-shadow: inset 3px 0 0 var(--paper); }
.floors button { display: flex; justify-content: space-between; align-items: center; min-height: 44px; gap: 12px; text-align: left; text-transform: none; letter-spacing: 0.02em; font-weight: 400; font-size: 14px; }
.floors button .note { color: var(--dim); font-size: 12px; font-variant-numeric: tabular-nums; }
.floors button:disabled { opacity: 0.45; cursor: default; }
.contrast .hint { color: var(--paper); }
.contrast .hint.lit, .contrast .hud-bottom .hint.lit { color: #fff2a8; }

/* the stamp that comes down on a catch: red ink on the screen, a little crooked */
.stamp-caught {
  position: fixed; left: 50%; top: 25%; z-index: 7; pointer-events: none;
  border-radius: 6px; color: var(--alarm); background: rgba(12, 15, 23, 0.6); text-shadow: 0 0 1px var(--alarm);
  font: 400 54px/1 var(--font-display); letter-spacing: 0.08em; text-transform: uppercase;
  transform: translate(-50%, -50%) rotate(-7deg); opacity: 0; visibility: hidden;
}
/* the ink comes off unevenly, as off a rubber stamp; the dark plate under it
   doesn't, so a bright floor never shows through as static */
.stamp-caught .ink {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 10px 26px 12px; border: 5px solid var(--alarm); border-radius: 6px;
  -webkit-mask-image: url(ink.png); mask-image: url(ink.png); -webkit-mask-size: 160px; mask-size: 160px;
}
.stamp-caught small { font: 700 15px/1.2 var(--font-ui); letter-spacing: 0.24em; }
.stamp-caught.on { visibility: visible; animation: stamp-slam 0.3s forwards; transition: opacity 0.3s; }
/* it falls faster and faster (0.2 s, STAMP_DROP in game.js) and hits, then
   squashes and settles; at the end of the catch it lifts away */
@keyframes stamp-slam {
  0% { opacity: 0; transform: translate(-50%, -50%) rotate(-14deg) scale(2.3); animation-timing-function: cubic-bezier(.55, 0, 1, .45); }
  66% { opacity: 0.95; transform: translate(-50%, -50%) rotate(-7deg) scale(0.94); animation-timing-function: ease-out; }
  100% { opacity: 0.95; transform: translate(-50%, -50%) rotate(-7deg) scale(1); }
}
.stamp-caught.on.lifting { animation: stamp-slam 0.3s forwards, stamp-lift 0.3s ease-in forwards; }
@keyframes stamp-lift { to { opacity: 0; transform: translate(-50%, -54%) rotate(-7deg) scale(1.04); } }
@media (prefers-reduced-motion: reduce) { .stamp-caught.on, .stamp-caught.on.lifting { animation: none; transition: none; opacity: 0.95; } .stamp-caught.on.lifting { opacity: 0; } }

/* a phone on its side: the buttons go down the right, the hint to the top,
   so neither sits over the ball */
@media (orientation: landscape) and (max-height: 520px) {
  .hud-bottom { left: auto; width: auto; align-items: flex-end; }
  .buttons { flex-direction: column; align-items: stretch; gap: 10px; }
  .hint { position: fixed; top: calc(10px + env(safe-area-inset-top, 0px)); left: 50%; transform: translateX(-50%); max-width: 46vw; }
  .card { width: min(560px, 100%); }
  .floors { max-height: calc(100dvh - 240px - var(--random-nav-h, 0px)); } /* the scorecard's buttons stay on screen, above the navbar too */
}

/* a guard off the screen whose light is coming your way: a chevron at the
   edge, pointing at them; it pulses when the light is nearly on you */
.threat {
  position: fixed; z-index: 4; width: 34px; height: 34px; margin: -17px 0 0 -17px; pointer-events: none;
  border-radius: 11px; background: center / 100% no-repeat; /* drawn in game.js, in the eye's hand */
}
.threat::after { content: ""; position: absolute; inset: 0; background: var(--arrow) center / 100% no-repeat; transform: rotate(var(--turn, 0rad)); }
.threat.soon { animation: threat-pulse 0.45s ease-in-out infinite alternate; } /* the 900 ms beat, as in game.js */
@keyframes threat-pulse { to { box-shadow: 0 0 0 6px rgba(229, 72, 77, 0.25); } }
@media (prefers-reduced-motion: reduce) { .threat.soon { animation: none; } }
