/*
 * watch.css — THE WALL AND THE RECORD, spectator tier (2026-10-25 rebuild).
 * The big screen: legible at 3+ meters on a TV. The page is standalone (no
 * base.html chrome, no lattice) and body carries .watch-boost, which
 * rescales the type tokens — this sheet never invents a second scale.
 * Everything sits under body.watch-boost: watch.css also ships on the
 * working board via base.html and must stay inert there.
 * Laws honored: every color a token; no animation of any length inside the
 * swapped region (#watch-live-region); nothing under 17px effective
 * (the boosted --t-meta IS the 17px floor).
 */

/* -- stage: the wall's own canvas, no lattice ---------------------------- */
body.watch-boost {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: var(--s-void);
}

.watch-stage {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: var(--sp-4) var(--sp-6) var(--sp-6);
}

/* The invisible SSE listener must not open a flex gap. */
body.watch-boost .sse-listener { display: none; }

/* -- ambient: ONE radar sweep behind the grid ---------------------------- */
.watch-sweep {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 0;
  width: 3px;
  background: linear-gradient(
    to bottom,
    transparent,
    var(--sig) 30%,
    var(--sig) 70%,
    transparent
  );
  opacity: 0.04; /* the ceiling: presence without strobe */
  animation: sweep-x var(--c-sweep) linear infinite; /* 12s base; boost doubles */
  pointer-events: none;
}

/* -- kiosk masthead ------------------------------------------------------ */
.watch-masthead {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-5) var(--sp-8);
  padding: var(--sp-4) var(--sp-6);
  border-bottom: 1px solid var(--line);
}

.watch-brand {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
}

.watch-mark {
  width: clamp(32px, 4vw, 56px);
  height: clamp(32px, 4vw, 56px);
  color: var(--sig);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
}

.watch-wordmark {
  font-family: var(--font-mono);
  font-weight: 600;
  /* 4vw tracks the fluid hero token (4vw ceiling) so the wordmark and the
     masthead scale together — at 4.6vw it outgrew the row the ladder fits. */
  font-size: clamp(30px, 4vw, var(--t-display-hero));
  line-height: var(--t-display-hero-lh);
  letter-spacing: 0.12em;
  color: var(--text-max);
  white-space: nowrap;
}

.watch-word-accent { color: var(--sig); }

.watch-event-mast {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-width: 0;
}

.watch-event-mast .event-emblem {
  width: 40px;
  height: 40px;
}

.watch-event-mast .event-emblem .icon {
  width: 24px;
  height: 24px;
}

.watch-event-name {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--t-display-2);
  line-height: var(--t-display-2-lh);
  color: var(--text-max);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.watch-live-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--line);
  border-radius: var(--r-lamp);
  color: var(--text-label);
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  white-space: nowrap;
}

/* -- counters: display-size mono numerals on stable masthead wrappers ----- */
.watch-counters {
  display: flex;
  gap: var(--sp-8);
  margin-left: auto;
}

.watch-counter {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--sp-1);
}

.watch-counter-num {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: var(--t-display-1);
  line-height: var(--t-display-1-lh);
  color: var(--text-max);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.watch-counter-frac {
  font-size: var(--t-title);
  color: var(--text-label);
}

.watch-counter-lbl {
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-label);
}

/* -- territory fill: solved-fraction hatching in the hex silhouette ------ */
.watch-territory {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-1);
}

.watch-territory-gauge {
  position: relative;
  width: clamp(48px, 5vw, 76px);
  aspect-ratio: 1;
}

/* The hex mask matches i-hexlamp's silhouette; the bar inside carries the
   solved fraction and is the ONLY part ever swapped (hx-swap-oob twin). */
.watch-territory-mask {
  position: absolute;
  inset: 0;
  background: var(--s-pit);
  clip-path: polygon(
    50% 14.6%, 79.2% 32.3%, 79.2% 67.7%,
    50% 85.4%, 20.8% 67.7%, 20.8% 32.3%
  );
}

.watch-territory-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  background:
    repeating-linear-gradient(45deg, var(--ch-solved) 0 1px, transparent 1px 5px),
    var(--ch-solved-dim);
}

.watch-territory-hex {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.watch-territory-lbl {
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-label);
}

/* -- the swapped region: nothing animated lives here --------------------- */
.watch-live-region {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  gap: var(--sp-4);
}

/* -- zones: 6px state edges at this scale -------------------------------- */
.watch-grid {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(6, minmax(300px, 1fr));
  gap: var(--sp-4);
  min-height: 0;
  min-width: 0;
  overflow-x: auto;
  padding-bottom: var(--sp-2);
}

.watch-zone {
  display: flex;
  flex-direction: column;
  min-width: 300px;
  min-height: 0;
  background: var(--s-panel);
  border: 1px solid var(--line-soft);
  border-top: 6px solid var(--zone-hue, var(--line));
  border-radius: var(--r-chamfer);
}

.watch-zone[data-state="backlog"] { --zone-hue: var(--ch-backlog); }
.watch-zone[data-state="claimed"] { --zone-hue: var(--ch-claimed); }
.watch-zone[data-state="stuck"] { --zone-hue: var(--ch-stuck); }
.watch-zone[data-state="captured"] { --zone-hue: var(--ch-captured); }
.watch-zone[data-state="solved"] { --zone-hue: var(--ch-solved); }
.watch-zone[data-state="writeup_posted"] { --zone-hue: var(--ch-writeup); }

.watch-zone-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--line-soft);
}

.watch-zone-word {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: var(--t-title-lg);
  line-height: var(--t-title-lg-lh);
  letter-spacing: 0.04em;
  color: var(--text-max);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.watch-zone-count {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: var(--t-display-2);
  line-height: 1;
  color: var(--zone-hue, var(--text-max));
  font-variant-numeric: tabular-nums;
}

/* .watch-cards (NOT .column-cards): Sortable never wires here — spectator
   tiles must not become drag anchors firing 401 POSTs. */
.watch-cards {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-height: 160px;
  padding: var(--sp-3);
  overflow-y: auto;
}

/* -- tiles ---------------------------------------------------------------- */
.watch-tile {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-4);
  background: var(--s-card);
  border: 1px solid var(--line-soft);
  border-radius: var(--r-chamfer);
  cursor: default;
}

/* Attribute selector: only tiles that actually carry a deep-link. */
.watch-tile[hx-get] {
  cursor: pointer;
  transition:
    background var(--t-fast) var(--ease-snap),
    border-color var(--t-fast) var(--ease-snap);
}

.watch-tile[hx-get]:hover {
  background: var(--s-card-hi);
  border-color: var(--line-tick);
}

.watch-tile-top {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.watch-tile-lamp {
  width: 14px;
  height: 14px;
}

.watch-tile-points {
  margin-left: auto;
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: var(--t-title-lg);
  line-height: 1;
  color: var(--text-max);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.watch-pts-unit {
  margin-left: var(--sp-1);
  font-size: var(--t-meta);
  font-weight: 400;
  color: var(--text-label);
}

.watch-tile-title {
  font-family: var(--font-sans);
  font-weight: 700; /* synthesized over the vendored 600: the TV-distance cut */
  font-size: clamp(20px, 1.9vw, 44px);
  line-height: 1.15;
  color: var(--text-max);
  overflow-wrap: anywhere;
}

.watch-tile-cat {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--cat-misc); /* default: unmapped categories stay labeled + neutral */
  font-family: var(--font-mono);
  font-size: max(18px, var(--t-ui));
  letter-spacing: 0.02em;
}

.watch-tile-cat.cat-pwn { color: var(--cat-pwn); }
.watch-tile-cat.cat-web { color: var(--cat-web); }
.watch-tile-cat.cat-crypto { color: var(--cat-crypto); }
.watch-tile-cat.cat-rev { color: var(--cat-rev); }
.watch-tile-cat.cat-forensics { color: var(--cat-forensics); }
.watch-tile-cat.cat-stego { color: var(--cat-stego); }

.watch-cat-mark {
  width: 14px;
  height: 14px;
  fill: currentColor;
  flex: none;
}

/* -- presence-only signal pills: icon, never text; static by poll law ----- */
.watch-pill-signal {
  padding: 3px 4px;
  gap: 0;
  line-height: 1;
}

.watch-pill-swarm {
  border-color: var(--st-info);
  color: var(--st-info);
  background: transparent;
}

/* -- tile foot: holder stack + lease + recency ---------------------------- */
.watch-tile-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-top: auto;
  padding-top: var(--sp-2);
  border-top: 1px solid var(--line-soft);
}

.watch-holders {
  display: flex;
}

.watch-holder-avatar {
  width: 34px;
  height: 34px;
  border: 2px solid var(--s-card);
  border-radius: var(--r-lamp);
}

.watch-holder-avatar + .watch-holder-avatar {
  margin-left: calc(-1 * var(--sp-2));
}

.watch-lease {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

body.watch-boost .claim-timer { font-size: var(--t-meta); }

.watch-recency {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  color: var(--text-label);
  white-space: nowrap;
}

.watch-recency-dot {
  width: 8px;
  height: 8px;
  border-radius: var(--r-lamp);
  background: var(--text-faint); /* decorative: the label carries the meaning */
}

/* -- quiet: no live event — a calm hold screen ---------------------------- */
.watch-quiet {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-8);
}

.watch-quiet-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  max-width: 36rem;
  text-align: center;
}

.watch-quiet-mark {
  width: 96px;
  height: 96px;
  color: var(--text-faint);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.2;
}

.watch-quiet-card h1 {
  margin: 0;
  font-size: var(--t-display-1);
}

.watch-quiet-card p {
  margin: 0;
  color: var(--text-label);
  font-size: var(--t-body);
}

/* Event archived mid-watch: the fragment's ended state, same calm. */
.watch-ended {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-8);
  border: 1px dashed var(--line-soft);
  border-radius: var(--r-panel);
  color: var(--text-label);
  font-size: var(--t-body);
  text-align: center;
}

/* -- narrower stages: scroll, never squish -------------------------------- */
@media (max-width: 1600px) {
  .watch-grid { grid-template-columns: repeat(6, minmax(280px, 1fr)); }
  .watch-zone { min-width: 280px; }
}

@media (max-width: 640px) {
  .watch-masthead {
    gap: var(--sp-4);
    padding: var(--sp-3) var(--sp-4);
  }

  .watch-counters {
    gap: var(--sp-4);
    width: 100%;
    margin-left: 0;
    justify-content: space-between;
  }

  .watch-counter { align-items: flex-start; }

  .watch-stage { padding: var(--sp-3) var(--sp-4); }

  .watch-grid { grid-template-columns: repeat(6, minmax(240px, 1fr)); }
  .watch-zone { min-width: 240px; }
}

/* -- reduced motion: the sweep parks, nothing else moves ------------------ */
@media (prefers-reduced-motion: reduce) {
  .watch-sweep {
    animation: none;
    opacity: 0.02; /* parked, still present: the wall is never blank */
  }
}
