/* ==========================================================================
   Daniel Hater Club — shared chrome
   Tokens, the space backdrop, ticker, panels and footer. Every content page
   pulls this in; per-page themes layer on top with their own stylesheet.
   ========================================================================== */

:root {
  /* --- palette: trophy gold on deep space, teal for data --- */
  --void:      #05061a;
  --void-lift: #0d1130;
  --gold:      #ffcb2c;
  --gold-hi:   #fff6c4;
  --gold-lo:   #a35f06;
  --cyan:      #35e8ce;
  --cyan-lo:   #0c5f6b;
  --blue:      #1a3fa0;
  --blue-lo:   #0a1b52;
  --magenta:   #ff3fa4;
  --lime:      #7cff3f;
  --paper:     #e8ecff;
  --dim:       #8f9bd4;

  /* --- type: a different face per job, the way the old web did it --- */
  --display: Impact, Haettenschweiler, "Arial Narrow Bold", "Arial Black", sans-serif;
  --ui:      Verdana, Geneva, Tahoma, sans-serif;
  --serif:   "Times New Roman", Times, serif;
  --hand:    "Comic Sans MS", "Chalkboard SE", "Marker Felt", cursive;
  --mono:    "Courier New", Courier, monospace;
}

* { box-sizing: border-box; }

/* `hidden` has to outrank the `display` a component sets on itself — several
   things on these pages (the amendment editor's two fields, its dialog) ship
   hidden and are shown by script. */
[hidden] { display: none !important; }

html { background: var(--void); }

body {
  margin: 0;
  min-height: 100dvh;
  color: var(--paper);
  font: 15px/1.55 var(--ui);
  overflow-x: hidden;
}

img { max-width: 100%; }

a { color: var(--cyan); }
a:hover { color: var(--magenta); }

:where(a, button, [tabindex]):focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 3px;
}

/* --------------------------------------------------------------- backdrop */
/* Three fixed decorative layers, drawn entirely from CSS so no page has to
   carry markup for them: two tiled starfields drifting at different speeds
   (cheap parallax depth) on <html>, then a nebula bloom on <body> above them,
   so the wordmark always has something to sit against. Painting order is tree
   order — html::before, html::after, then body::before — and page content
   lifts above all three with its own z-index. */
html::before,
html::after,
body::before {
  position: fixed;
  inset: 0;
  content: "";
  pointer-events: none;
  z-index: 0;
}

html::before,
html::after {
  inset: -20%;
  background-image: url("/img/homepage/bg-stars.gif");
  background-repeat: repeat;
}
html::before {
  background-size: 200px 200px;
  animation: drift-a 240s linear infinite;
}
html::after {
  background-size: 420px 420px;
  opacity: .55;
  animation: drift-b 400s linear infinite;
}

body::before {
  background:
    radial-gradient(46% 40% at 34% 40%, rgba(56, 30, 140, .58), transparent 70%),
    radial-gradient(38% 34% at 78% 74%, rgba(10, 92, 120, .42), transparent 72%),
    radial-gradient(60% 50% at 50% 0%,  rgba(120, 26, 96, .30), transparent 70%);
}

@keyframes drift-a { to { background-position: -600px  400px; } }
@keyframes drift-b { to { background-position:  840px -520px; } }

/* ----------------------------------------------------------------- ticker */
.ticker {
  position: relative;
  z-index: 3;
  overflow: hidden;
  border-block: 3px ridge var(--gold);
  background: linear-gradient(180deg, #2a1060, #10063a 46%, #2a1060);
  font: 700 12px/1 var(--ui);
  letter-spacing: .08em;
  text-transform: uppercase;
}
.ticker__track {
  display: flex;
  width: max-content;
  padding: 7px 0;
}
/* The scroll is a -50% slide, which only lines up once /js/ticker.js has
   cloned the single authored run into a second copy. Until then (or with JS
   off) the one run sits still rather than sliding half a message and jumping. */
.ticker__track:has(.ticker__run + .ticker__run) {
  animation: ticker 46s linear infinite;
}
.ticker__run { display: flex; gap: 2.4rem; padding-right: 2.4rem; white-space: nowrap; }
.ticker__run b { color: var(--gold); }
.ticker__run i { color: var(--cyan); font-family: var(--serif); font-size: 13px; letter-spacing: 0; text-transform: none; }

@keyframes ticker { to { transform: translateX(-50%); } }

/* ------------------------------------------------------------ panel/table */
/* The beveled box the standings live in — outset borders, gradient headers. */
.panel {
  max-width: 300px;
  margin: 0 auto;
  border: 4px outset var(--cyan);
  background: linear-gradient(170deg, #06313a, #041b3e 55%, #071033);
  box-shadow: 0 0 0 2px var(--blue-lo), 0 10px 34px rgba(0, 0, 0, .65);
}
.panel__bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .6rem;
  padding: 6px 10px;
  border-bottom: 3px ridge var(--cyan);
  background: linear-gradient(180deg, #3ff0d2, #109a8e 44%, #0a5f74);
}
/* The two spinning stars flanking the heading are pure decoration, so they
   live here instead of as a matched pair of <img> tags in the markup. */
.panel__bar::before,
.panel__bar::after {
  content: "";
  flex: none;
  width: 20px;
  height: 20px;
  background: url("/img/homepage/deco-spinning-star.gif") center / contain no-repeat;
}
.panel__bar h2 {
  margin: 0;
  /* sized to clear the 300px panel on one line, stars and padding included */
  font: 400 22px/1.1 var(--display);
  white-space: nowrap;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: #04212b;
  text-shadow: 1px 1px 0 rgba(255, 255, 255, .55);
}
.panel__note {
  margin: 0;
  padding: 5px 10px;
  border-bottom: 1px dashed var(--cyan-lo);
  font: 11px/1.3 var(--mono);
  text-align: center;
  text-wrap: balance;
  color: var(--cyan);
}
.panel__foot { margin: 0; padding: 10px 10px 12px; text-align: center; }
.panel__link { color: var(--gold); }

.ladder { width: 100%; border-collapse: collapse; }
.ladder th {
  padding: 5px 8px;
  background: linear-gradient(180deg, #2c5fd8, #16307e);
  border-bottom: 2px solid var(--cyan);
  font: 700 10px/1 var(--ui);
  letter-spacing: .1em;
  text-transform: uppercase;
  text-align: left;
  color: var(--gold-hi);
}
.ladder th:first-child,
.ladder td:first-child { width: 3.2em; text-align: center; white-space: nowrap; }

.ladder td {
  padding: 7px 8px;
  border-bottom: 1px solid rgba(53, 232, 206, .18);
  font: 15px/1.4 var(--serif);
}

/* Trophy on first place, poop on last: sized off the row's own text so the
   gif grows with the cell instead of setting its height. */
.ladder__icon {
  width: auto;
  height: 1.5em;
  margin-left: .4em;
  vertical-align: -.45em;
}
/* PAID sits at the right edge of the team cell, pinned there rather than laid
   out after the name, so a long name runs underneath it instead of pushing it
   into the W–L column. The cell is the positioning context. */
.ladder td:nth-child(2) { position: relative; }
.ladder__paid {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  padding: 3px 5px;
  background: #1f9d3a;
  border: 1px solid #2fd35a;
  font: 700 9px/1 var(--ui);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #fff;
}
/* In season the chip is a bare dollar sign — the word was the widest thing in
   the team cell and the row now has two more columns to seat. */
.ladder__paid--mini {
  right: 5px;
  padding: 2px 4px;
  font-size: 10px;
  letter-spacing: 0;
}

.ladder tbody tr:nth-child(odd)  { background: rgba(53, 232, 206, .07); }
.ladder tbody tr:nth-child(even) { background: rgba(26, 63, 160, .16); }
.ladder tbody tr:hover           { background: rgba(255, 203, 44, .16); }

.ladder td:first-child { font: 700 13px/1.4 var(--mono); color: var(--dim); }

/* ---- in season: W-L, the week's score, left-to-play, survivor, shotguns ---
   Five number columns instead of one, in a 300px rail. Everything but the team
   name is centred; the week's score is the one exception, its digits ranged
   right under a centred header so the decimal points line up down the column.
   The team cell gives up what width it can — the names are short and the
   columns beside them are not. */
.ladder--live th,
.ladder--live td { padding-inline: 4px; text-align: center; }
.ladder--live th { letter-spacing: .04em; font-size: 9px; }
.ladder--live td { font-size: 14px; }
.ladder--live th:nth-child(2),
.ladder--live td:nth-child(2) { width: 4.6em; text-align: left; }
.ladder--live td:nth-child(n+3) { font: 700 11px/1.4 var(--mono); white-space: nowrap; }
.ladder--live th:first-child,
.ladder--live td:first-child { width: 2.2em; }
.ladder--live th:nth-child(3),
.ladder--live td:nth-child(3) { width: 3.4em; }
.ladder--live td:nth-child(3) { color: var(--cyan); }
.ladder--live th:nth-child(4),
.ladder--live td:nth-child(4) { width: 4.2em; }
.ladder--live td:nth-child(4) { color: var(--gold); text-align: right; }
.ladder--live th:nth-child(5),
.ladder--live td:nth-child(5) { width: 2.8em; }
.ladder--live td:nth-child(5) { color: var(--dim); }
.ladder--live th:nth-child(6),
.ladder--live td:nth-child(6) { width: 2.8em; }
.ladder--live th:nth-child(7),
.ladder--live td:nth-child(7) { width: 2.8em; padding-right: 6px; }
/* A beer owed is worth noticing; nought is not. */
.ladder__shtg { color: var(--gold-hi); }

/* Off-season is three columns, and follows the same rule: the team name left,
   everything else centred. */
.ladder--off th,
.ladder--off td { text-align: center; }
.ladder--off th:nth-child(2),
.ladder--off td:nth-child(2) { text-align: left; }
.ladder--off th:last-child,
.ladder--off td:last-child { width: 4.6em; }
.ladder--off td:last-child { font: 700 13px/1.4 var(--mono); color: var(--cyan); }

/* A column header that can explain itself. The label is a button so a tap
   leaves focus behind — that is the whole of the mobile story, since a phone
   cannot hover — and the same rule serves both. */
.ladder th { position: relative; }
.ladder__hint {
  appearance: none;
  padding: 0;
  background: none;
  border: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: help;
}
.ladder__hint::after {
  content: attr(data-hint);
  position: absolute;
  top: calc(100% + 5px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 6;
  padding: 4px 7px;
  background: #061436;
  border: 1px solid var(--cyan);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .6);
  font: 700 10px/1.2 var(--ui);
  letter-spacing: .04em;
  text-transform: none;
  white-space: nowrap;
  color: var(--gold-hi);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.ladder__hint:hover::after,
.ladder__hint:focus::after { opacity: 1; visibility: visible; }
/* The last columns are narrow and near the panel's edge, so their hints hang
   from the right instead of straddling a 2.8em cell. */
.ladder th:nth-last-child(-n+2) .ladder__hint::after {
  left: auto;
  right: -4px;
  transform: none;
}

/* Survivor pool: a check while you're in it, a skull and the week you went out
   once you're not. The superscript is the whole history the column has room
   for, so it stays legible rather than shrinking away to nothing. */
.ladder__srv { font-size: 15px; }
.ladder__srv--alive { color: #2fd35a; }
.ladder__srv--out { color: #e0566b; }
.ladder__srv-wk {
  margin-left: 1px;
  font: 700 10px/1 var(--mono);
  vertical-align: super;
}

/* On the brink: both marks sit in the cell, stacked on the same spot, and one
   second each. Stacking them rather than rewriting one glyph keeps the column
   from twitching as the check and the skull trade places. Two independent
   keyframes rather than one with a negative delay — same effect, and it can't
   be thrown off by how a browser rounds the moment they swap.

   Deliberately *not* behind `prefers-reduced-motion`, unlike the ticker and
   the blink below: the alternation is the warning, not decoration on top of
   one, and pinning it to a still frame is the difference between a row that
   says "about to go out" and one that just says "out". A second-long swap on a
   single glyph is not the kind of motion that guard is there to catch. */
.ladder__srv--risk {
  position: relative;
  display: inline-block;
  min-width: 1.1em;
}
.ladder__srv-flip:first-child {
  color: #2fd35a;
  animation: srv-check 2s infinite;
}
.ladder__srv-flip:last-child {
  position: absolute;
  inset: 0;
  text-align: center;
  color: #e0566b;
  /* Hidden at rest as well as at 0%, so the frame before the animation is
     applied shows the check alone rather than both glyphs on top of each
     other. */
  opacity: 0;
  animation: srv-skull 2s infinite;
}
@keyframes srv-check { 0%, 49.9% { opacity: 1; } 50%, 100% { opacity: 0; } }
@keyframes srv-skull { 0%, 49.9% { opacity: 0; } 50%, 100% { opacity: 1; } }

/* ----------------------------------------------------------------- footer */
.footer {
  position: relative;
  z-index: 2;
  padding: 8px 1rem 30px;
  text-align: center;
}
.rule {
  height: 3px;
  margin: 0 auto 14px;
  max-width: 620px;
  border: 0;
  background: linear-gradient(90deg, transparent, var(--gold), var(--magenta), var(--cyan), transparent);
}
.footer__love {
  margin: 0 0 6px;
  font: 15px/1.4 var(--hand);
  color: var(--gold-hi);
  text-shadow: 1px 1px 0 var(--gold-lo), 2px 2px 0 rgba(0, 0, 0, .8);
}
.footer__meta {
  margin: 0;
  font: 11px/1.4 var(--mono);
  color: var(--dim);
}
.footer__meta .dot { margin: 0 .5em; }
.counter b {
  padding: 1px 5px;
  margin-left: 2px;
  border: 2px inset #444;
  background: #000;
  color: var(--lime);
  letter-spacing: .16em;
}

/* ------------------------------------------------------------------ bits */
.blink { font-style: normal; color: var(--magenta); }

@media (prefers-reduced-motion: no-preference) {
  .blink { animation: blink 1.1s steps(1) infinite; }
}
@keyframes blink { 50% { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  html::before,
  html::after,
  .ticker__track { animation: none; }
}
