/* CAM 04 — a takeover page.
   The browser window IS the monitor, so the frame is fixed, nothing scrolls and there is no site
   chrome. Everything positions in % of that frame and sizes in vmin, which lets the same scene fill
   a phone in portrait and an ultrawide without a viewBox to stay in register with.

   Palette and type match DAZZLE's: near-black blue, off-white, one gold accent used sparingly. */

:root {
  --bg: #05060a;
  --line: rgba(232, 230, 223, 0.08);
  --line-2: rgba(232, 230, 223, 0.16);
  --fg: #e8e6df;
  --fg-2: #b7b4ac;
  --mute: #7c7a75;
  --gold: #f4b728;
  --gold-2: #ffd36a;
  --red: #ff4d5a;
  --ok: #4ade80;
  --display: "Space Grotesk", "Inter", system-ui, sans-serif;
  --sans: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, Menlo, monospace;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; overflow: hidden; }
body { background: var(--bg); color: var(--fg); font-family: var(--sans); -webkit-font-smoothing: antialiased; }
a { color: inherit; text-decoration: none; }
[hidden] { display: none !important; }
::selection { background: var(--gold); color: #000; }

.seen {
  position: fixed; inset: 0; overflow: hidden;
  background: var(--bg); cursor: crosshair;
  font-family: var(--mono); font-variant-ligatures: none;
}
.seen-frame { position: absolute; inset: 0; animation: feedJitter 13s steps(1) infinite; }

/* ---------- the concourse ---------- */
.s-hall { position: absolute; inset: 0; }
.s-hall::before {
  content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(120% 78% at 50% 8%, rgba(76, 94, 132, .2), transparent 62%),
    radial-gradient(64% 46% at 13% 26%, rgba(244, 183, 40, .05), transparent 72%),
    radial-gradient(58% 42% at 87% 22%, rgba(139, 92, 246, .06), transparent 72%),
    linear-gradient(to bottom, transparent 48%, rgba(122, 152, 205, .09) 56%, transparent 64%),
    linear-gradient(#080a11 0%, #0a0d16 46%, #05060b 100%);
}
.s-hall::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 62%;
  background: repeating-linear-gradient(90deg, transparent 0 13.5%, rgba(3, 4, 8, .72) 13.5% 16.5%);
  -webkit-mask-image: linear-gradient(to bottom, #000 30%, transparent 96%);
  mask-image: linear-gradient(to bottom, #000 30%, transparent 96%);
}

/* Light battens overhead, receding to the same vanishing point as the floor. */
.s-ceil {
  position: absolute; left: -25%; right: -25%; top: -8%; height: 36%;
  transform: perspective(340px) rotateX(-72deg); transform-origin: 50% 0;
  background-image: repeating-linear-gradient(0deg, rgba(186, 212, 255, .15) 0 2px, transparent 2px 116px);
  -webkit-mask-image: linear-gradient(to bottom, transparent 4%, #000 78%);
  mask-image: linear-gradient(to bottom, transparent 4%, #000 78%);
  opacity: .55; pointer-events: none;
}

.s-floor {
  position: absolute; left: -60%; right: -60%; bottom: -16%; height: 74%;
  transform: perspective(340px) rotateX(74deg); transform-origin: 50% 100%;
  background-image:
    repeating-linear-gradient(90deg, rgba(150, 175, 215, .17) 0 1px, transparent 1px 92px),
    repeating-linear-gradient(0deg, rgba(150, 175, 215, .13) 0 1px, transparent 1px 92px);
  background-position: 0 0, 0 0;
  animation: floorDrift 16s linear infinite;
  -webkit-mask-image: linear-gradient(to top, #000 4%, rgba(0, 0, 0, .3) 44%, transparent 80%);
  mask-image: linear-gradient(to top, #000 4%, rgba(0, 0, 0, .3) 44%, transparent 80%);
}
@keyframes floorDrift { to { background-position: 0 92px, 0 92px; } }

.s-haze {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(to top, rgba(8, 10, 17, .88), transparent 42%),
    radial-gradient(100% 56% at 50% 100%, rgba(64, 80, 118, .13), transparent 72%);
}

/* ---------- the crowd: everyone it has no trouble with ---------- */
.s-crowd { position: absolute; inset: 0; }
.s-ped {
  position: absolute; top: var(--y); left: 0; height: var(--h); opacity: var(--o);
  will-change: transform; animation: walkR var(--dur) linear infinite var(--delay);
}
.s-ped.to-l { animation-name: walkL; }
.s-ped::before { content: ""; position: absolute; inset: -5px -7px -3px; border: 1px solid rgba(152, 182, 224, .2); }
@keyframes walkR { from { transform: translateX(-16vw); } to { transform: translateX(116vw); } }
@keyframes walkL { from { transform: translateX(116vw); } to { transform: translateX(-16vw); } }

.s-pfig { height: 100%; width: auto; display: block; fill: #1a1f2d; }
.s-pfig .lg { animation: step .92s steps(2) infinite; }
.s-pfig .lg.b { animation-delay: .46s; }
@keyframes step { 0% { transform: translateX(-.7px); } 50% { transform: translateX(.7px); } 100% { transform: translateX(-.7px); } }

.s-pbox {
  position: absolute; left: 50%; bottom: calc(100% + 9px); transform: translateX(-50%);
  display: flex; align-items: center; gap: 6px; white-space: nowrap;
  padding: 2px 5px; background: rgba(5, 7, 12, .6); border: 1px solid rgba(152, 182, 224, .16);
  font-size: clamp(7px, .86vmin, 9.5px); letter-spacing: .12em; color: rgba(196, 208, 226, .5);
}
.s-pbox i { display: block; height: 7px; background: #000; }
.s-pok { color: rgba(116, 196, 148, .7); }

/* ---------- the five it could not resolve ---------- */
.s-subs { position: absolute; inset: 0; }
.s-sub {
  position: absolute; left: var(--x); bottom: var(--y); width: var(--w);
  transform: translateX(-50%); display: block; z-index: 3;
}
.s-sub.far { z-index: 2; }
.s-sub.open, .s-sub.locked, .s-sub:focus-visible { z-index: 9; }
.s-sub:focus { outline: none; }

.s-fig { position: relative; width: 100%; aspect-ratio: 4 / 5; }
.s-fig svg {
  width: 100%; height: 100%; display: block;
  filter: drop-shadow(0 8px 22px rgba(0, 0, 0, .85)) brightness(.9) saturate(.9) contrast(1.04);
  transition: filter .25s ease, opacity .4s ease;
}
.s-sub.open .s-fig svg, .s-sub.locked .s-fig svg {
  filter: drop-shadow(0 8px 26px rgba(244, 183, 40, .24)) brightness(1.02) contrast(1.02);
}

/* The lock cycle: the box hunts in cold white, then gives up in gold. One 6s keyframe drives the
   border and both status words, offset per shape by --d so the five never agree. */
.s-box {
  position: absolute; inset: -4% -8%; pointer-events: none;
  border: 1px solid rgba(200, 215, 235, .28);
  animation: lockBox 6s steps(1) infinite var(--d);
}
@keyframes lockBox {
  0%, 22% { border-color: rgba(200, 215, 235, .3); box-shadow: none; }
  22.01%, 100% { border-color: rgba(244, 183, 40, .5); box-shadow: 0 0 30px -8px rgba(244, 183, 40, .45); }
}
.s-box .c { position: absolute; width: 9px; height: 9px; border: 0 solid var(--gold); }
.s-box .tl { top: -1px; left: -1px; border-top-width: 2px; border-left-width: 2px; }
.s-box .tr { top: -1px; right: -1px; border-top-width: 2px; border-right-width: 2px; }
.s-box .bl { bottom: -1px; left: -1px; border-bottom-width: 2px; border-left-width: 2px; }
.s-box .br { bottom: -1px; right: -1px; border-bottom-width: 2px; border-right-width: 2px; }

.s-top {
  position: absolute; left: -1px; bottom: calc(100% + 6px);
  display: flex; align-items: center; gap: 8px; white-space: nowrap;
  font-size: clamp(8px, .95vmin, 11px); letter-spacing: .16em; color: rgba(214, 224, 240, .78);
}
.s-top i { display: inline-block; height: 8px; background: #000; vertical-align: middle; }

.s-stat { position: absolute; left: -1px; top: calc(100% + 6px); display: grid; font-size: clamp(8px, .95vmin, 11px); letter-spacing: .2em; }
.s-stat > span { grid-area: 1 / 1; white-space: nowrap; animation: 6s steps(1) infinite var(--d); }
.s-stat .a { color: rgba(190, 206, 228, .72); animation-name: statA; opacity: 1; }
/* Base state matches keyframe 0 of each, so the pair never both shows before the cycle starts. */
.s-stat .b { color: var(--gold); animation-name: statB; opacity: 0; }
@keyframes statA { 0%, 22% { opacity: 1; } 22.01%, 100% { opacity: 0; } }
@keyframes statB { 0%, 22% { opacity: 0; } 22.01%, 100% { opacity: 1; } }

/* the key, and the only button on the page */
.s-panel {
  position: absolute; left: 50%; bottom: calc(100% + 28px); transform: translate(-50%, -5px);
  width: max-content; max-width: min(320px, 64vw); display: grid; gap: 8px; padding: 10px 12px;
  background: rgba(5, 7, 12, .93); border: 1px solid color-mix(in srgb, var(--gold) 38%, transparent);
  box-shadow: 0 24px 50px -24px #000; backdrop-filter: blur(6px);
  opacity: 0; pointer-events: none; transition: opacity .18s ease, transform .18s ease;
}
/* Once it is up the panel has to be reachable: it is inside the anchor, so taking pointer events
   back both makes CLAIM clickable and keeps the pointer within the anchor on the way to it. The
   ::after bridges the gap the pointer has to cross — without it, moving toward the button leaves
   the anchor and closes the panel out from under you. */
.s-sub.open .s-panel, .s-sub:focus-visible .s-panel { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.s-panel::after { content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 34px; }
.s-panel .row { display: grid; gap: 3px; font-size: clamp(8px, .92vmin, 10px); letter-spacing: .18em; color: var(--mute); }
.s-panel code { font-family: var(--mono); font-size: clamp(10px, 1.15vmin, 12.5px); letter-spacing: .02em; color: var(--gold-2); word-break: break-all; }
.s-panel .claim {
  text-align: center; padding: 7px 10px; background: var(--gold); color: #0a0800;
  font-size: clamp(9px, 1vmin, 11px); font-weight: 700; letter-spacing: .18em;
}
.s-sub:hover .claim { background: var(--gold-2); }

/* The shape someone arrived here holding. It is an exhibit, not an offer: their key is already in
   the banner, so showing it a second time in a floating panel only invited the two to disagree. */
.s-sub.locked .s-box { animation: none; border-color: var(--gold); box-shadow: 0 0 44px -8px rgba(244, 183, 40, .55); }
.s-sub.locked .s-panel { display: none; }
.s-sub.locked .s-stat > span { opacity: 0; animation: none; }
.s-sub.locked .s-stat .v { opacity: 1; }
.s-stat .v { color: var(--gold-2); opacity: 0; }

/* Claiming releases the shape: stripes wipe across it, the box lets go, and somebody else walks
   into the frame. The point of the whole page is that the record ends, so it has to LOOK like the
   record ending rather than a button going grey. */
.s-wipe {
  position: absolute; inset: 0; opacity: 0; pointer-events: none;
  background: repeating-linear-gradient(72deg, var(--gold) 0 3px, transparent 3px 11px);
  mix-blend-mode: screen;
}
.s-sub.released .s-wipe { animation: wipe .85s ease-out forwards; }
.s-sub.released .s-fig svg { animation: dissolve 1s ease-in forwards; }
.s-sub.released .s-box { animation: none; border-color: rgba(232, 230, 223, .18); box-shadow: none; }
.s-sub.released .s-stat > span { animation: none; opacity: 0; }
.s-sub.released .s-stat .r { opacity: 1; }
.s-sub.arriving .s-fig svg { animation: arrive .7s ease-out both; }
.s-stat .r { color: var(--ok); opacity: 0; }
@keyframes wipe {
  0% { opacity: 0; transform: translateY(-14%); }
  22% { opacity: .85; }
  100% { opacity: 0; transform: translateY(14%); }
}
@keyframes dissolve { to { opacity: 0; filter: blur(3px) brightness(2.2) saturate(0); transform: scale(1.04); } }
@keyframes arrive { from { opacity: 0; filter: blur(4px) brightness(.4); } }

/* ---------- optics ---------- */
.s-sweep {
  position: absolute; left: 0; right: 0; top: -42vh; height: 38vh; pointer-events: none;
  background: linear-gradient(to bottom, transparent, rgba(140, 190, 255, .045) 62%, rgba(184, 216, 255, .14));
  border-bottom: 1px solid rgba(184, 216, 255, .3);
  animation: sweep 9s linear infinite;
}
@keyframes sweep { to { top: 104%; } }

.seen-lines {
  position: absolute; inset: 0; z-index: 20; pointer-events: none; opacity: .5;
  background: repeating-linear-gradient(to bottom, rgba(0, 0, 0, .3) 0 1px, transparent 1px 3px);
}
.seen-lines::after {
  content: ""; position: absolute; inset: -50%; opacity: .05;
  background-image: 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='.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: grain .7s steps(4) infinite;
}
@keyframes grain {
  0% { transform: translate(0, 0); } 25% { transform: translate(-3%, 2%); }
  50% { transform: translate(2%, -3%); } 75% { transform: translate(-2%, -1%); }
}
.seen-vig {
  position: absolute; inset: 0; z-index: 21; pointer-events: none;
  background: radial-gradient(122% 100% at 50% 48%, transparent 36%, rgba(0, 0, 0, .55) 76%, rgba(0, 0, 0, .88) 100%);
}
@keyframes feedJitter {
  0%, 95.6% { transform: none; opacity: 1; }
  96% { transform: translate(-2px, 1px); }
  96.4% { transform: translate(2px, -1px); opacity: .93; }
  96.8%, 98.3% { transform: none; opacity: 1; }
  98.7% { transform: translate(1px, 0); opacity: .95; }
}

/* ---------- the overlay the operator reads ---------- */
.seen-hud {
  position: absolute; inset: 0; z-index: 30; pointer-events: none;
  font-family: var(--mono); font-size: clamp(10px, 1.2vmin, 13px);
  letter-spacing: .16em; text-transform: uppercase; color: rgba(200, 212, 230, .6);
}
.seen-hud a { pointer-events: auto; }
.h-tl { position: absolute; top: clamp(14px, 2.2vmin, 26px); left: clamp(14px, 2.4vmin, 30px); }
/* The two top corners carry the whole frame: which camera this is, and that it is running. They
   were set at HUD size and were simply too small to read, so they get a scale of their own. */
.h-brand {
  display: flex; align-items: center; gap: .42em;
  font-family: var(--display); font-weight: 700; font-size: clamp(23px, 3.1vmin, 36px);
  letter-spacing: .24em; color: var(--fg);
}
/* The mark is the brand's, shared with the main site. Sized off the wordmark so the two scale
   together, and nudged up a hair because the glyphs have no descenders to balance against. */
.h-mark { width: 1.05em; height: 1.05em; flex: none; fill: currentColor; margin-top: -.06em; }
.h-sub { margin-top: 9px; font-size: clamp(11px, 1.4vmin, 15px); color: var(--fg-2); }
.h-tr { position: absolute; top: clamp(14px, 2.2vmin, 26px); right: clamp(14px, 2.4vmin, 30px); text-align: right; }
.h-rec { display: flex; align-items: center; justify-content: flex-end; gap: 8px; font-size: clamp(13px, 1.7vmin, 18px); color: var(--red); }
.h-rec i { width: 9px; height: 9px; border-radius: 50%; background: var(--red); animation: rec 1.7s steps(1) infinite; }
@keyframes rec { 0%, 55% { opacity: 1; } 55.01%, 100% { opacity: .12; } }
.h-clock { margin-top: 9px; font-size: clamp(12px, 1.55vmin, 17px); letter-spacing: .06em; color: rgba(206, 218, 236, .82); font-variant-numeric: tabular-nums; }

/* Everything the feed intercepts is struck out. The terms that matter burn through. Narrow enough
   that the log never reaches the centred call to action; it wraps to a second line instead. */
.h-bl { position: absolute; left: clamp(14px, 2.4vmin, 30px); bottom: clamp(14px, 2.4vmin, 26px); max-width: min(330px, 27vw); }
.h-flag { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; }
.h-flag .k { color: var(--mute); margin-right: 3px; }
.h-flag b { color: var(--gold); font-weight: 600; letter-spacing: .12em; }
.h-flag i { display: block; height: 10px; background: #000; border: 1px solid rgba(232, 230, 223, .05); }
.h-bl, .h-br { text-shadow: 0 1px 10px var(--bg), 0 0 22px var(--bg); }

.h-br { position: absolute; right: clamp(14px, 2.4vmin, 30px); bottom: clamp(14px, 2.4vmin, 26px); display: grid; gap: 6px; }
.h-br div { display: flex; gap: 14px; justify-content: flex-end; align-items: baseline; color: var(--fg-2); font-variant-numeric: tabular-nums; }
.h-br span { color: var(--mute); }
.h-br .bad { color: var(--gold); }
.h-br .gold { color: var(--gold-2); }

.h-verify {
  position: absolute; top: clamp(14px, 2.2vmin, 26px); left: 50%; transform: translateX(-50%);
  display: grid; gap: 6px; justify-items: center; text-align: center;
  padding: 11px 20px; max-width: min(92vw, 470px);
  background: rgba(5, 7, 12, .88); border: 1px solid; backdrop-filter: blur(8px);
}
.h-verify b { letter-spacing: .22em; }
.h-verify span { color: var(--mute); font-size: .92em; }
.h-verify code { font-family: var(--mono); text-transform: none; letter-spacing: .02em; color: var(--gold-2); word-break: break-all; }
.h-verify.ok { border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
.h-verify.ok b { color: var(--ok); }
.h-verify.bad { border-color: color-mix(in srgb, var(--red) 45%, transparent); }
.h-verify.bad b { color: var(--red); }
.h-claim { margin-top: 4px; padding: 8px 16px; background: var(--gold); color: #0a0800; font-weight: 700; letter-spacing: .18em; font-size: .96em; }
.h-claim:hover { background: var(--gold-2); }

@media (max-width: 1180px) {
  /* The counters drop out, so the intercept log takes the bottom edge and centres. Over the middle
     of the feed it needs a plate of its own to stay legible where a shape happens to stand. */
  .h-bl {
    left: 50%; transform: translateX(-50%); max-width: min(560px, 92vw);
    padding: 8px 14px; background: rgba(5, 6, 10, .74); border: 1px solid var(--line); backdrop-filter: blur(4px);
  }
  .h-flag { justify-content: center; }
  .h-br { display: none; }
  /* The verify banner is centred at the top, and below this width it reaches the header. Dropping
     the tail of the camera line is what keeps the two from overlapping. */
  .h-tl .wide { display: none; }
}
@media (max-height: 660px) {
  /* A short window puts the nearest shapes under the bottom overlay, so they move up. The two deep
     ones are NOT lifted: they already sit high, and raising them pushed their panel off the top. */
  .s-sub { width: calc(var(--w) * .82); }
  .s-sub:not(.far) { bottom: calc(var(--y) + 12%); }
  .s-panel { bottom: calc(100% + 22px); }
}
@media (max-width: 760px) {
  /* Two of the five stand too deep to be tappable on a phone, so the frame keeps the three nearest
     and scales them up rather than shrinking five targets below a fingertip. They also stand
     higher, to clear the intercept log along the bottom. */
  .s-sub.far { display: none; }
  .s-sub { width: calc(var(--w) * 1.5); bottom: calc(var(--y) + 16%); }
  .h-verify { top: calc(clamp(14px, 2.2vmin, 26px) + 90px); bottom: auto; }
}
/* A touch screen has no hover to open a panel with, and a panel centred on a shape near the edge
   of a phone hangs off it. So the key panel is desktop-only: on touch the shape itself is the tap
   target, the key is already in the post that opens, and anyone arriving from a claim link gets
   their button from the verify banner, which is in frame at every width. */
@media (hover: none) { .s-panel { display: none; } }

@media (prefers-reduced-motion: reduce) {
  .seen-frame, .s-floor, .s-sweep, .seen-lines::after, .s-pfig .lg { animation: none; }
  .s-ped { animation-play-state: paused; }
  .s-box, .s-stat > span { animation-iteration-count: 1; animation-fill-mode: forwards; }
}
