/* match-night.css: the parts of the site that are meant to feel like a match
   night (DECISIONS.md, 2026-09-19).

   The strip-back rules still hold underneath: plain words, one idea per
   screen on a phone, no box around everything. What changes here is the
   volume. A poster at the top of the home page, the numbers large and
   tabular, a chat ticker under the header, the server list drawn like a
   server browser, and a rank up drawn as an event rather than a line.

   Every colour is a token. Nothing carries an inline style, so a bar is SVG
   and a width is an attribute. Everything that moves is bounded, and the
   whole file goes quiet under prefers-reduced-motion at the bottom. */

/* ---------- Imagery ---------- */
/* An empty slot is not a broken page: the poster draws itself out of the
   faction shapes and the gradient and nothing is missing. */
.art, .art__img { display: block; width: 100%; height: 100% }
.art__img { object-fit: cover }
.shapes { inset: 0; width: 100%; height: 100% }
.shapes__far { fill: var(--hero-ink); opacity: 0.05 }
.shapes__mid { opacity: 0.3 }
.shapes__near { opacity: 0.62 }
.shapes__lonestar { fill: var(--red-fill) }
.shapes__valkyra { fill: var(--muted2) }
.shapes__manticore { fill: var(--edge) }

/* The poster: the faction colours as light, under whatever sits on top. It is
   drawn whether or not a screenshot has landed, so an image arriving changes
   the picture and not the layout. The layers are stacked by hand because an
   image is in flow and a gradient on a pseudo element is not. */
.hero__media, .poster__media, .door__art { position: relative; background: var(--hero-bg); overflow: hidden }
.hero__media::before, .poster__media::before, .door__art::before {
  content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(70% 46% at 50% -8%, rgba(244, 239, 231, 0.3), transparent 72%),
    radial-gradient(95% 130% at 6% 100%, var(--red-deep), transparent 62%),
    radial-gradient(85% 120% at 96% 4%, var(--raised), transparent 64%),
    radial-gradient(75% 110% at 52% 108%, var(--surface), transparent 60%);
  opacity: 0.44;
}
/* The floodlight falls off at the edges, which is what stops a big flat
   panel reading as a slide background. */
.hero__media::after, .poster__media::after, .door__art::after {
  content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background: radial-gradient(125% 95% at 50% 8%, transparent 38%, rgba(15, 13, 12, 0.6) 100%);
}
.hero__media--empty::before { opacity: 0.5 }
.art, .shapes { position: relative; z-index: 1 }
.shapes { position: absolute }
.hero__wash, /* The two doors must not be the same picture twice while both slots are
   empty, so the right hand one turns the light round and flips the shapes. */
.door__art--new::before {
  background:
    radial-gradient(92% 125% at 94% 96%, var(--surface), transparent 60%),
    radial-gradient(82% 115% at 8% 6%, var(--red-deep), transparent 64%),
    radial-gradient(76% 112% at 46% 104%, var(--raised), transparent 58%);
}
.shapes--flip { transform: scaleX(-1) }
.door__wash { z-index: 2 }

/* ---------- The chat ticker ---------- */
/* Two copies of the same list, so one pass of the track loops seamlessly.
   Every line was rendered by the server; nothing here is built in a browser. */
.ticker { border-bottom: 1px solid var(--divider); background: var(--surface); overflow: hidden }
.ticker__track { display: flex; width: max-content; animation: tickerRoll 52s linear infinite }
.ticker:hover .ticker__track, .ticker:focus-within .ticker__track { animation-play-state: paused }
.ticker__list { display: flex; align-items: center; flex: 0 0 auto }
.ticker__item {
  display: inline-flex; align-items: center; gap: 9px; padding: 0 20px;
  min-height: 38px; white-space: nowrap; font-size: 14px; color: var(--muted);
}
.ticker__mark { width: 7px; height: 7px; background: var(--edge); flex: 0 0 auto }
.ticker__item--rankup .ticker__mark { background: var(--ink) }
.ticker__item--money .ticker__mark { background: var(--amber-ink) }
.ticker__item--joined .ticker__mark { background: var(--muted) }
.ticker__item--war .ticker__mark { background: var(--red-fill) }
.ticker__text { color: var(--ink) }
.ticker__stamp { font-family: var(--data); font-size: 12px; color: var(--muted2) }

/* ---------- The hero ---------- */
.hero--match {
  position: relative; display: flex; align-items: flex-end; overflow: hidden;
  min-height: 62vh; margin: -8px calc(var(--gutter) * -1) 10px;
  background: var(--hero-bg); color: var(--hero-ink);
}
.hero__media { position: absolute; inset: 0 }
/* The wash is what makes a headline readable over somebody's screenshot. It
   is deliberately heavy at the bottom, which is where the words are and where
   the tool tells Daz to keep nothing important. */
.hero__wash {
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(15, 13, 12, 0.1) 0%, rgba(15, 13, 12, 0.45) 30%,
    rgba(15, 13, 12, 0.88) 66%, rgba(15, 13, 12, 0.98) 100%);
}
.hero__body { position: relative; z-index: 3; width: 100%; padding: 30px var(--gutter) 26px }
.hero--match .kicker {
  font-family: var(--display); font-weight: 700; font-size: 13px;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--hero-muted);
}
.h1--hero { font-size: var(--type-hero); letter-spacing: -0.015em; margin: 8px 0 2px }
.hero--match .bignum__value { font-size: var(--num-hero); color: var(--hero-ink); text-shadow: 0 0 22px rgba(244, 239, 231, 0.4) }
.hero--match .bignum__label { color: var(--hero-muted) }
.hero__line { font-size: 18px; line-height: 1.45; max-width: 28ch; margin-bottom: 18px }
.hero--match .hero__cta { margin-top: 0 }

/* ---------- Numbers that are the point of the screen ---------- */
.bignum { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 12px; margin: 12px 0 10px }
.bignum__value {
  font-family: var(--data); font-weight: 700; font-variant-numeric: tabular-nums;
  font-size: var(--num-big); line-height: 0.92; letter-spacing: -0.03em; color: var(--ink);
}
.bignum__label { flex: 1 1 100%; color: var(--muted); font-size: 15px }
.bignum--stale .bignum__value { color: var(--amber-ink) }
.bignum--offline .bignum__value { color: var(--muted) }
/* One beat when a number really changes, applied by live.js and taken off
   again when the animation ends. */
.num--pulse { animation: numberPulse 520ms ease-out 1 }
.asof__count { font-family: var(--data); font-variant-numeric: tabular-nums; letter-spacing: -0.03em }

/* ---------- The server browser ---------- */
.browser { display: flex; flex-direction: column; margin: 0 calc(var(--gutter) * -1) }
.srv {
  position: relative; display: grid; grid-template-columns: minmax(0, 1fr) 118px;
  gap: 6px 14px; align-items: start; padding: 13px var(--gutter) 13px 17px;
  color: var(--ink); border-bottom: 1px solid var(--divider);
}
.srv:hover { text-decoration: none; background: var(--surface) }
/* A server with people on it is the one you want, so it is the loud row. */
.srv--live { background: var(--surface) }
.srv--live::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--ink);
}
.srv--offline { color: var(--muted) }
.srv__head { grid-column: 1; display: flex; align-items: baseline; gap: 6px 10px; flex-wrap: wrap; min-width: 0 }
.srv__name { font-family: var(--display); font-weight: 700; font-size: 20px; line-height: 1.1 }
.srv__count { grid-column: 2; grid-row: 1 / span 2; display: flex; flex-direction: column; gap: 5px; align-items: flex-end }
.srv__count .pill { font-size: 13px }
.srv__where { grid-column: 1 }
.srv__note { grid-column: 1 / -1; font-size: 14px; color: var(--muted) }
.srv .fbar { grid-column: 1 / -1 }
.srv__foot { grid-column: 1 / -1; display: flex; justify-content: space-between; gap: 4px 14px; flex-wrap: wrap }
.srv__ping { font-family: var(--data); font-size: 12px; color: var(--muted2) }
.pbar { display: block; width: 118px; height: 8px }
.pbar__track { fill: var(--raised) }
.pbar__fill { fill: var(--ink) }
.srv--stale .pbar__fill { fill: var(--amber-ink) }
.srv--offline .pbar__fill, .srv--rejected .pbar__fill { fill: var(--edge) }

/* ---------- Promotions and honours as events ---------- */
.events { display: grid; grid-template-columns: 1fr; gap: 10px }
.event {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  column-gap: 16px; align-items: center; padding: 14px 16px;
  background: var(--surface); border-left: 3px solid var(--border);
}
/* Every cell is placed by hand: an auto placed grid puts the headline under
   the glyph the moment a card has one child fewer than the last one. */
.event__glyph { grid-column: 1; grid-row: 1 / span 3; display: flex; color: var(--amber-ink) }
.event__kicker { grid-column: 2; grid-row: 1 }
.event__title { grid-column: 2; grid-row: 2 }
.event__when { grid-column: 2; grid-row: 3 }
/* An honour says what it is called, what it is for, and when it was won. The
   middle line is the plain one, so it is always there (DECISIONS.md,
   2026-09-19): a name on its own would be a term with nothing to decode it. */
.event--honour .event__glyph { grid-row: 1 / span 3 }
.event--honour .event__title { grid-row: 1 }
.event__what { grid-column: 2; grid-row: 2 }
.event--honour .event__when { grid-row: 3 }
.event__what { color: var(--ink); font-size: 14px }
.event--unearned .event__what { color: var(--muted) }
.event__kicker {
  font-family: var(--display); font-weight: 700; font-size: 12px;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted2);
}
.event__title { font-family: var(--display); font-weight: 900; font-size: 24px; line-height: 1.05 }
.event__when { color: var(--muted); font-size: 14px }
/* The featured server is the one to join tonight, so it is the lead of the
   browser rather than another row with a word beside it. */
.srv--featured { padding-top: 18px; padding-bottom: 18px }
.srv--featured .srv__name { font-size: 26px }
.srv--featured .pill { font-size: 16px }
.srv--featured .pbar { height: 12px }

/* Five honours the same size as a promotion turn an achievement into
   paperwork, so the set is compact and the promotion is the event. */
.event--honour { padding: 10px 14px; column-gap: 12px }

/* One event panel, then a compact history. Three cards that look the same
   make a promotion look like a settings log. */
.event--latest {
  border-left-color: var(--ink); padding: 22px 20px 24px;
  background:
    linear-gradient(135deg, var(--raised) 0%, var(--surface) 62%);
  column-gap: 20px;
}
.event--latest .event__kicker { color: var(--ink); font-size: 13px }
.event--latest .event__title { font-size: var(--type-display) }
.event--latest .event__when { font-size: 15px }
.event--latest .event__glyph { color: var(--ink) }
.event--unearned { background: transparent; border-left-color: var(--divider) }
.event--unearned .event__glyph { color: var(--muted2) }
.event--unearned .event__title { color: var(--muted) }

/* ---------- The two doors ---------- */
/* Auto margins centre the dialog and still let a tall one scroll, which
   align-items: center does not. */
.doors { overflow-y: auto; align-items: flex-start; padding: 20px var(--gutter) 28px }
.doors__inner { max-width: 840px; gap: 12px; margin-block: auto }
.doors__pair { display: grid; grid-template-columns: 1fr; gap: 12px }
.door {
  display: block; padding: 0; overflow: hidden; cursor: pointer; text-align: left;
  border: 1px solid var(--edge); background: var(--hero-bg); color: var(--hero-ink);
  font-family: var(--body); min-height: var(--tap);
}
.door:hover, .door:focus-visible { border-color: var(--hero-ink) }
.door__art { position: relative; display: block; height: 138px; overflow: hidden }
.door__wash {
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(15, 13, 12, 0) 0%, rgba(15, 13, 12, 0.88) 100%);
}
.door__body { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; padding: 14px 16px 16px }
.door__q { font-family: var(--display); font-weight: 900; font-size: var(--type-display); line-height: 1.02 }
.door__pick {
  display: inline-flex; align-items: center; min-height: 38px; padding: 0 14px;
  background: var(--red-fill); color: var(--red-fill-ink); font-size: 16px; font-weight: 500;
}
.door__note { color: var(--hero-muted); font-size: 14px }

/* ---------- The club night poster ---------- */
.poster {
  position: relative; display: flex; align-items: flex-end; overflow: hidden;
  min-height: 300px; margin: 0 calc(var(--gutter) * -1);
  background: var(--hero-bg); color: var(--hero-ink);
}
.poster__media { position: absolute; inset: 0 }
.poster__wash {
  position: absolute; inset: 0; z-index: 2;
  background: linear-gradient(180deg,
    rgba(15, 13, 12, 0.15) 0%, rgba(15, 13, 12, 0.6) 40%, rgba(15, 13, 12, 0.96) 100%);
}
.poster__body { position: relative; z-index: 3; width: 100%; padding: 26px var(--gutter) 24px }
.poster__kicker {
  font-size: 13px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--hero-muted);
}
.poster .club__date { color: var(--hero-ink); margin: 6px 0 2px }
.poster__where { color: var(--hero-muted); font-size: 15px }
.poster .bignum { margin-bottom: 2px }
.poster .bignum__value { color: var(--hero-ink) }
.poster .bignum__label { color: var(--hero-muted) }
.poster__joke { color: var(--hero-muted); font-size: 16px; margin-bottom: 16px }

/* ---------- Small things the new layout needs ---------- */
.band__more { margin-top: 14px }
.searchline--foot { margin-top: 28px }

/* The logo warms up once, like a monitor finding its picture. Nothing else on
   the chrome is retro and nothing repeats. */
.brand { position: relative }
.brand::after {
  content: ""; position: absolute; inset: -2px -4px; background: var(--bg);
  pointer-events: none; opacity: 0;
  animation: crtVeil 820ms steps(1, end) 1 both;
}

@media (prefers-reduced-motion: reduce) {
  .ticker { display: none }
  .brand::after, .num--pulse, .ticker__track { animation: none }
}

@media (min-width: 900px) {
  .srv {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1.5fr) minmax(0, 1.1fr) 150px;
    align-items: center; row-gap: 4px;
  }
  .srv__head { grid-column: 1; grid-row: 1 }
  .srv__where { grid-column: 2; grid-row: 1 }
  .srv__foot { grid-column: 3; grid-row: 1; justify-content: flex-start }
  .srv__count { grid-column: 4; grid-row: 1 / span 1 }
  .srv .fbar, .srv__note { grid-column: 1 / 4; grid-row: 2 }
  .pbar, .srv__count { width: 150px }
}

@media (min-width: 700px) {
  .hero--match { min-height: 58vh; margin-left: calc(var(--gutter-wide) * -1); margin-right: calc(var(--gutter-wide) * -1) }
  .hero__body { padding: 40px var(--gutter-wide) 34px; max-width: 760px }
  .browser, .poster { margin: 0 calc(var(--gutter-wide) * -1) }
  .poster__body { padding: 34px var(--gutter-wide) 30px; max-width: 700px }
  .srv { padding-left: calc(var(--gutter-wide) + 3px); padding-right: var(--gutter-wide) }
  .doors__pair { grid-template-columns: 1fr 1fr }
  .door__art { height: 170px }
  .events { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)) }
}

/* ---------- Small print, one step up ---------- */
/* Round 1 of the review: the metadata was 14px grey on near black and read
   as a form. It clears the contrast table either way; this is about size. */
.meta, .srv__where, .mrow__meta, .record__meta, .ticker__item { font-size: 15px }
.note, .stat__note, .srv__note, .kicker { font-size: 16px }
.hero--match .kicker { font-size: 13px }
.stat__note, .srv__ping, .ticker__stamp, .event__kicker { font-size: 13px }
