/* ═══ home ═══════════════════════════════════════════════════════════════ */

/* ── the cold open ───────────────────────────────────────────────────────── */
.open {
  position: relative;
  min-height: min(92svh, 900px);
  display: grid; align-items: center;
  padding: var(--s9) 0 var(--s8);
  border-bottom: var(--hair) solid var(--line);
  overflow: hidden;
  isolation: isolate;
}
/* The mark is the artwork. It sits in its own column on the right at a crop
   that keeps the G readable — a tighter crop turned it into wallpaper, which
   is a texture, not an identity. */
.open-art {
  position: absolute; z-index: -1;
  inset: -2% 2% -2% 48%;
  pointer-events: none;
  mask-image: radial-gradient(78% 76% at 52% 48%, #000 44%, transparent 92%);
  -webkit-mask-image: radial-gradient(78% 76% at 52% 48%, #000 44%, transparent 92%);
}
.open-art canvas { width: 100%; height: 100%; opacity: .68; }
.open-art-shards { position: absolute; inset: 0; }

.open-in { position: relative; }

.boot {
  font: 400 11px/1.9 var(--data);
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--t-ter);
  margin: 0 0 var(--s5);
  min-height: 7.6em;
  white-space: pre-wrap;
}
.boot b { color: var(--t-hi); font-weight: 400; }
.boot .cur {
  display: inline-block; width: 8px; height: 1em; vertical-align: -2px;
  background: var(--blown); animation: blink 1.05s steps(1) infinite;
}
@keyframes blink { 0%,50% { opacity: 1 } 50.01%,100% { opacity: 0 } }

.open h1 { margin: 0 0 var(--s4); }
.open h1 .tear { display: inline-block; }

.open-line {
  font: 500 11px/1 var(--data); letter-spacing: .28em;
  color: var(--t-dim); margin: 0 0 var(--s5);
}

.open-lede { margin-bottom: var(--s6); max-width: 54ch; }

.acts { display: flex; flex-wrap: wrap; gap: var(--s2); margin-bottom: var(--s7); }
.act {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 12px 18px;
  border: var(--hair) solid var(--line-up);
  background: rgba(10,10,12,.66);
  backdrop-filter: blur(6px);
  font: 600 11px/1 var(--data); letter-spacing: .18em; text-transform: uppercase;
  color: var(--t-body);
  clip-path: polygon(0 0, calc(100% - 9px) 0, 100% 9px, 100% 100%, 9px 100%, 0 calc(100% - 9px));
  transition: color var(--quick), border-color var(--quick), background var(--quick), transform var(--quick);
}
.act i { font-style: normal; color: var(--t-dim); }
.act:hover { color: var(--blown); border-color: var(--blown); background: var(--panel-hi); }
.act:hover i { color: var(--blown); }
.act:first-child { background: var(--blown); border-color: var(--blown); color: var(--void); font-weight: 700; }
.act:first-child i { color: var(--void); }
.act:first-child:hover { background: var(--t-hi); color: var(--void); }

.open-strip {
  display: flex; flex-wrap: wrap; gap: 1px;
  border: var(--hair) solid var(--line);
  background: var(--line);
  max-width: 940px;
}
.open-strip > div {
  flex: 1 1 150px; padding: 13px var(--s4);
  background: rgba(8,8,10,.86); backdrop-filter: blur(8px);
  display: grid; gap: 7px;
}
.open-strip .k {
  font: 500 9px/1 var(--data); letter-spacing: .2em; text-transform: uppercase; color: var(--t-dim);
}
.open-strip b { font: 500 14px/1 var(--data); color: var(--t-hi); font-variant-numeric: tabular-nums; }
.open-strip .live-b { display: flex; align-items: center; gap: 8px; color: var(--blown); }

/* ── the register (what the island runs) ─────────────────────────────────── */
.register {
  border-top: var(--hair) solid var(--line);
  display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 0 var(--s6);
}
.reg {
  display: grid; grid-template-columns: 34px minmax(0,1fr) auto;
  gap: var(--s4); align-items: baseline;
  padding: 18px 12px;
  border-bottom: var(--hair) solid var(--line);
  /* paint-only: a padding transition relayouts the row on every frame */
  transition: background var(--quick), box-shadow var(--quick);
}
.reg:hover { background: var(--panel); box-shadow: inset 3px 0 0 var(--blown); }
.reg-n { font: 400 11px/1.4 var(--data); color: var(--t-off); }
.reg-b { display: grid; gap: 5px; min-width: 0; }
.reg-b b {
  font-family: var(--display); font-weight: 700; font-stretch: 106%;
  font-size: 17px; line-height: 1.1; letter-spacing: -.01em; color: var(--t-hi);
}
.reg-b em { font-style: normal; font-size: 13px; line-height: 1.5; color: var(--t-ter); }
.reg-v { font-size: 13px; color: var(--t-sec); white-space: nowrap; }
.reg-v i { font-style: normal; font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--t-dim); }
.reg:hover .reg-v { color: var(--blown); }

/* ── mini boards ─────────────────────────────────────────────────────────── */
.board-mini .panel-b { padding: 0; }
.board-mini ol { list-style: none; margin: 0; padding: 0; counter-reset: r; }
.board-mini li {
  display: grid; grid-template-columns: 26px minmax(0,1fr) auto; gap: var(--s3);
  align-items: baseline; padding: 9px var(--s4);
  border-bottom: var(--hair) solid var(--line);
  transition: background var(--quick);
}
.board-mini li:last-child { border-bottom: 0; }
.board-mini li:hover { background: var(--panel-up); }
.board-mini li b { counter-increment: r; font: 400 11px/1 var(--data); color: var(--t-off); }
.board-mini li span { font-size: 13px; color: var(--t-body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board-mini li em { font: 500 12px/1 var(--data); font-style: normal; color: var(--t-hi); }
.board-mini li:first-child b { color: var(--blown); }
.board-mini li:first-child em { color: var(--blown); }

/* ── join ────────────────────────────────────────────────────────────────── */
.join { display: grid; grid-template-columns: 300px minmax(0,1fr); gap: var(--s7); align-items: start; }
.join-art {
  position: relative; aspect-ratio: 3/4;
  border: var(--hair) solid var(--line);
  background: var(--panel);
  box-shadow: var(--lit-edge), var(--crush);
  overflow: hidden;
}
.join-art canvas { width: 100%; height: 100%; opacity: .78; }

.mini-name { color: var(--t-hi); }

@media (max-width: 1180px) {
  .register { grid-template-columns: minmax(0,1fr); }
  .open-art { inset: -2% -14% 34% 30%; }
  .open-art canvas { opacity: .4; }
  .join { grid-template-columns: minmax(0,1fr); }
  .join-art { max-width: 260px; aspect-ratio: 1/1; }
}
@media (max-width: 860px) {
  .open { min-height: 0; padding-top: var(--s7); }
  .boot { min-height: 5.7em; }
  .open-strip > div { flex-basis: 46%; }
}
@media (max-width: 700px) {
  /* On a phone there is no second column to put the mark in, so it goes to the
     upper-right corner and drops back far enough that body copy still reads
     against it. Artwork that costs a paragraph its contrast is not artwork. */
  .open-art { inset: -2% -34% auto 38%; height: 46%; }
  .open-art canvas { opacity: .26; }
  .open-art-shards { display: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   HIS 2026-08-21 ASK: the live player count, every feature by name, and a
   Discord button. Three blocks, all of them index-only, all of them loaded
   BEFORE haven.css so the theme layer keeps the last word.

   ★ RED IS LIGHT, NEVER INK. Nothing added here reads as red body copy. The
     tally's figure is --t-hi bone with an ember GLOW behind it; the bar and
     the Discord button are ember as PAINT with white on top; the one place a
     red ink token appears is `--ember-ink` on the tally's live label, which
     check_contrast measures at 6.1:1 and clears at 4.5:1.
   ★ NOTHING HERE WRITES A CUSTOM PROPERTY ON :root. The tally bar is filled
     by writing `style.width` on ONE element - a root write invalidates the
     whole document on every frame.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── the tally: his first question, in the first viewport ────────────────── */
.tally {
  margin: 0 auto 30px;
  display: grid; justify-items: center; gap: 9px;
  max-width: 420px;
}
.tally-k {
  margin: 0;
  font: 500 9.5px/1 var(--data); letter-spacing: .26em; text-transform: uppercase;
  color: var(--t-dim);
}
.tally-n {
  margin: 0; display: flex; align-items: baseline; gap: 10px;
  font-family: var(--data); font-variant-numeric: tabular-nums;
  line-height: 1;
}
/* The figure carries the light of the scene rather than being painted in it.
   ★ THE GLOW IS MIXED FROM `--ember`, NEVER TYPED AS AN rgba().
     A literal here is a colour that stops following the theme the moment the
     theme moves - which it did, mid-wave: haven.css went from red to amber
     under this file and every hard-coded rgba(224,27,27) in it became a red
     bruise on an amber page, with a passing build and a clean console. Every
     tint below is `color-mix`ed off the token, so the block cannot fall out
     of step with the sheet that owns the colour. */
.tally-v {
  font: 700 clamp(46px, 8.4vw, 92px)/1 var(--display);
  letter-spacing: .01em; color: var(--t-hi);
  text-shadow: 0 0 34px color-mix(in srgb, var(--ember) 55%, transparent),
               0 0 90px color-mix(in srgb, var(--ember) 30%, transparent);
}
.tally-of { font: 400 clamp(22px,3vw,34px)/1 var(--data); color: var(--t-off); }
.tally-cap { font: 500 clamp(18px,2.2vw,26px)/1 var(--data); color: var(--t-sec); }

/* the bar is decoration for the two figures above it, so it is aria-hidden.
   Height is fixed in px: a percentage height on a bar in a grid row that has
   no height is a 0px bar that reads as a rendering artifact. */
.tally-bar {
  width: min(320px, 74vw); height: 4px;
  border-radius: var(--r-pill);
  background: rgba(255,255,255,.07);
  overflow: hidden;
}
.tally-bar > i {
  display: block; height: 100%; width: 0;
  border-radius: var(--r-pill);
  background: linear-gradient(90deg, var(--ember-deep), var(--ember-core));
  box-shadow: 0 0 16px -2px color-mix(in srgb, var(--ember) 90%, transparent);
  transition: width 600ms cubic-bezier(.22,.61,.36,1);
}
.tally-s {
  margin: 0; display: inline-flex; align-items: center; gap: 9px;
  font: 500 9.5px/1 var(--data); letter-spacing: .2em; text-transform: uppercase;
  color: var(--t-sec);
}
.tally-s .dot { width: 7px; height: 7px; }
/* ★ THE LIT STATE IS SET BY THE READING, NEVER BY THE PAGE HAVING LOADED.
   home.js writes data-state on .tally only when status.players is a real
   number; `unknown` and `offline` stay bone, because an unknown figure is not
   a low one and must never paint as an alarm. */
.tally[data-state="live"] .tally-s { color: var(--ember-ink); }

@media (prefers-reduced-motion: reduce) {
  .tally-bar > i { transition: none; }
}

/* the register's count chip, so the sixteen rows carry their own total */
.sys-n { font-size: 11px; color: var(--t-dim); }
.sys-n i { font-style: normal; color: var(--t-sec); }

/* ── the register, at sixteen rows ───────────────────────────────────────── */
/* The rows were built for nine and now carry sixteen, so the value column is
   pinned rather than left to the longest string, and the hover mark takes the
   scene's colour instead of the old sheet's white. */
.reg:hover { box-shadow: inset 3px 0 0 var(--ember); }
.reg-v i { font-style: normal; color: var(--t-hi); }
.reg:hover .reg-v i { color: var(--ember-core); }

/* ── Discord ─────────────────────────────────────────────────────────────── */
/* The hero action. Ember is PAINT here: nothing is read THROUGH it, and the
   label is the proper noun so it needs no key. Border and hover fill are both
   mixed off `--ember-core`, so this control follows the theme's hue instead
   of pinning last week's one. */
.btn.dc { border-color: color-mix(in srgb, var(--ember-core) 42%, transparent); }
.btn.dc:hover { border-color: var(--ember-core);
  background: color-mix(in srgb, var(--ember-char) 72%, var(--panel-hi)); }
/* dominion.css sets `.btn svg { width:14px }` at (0,1,1), so a bare `.dc-ic`
   would lose on specificity no matter which sheet loaded last. Both selectors
   below out-specify it deliberately rather than by accident. */
.btn .dc-ic { width: 18px; height: 18px; flex: 0 0 auto; }
.hero-acts .btn .dc-ic { width: 20px; height: 20px; }

/* ★ NAMED `.dc-panel`, NOT `.dc`. It was `.dc` for one build, and the hero
   button is `class="btn dc"` - so the panel's own
   `grid-template-columns: minmax(0,1fr) 300px` matched the BUTTON and handed
   the word "Discord" a 300px column. The button rendered, the build passed,
   the console was clean and it was 406px wide next to two 206px siblings.
   A short generic class name is not a namespace. */
.dc-panel { display: grid; grid-template-columns: minmax(0,1fr) 300px; gap: var(--s6);
  align-items: center; padding: var(--s6); }
/* min-width:0 or a long German sentence refuses to wrap and pushes the button
   column off the panel: a grid item's default min-width is its content. */
.dc-b { min-width: 0; }
.dc-lede { margin: 0 0 var(--s4); font-size: clamp(15px,1.5vw,19px); color: var(--t-body); }
.dc-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.dc-list li {
  position: relative; padding-left: 20px; font-size: 13.5px; line-height: 1.55;
  color: var(--t-sec);
}
.dc-list li::before {
  content: ""; position: absolute; left: 0; top: .55em;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--ember); box-shadow: var(--glow-2);
}
.dc-go { display: grid; gap: 12px; justify-items: stretch; }
.dc-btn { min-height: 54px; font: 700 11px/1 var(--data); letter-spacing: .18em;
  text-transform: uppercase; gap: 11px; }
/* ★ THE NOTE IS THE UNVERIFIED STATE, AND IT HIDES ITSELF.
   build.py stamps data-invite from DISCORD_INVITE_VERIFIED. The element stays
   in the markup in both states so its key can never become an orphan and fail
   the catalogue gate; only its display changes. */
.dc-note {
  margin: 0; text-align: center;
  font: 400 11px/1.5 var(--ui); color: var(--t-dim);
}
.dc-panel[data-invite="verified"] .dc-note { display: none; }

@media (max-width: 860px) {
  .dc-panel { grid-template-columns: minmax(0,1fr); padding: var(--s5); }
}
