/* lobby.cx — visual target: design/mockups/lobbycx.html
   No inline styles anywhere: the CSP forbids them (style-src 'self'). */

@font-face { font-family: 'Silkscreen'; src: url('/static/fonts/silkscreen-latin-400-normal.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'JetBrains Mono'; src: url('/static/fonts/jetbrains-mono-latin-400-normal.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'JetBrains Mono'; src: url('/static/fonts/jetbrains-mono-latin-700-normal.woff2') format('woff2'); font-weight: 700; font-display: swap; }

/* ---------- tokens ---------- */
:root {
  --bg: #e7d9b4;
  --bg-panel: #f1e7c9;
  --bg-inset: #dccb9c;
  --ink: #2b2110;
  --ink-dim: #6c5c3c;
  --line: #b6a06a;
  --accent: #3d6b5c;
  --accent-ink: #f5f1e2;
  --link: #3a5fae;
  --visited: #6b3fa0;
  --danger: #a8452b;
  --chip-ink: #fffaf0;
  --chip-violet: #6f5f95;
  --chip-blue: #4f7096;
  --chip-rust: #a8452b;
  --chip-gold: #8a7526;
  --chip-green: #4c7a56;
  --chip-brown: #6c5c3c;
  --chip-rose: #9a4a6b;
  --chip-teal: #2f7a7a;
  --chip-slate: #55606e;
  --dot: rgba(43, 33, 16, .06);
  --lcd-bg: #14110a;
  --lcd-ink: #8ff05a;
  --lcd-ghost: rgba(143, 240, 90, .07);
  --lcd-matrix: radial-gradient(circle at 1.5px 1.5px, var(--lcd-ghost) 1px, transparent 0);
  /* Type (design pass, 2026-10-09): Verdana for anything you read, Tahoma for small labels and the
     header's links, mono for controls (buttons, tabs, chips) and page titles, the LCD displays in the
     same mono, Silkscreen for the wordmark and section labels, Courier New for codes. Text sizes are
     10 (chips and badges), 11, 12, 13 and 15px only. */
  --sans: Verdana, Geneva, Tahoma, sans-serif;
  --ui: Tahoma, Verdana, Geneva, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, monospace;
  --lcd: var(--mono);
  --code: 'Courier New', Courier, monospace;
  --pixel: 'Silkscreen', monospace;
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #171208; --bg-panel: #211a10; --bg-inset: #2a2013;
    --ink: #e8dcc0; --ink-dim: #a5926a; --line: #4a3c22;
    --accent: #5fae97; --accent-ink: #0f1a15;
    --link: #7fa8ff; --visited: #b389e0; --danger: #d97a55;
    --chip-violet: #9a89c9; --chip-blue: #7ea3c9; --chip-rust: #d97a55;
    --chip-gold: #c9ac4f; --chip-green: #79b489; --chip-brown: #a5926a;
    --chip-rose: #d98aab; --chip-teal: #6cc0bd; --chip-slate: #9aa5b3; --chip-ink: #171208;
    --dot: rgba(232, 220, 192, .05);
    --lcd-bg: #060503;
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --bg: #171208; --bg-panel: #211a10; --bg-inset: #2a2013;
  --ink: #e8dcc0; --ink-dim: #a5926a; --line: #4a3c22;
  --accent: #5fae97; --accent-ink: #0f1a15;
  --link: #7fa8ff; --visited: #b389e0; --danger: #d97a55;
  --chip-violet: #9a89c9; --chip-blue: #7ea3c9; --chip-rust: #d97a55;
  --chip-gold: #c9ac4f; --chip-green: #79b489; --chip-brown: #a5926a;
    --chip-rose: #d98aab; --chip-teal: #6cc0bd; --chip-slate: #9aa5b3; --chip-ink: #171208;
  --dot: rgba(232, 220, 192, .05);
  --lcd-bg: #060503;
  color-scheme: dark;
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
/* Room for the scrollbar is kept on every page, so going from a short page to a long one
   never slides the whole centered layout sideways. */
html { -webkit-text-size-adjust: 100%; scrollbar-gutter: stable; }
body {
  margin: 0 auto;
  max-width: 1180px;
  padding: 24px 16px;
  background-color: var(--bg);
  background-image: radial-gradient(circle at 1px 1px, var(--dot) 1px, transparent 0);
  background-size: 15px 15px;
  color: var(--ink);
  font-family: var(--sans);
  font-size: 13px;
  line-height: 1.5;
}
h1 { font-family: var(--mono); font-weight: 700; margin: 0; text-wrap: balance; letter-spacing: -.01em; }
h2, h3 { font-family: var(--ui); font-weight: 700; margin: 0; text-wrap: balance; }
h1 { font-size: 15px; }
a { color: var(--link); }
a:visited { color: var(--visited); }
button, input, textarea, select { font: inherit; color: inherit; }
/* iOS zooms the page into any text field under 16px when it's focused (which pushed the chat's send
   button off-screen), so on touch screens text fields are at least that. It beats the smaller sizes
   some fields set on purpose. Zoom itself stays allowed: people need pinch-zoom. */
@media (pointer: coarse) {
  input:not([type="checkbox"], [type="radio"], [type="range"], [type="hidden"], [type="submit"], [type="button"], [type="reset"], [type="file"], [type="color"]),
  textarea, select { font-size: 16px !important; }
}
:focus-visible { outline: 2px dashed var(--accent); outline-offset: 2px; }
/* The hidden attribute must always win. Without this, any class that sets display
   (e.g. display: flex) silently un-hides the element. */
[hidden] { display: none !important; }
/* !important so no component rule can resize it: `.field input { width: 100% }` once
   made the hidden genre radios page-wide, and the page slid sideways when the browser
   scrolled to one to say "please select one of these options". */
.visually-hidden {
  position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important;
  overflow: hidden !important; clip: rect(0 0 0 0) !important; white-space: nowrap !important; border: 0 !important;
}

/* ---------- header ---------- */
/* min-height: the same height whether the right side holds a button or only links
   (the log-in and sign-up pages), so nothing below moves between pages. */
.site-header {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin-bottom: 20px; min-height: 34px;
}
.wordmark {
  display: flex; align-items: center; gap: 9px;
  font-family: var(--pixel); font-size: 20px; letter-spacing: .02em;
  color: var(--accent); text-decoration: none;
}
.wordmark:visited { color: var(--accent); }
/* The tag (a room's name, a page's name) is cut off rather than wrapped, so a long one never
   makes the header taller on one page than on the next. */
.wordmark { min-width: 0; white-space: nowrap; }
.wordmark .tag { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.header-actions { flex-shrink: 0; }
/* A long username (up to 40 characters) is cut off rather than pushing the links onto another line. */
.header-user { max-width: 14em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Phones: always two rows (wordmark, then links), each a fixed height, whatever the links are:
   the links never wrap (an admin's five didn't fit), and the username gives way first. */
@media (max-width: 600px) {
  .site-header { flex-direction: column; align-items: stretch; flex-wrap: nowrap; gap: 8px; }
  .site-header .wordmark { min-height: 26px; }
  .header-actions { min-height: 34px; flex-wrap: nowrap; gap: 10px; min-width: 0; }
  .header-actions > * { flex-shrink: 0; white-space: nowrap; }
  .header-actions > .header-user { flex-shrink: 1; min-width: 0; }
}
.wordmark .tld { font-family: var(--ui); font-size: 13px; color: var(--ink-dim); letter-spacing: 0; }
.wordmark .tag { font-family: var(--ui); font-size: 11px; color: var(--ink-dim); }
/* facemark: the .cx read as an emoticon — x x eyes, a curved smile */
.facemark { position: relative; flex-shrink: 0; width: 22px; height: 22px; border-radius: 50%; background: var(--accent); }
.facemark::before {
  content: "x x"; position: absolute; top: 5px; left: 0; right: 0;
  text-align: center; font-family: var(--lcd); font-size: 7px; letter-spacing: 2px;
  color: var(--accent-ink); line-height: 1;
}
.facemark::after {
  content: ""; position: absolute; bottom: 5px; left: 50%; transform: translateX(-50%);
  width: 8px; height: 4px; border-bottom: 2px solid var(--accent-ink); border-radius: 0 0 8px 8px;
}
.header-actions { display: flex; gap: 14px; align-items: center; font-family: var(--ui); font-size: 12px; }
.header-actions a:not(.btn) { text-decoration: none; border-bottom: 1px dotted var(--link); }
.header-actions form { margin: 0; }
.link-button {
  background: none; border: none; padding: 0; cursor: pointer;
  font-family: var(--ui); font-size: 12px; color: var(--link); border-bottom: 1px dotted var(--link);
}

/* ---------- buttons ---------- */
.btn {
  display: inline-block; cursor: pointer; text-decoration: none; border-radius: 0;
  font-family: var(--mono); font-size: 12px; padding: 6px 14px;
  background: var(--accent); color: var(--accent-ink); border: 2px outset var(--accent);
}
.btn:visited { color: var(--accent-ink); }
.btn:active { border-style: inset; }
.btn--ghost { background: var(--bg-panel); color: var(--ink); border-color: var(--line); }
.btn--ghost:visited { color: var(--ink); }
/* Once full-width; now a main button sized to its label, like the period's, kept clear of the stretch in flex columns. */
.btn--block { align-self: flex-start; padding: 7px 18px; }
.btn--danger { background: var(--danger); border-color: var(--danger); }

/* ---------- panels, notes, sections ---------- */
.panel { background: var(--bg-panel); border: 2px outset var(--line); padding: 14px; }
/* The browse pages' one-line tagline (browse-top.eta): the same on home, /rooms and /search, so nothing moves between them. */
.tagline { margin: 0 0 12px; font-family: var(--ui); font-size: 12px; color: var(--ink-dim); white-space: pre-wrap; }
.note {
  font-size: 13px; color: var(--ink-dim); max-width: 60ch;
  margin: 0 0 22px; padding: 10px 14px;
  border: 1px dashed var(--line); background: var(--bg-panel);
}
.note--inset { background: var(--bg-inset); font-size: 12px; line-height: 1.55; }
/* The browse pages' guest note: wide enough to stay one line on desktop with its "how it works" link,
   and the link never splits across lines. */
.note--guest { max-width: 80ch; }
.note--guest a { white-space: nowrap; }
.note .glyph { font-family: var(--ui); color: var(--accent); font-weight: 700; margin-right: 6px; }
.section-label {
  display: flex; align-items: center; gap: 8px; margin: 26px 0 10px;
  font-family: var(--pixel); font-size: 14px; letter-spacing: .04em; text-transform: uppercase; color: var(--ink-dim);
}
.section-label::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.empty-state { margin: 0; padding: 4px 0; font-size: 13px; font-style: italic; color: var(--ink-dim); }

/* ---------- dialog: one framed panel, settings in group boxes (account, room settings, admin) ---------- */
.dialog { padding: 16px 18px 4px; }
.dialog__head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 20px; padding-bottom: 10px; border-bottom: 1px solid var(--line); }
.dialog__head .form-note { margin: 0; }
.control-panel { columns: 2 340px; column-gap: 18px; padding-top: 8px; }
.group {
  display: flex; flex-direction: column; gap: 12px;
  break-inside: avoid; margin: 0 0 24px; padding: 18px 14px 14px;
  border: 2px groove var(--line);
}
.group > * { margin-top: 0; margin-bottom: 0; }
.group > .btn { align-self: flex-start; }
/* In the flow (not absolutely placed, which column layout draws badly), pulled up onto the top border like a legend. */
.group > .group__title {
  align-self: flex-start; margin: -27px 0 0 -5px; padding: 0 5px;
  font-family: var(--ui); font-size: 12px; font-weight: 700; line-height: 16px; color: var(--ink); background: var(--bg-panel);
}
.group--danger .group__title { color: var(--danger); }
.group .community-list { border-width: 1px; border-style: solid; }
.tally { width: 100%; border-collapse: collapse; font-size: 13px; }
.tally th, .tally td { padding: 5px 4px; border-bottom: 1px dashed var(--line); text-align: left; font-weight: 400; }
.tally td { text-align: right; font-family: var(--lcd); font-weight: 700; }
.tally tr:last-child th, .tally tr:last-child td { border-bottom: 0; }
.tally .is-hot td, .tally .is-hot th a { color: var(--danger); }

/* ---------- flash / form errors ---------- */
.flash {
  font-family: var(--ui); font-size: 12px; padding: 9px 12px; margin-bottom: 14px;
  border: 1px solid var(--line); background: var(--bg-inset);
}
.flash--error { border-color: var(--danger); color: var(--danger); }
.flash--ok { border-color: var(--accent); color: var(--accent); }
/* A form's button with its "saved" line beside it (partials/form-status.eta). The line's space is the
   row the button already makes, so it appears without moving anything; messages stay short to fit. */
.form-actions { display: flex; align-items: center; gap: 10px; min-width: 0; }
.form-actions .btn { flex: none; }
.form-status { min-width: 0; font-family: var(--ui); font-size: 11px; line-height: 14px; color: var(--accent); overflow-wrap: anywhere; }
.check-row { display: flex; gap: 8px; align-items: flex-start; font-size: 13px; margin: 4px 0 12px; cursor: pointer; }
.check-row input { margin-top: 3px; flex: none; }
.report-context { margin: 8px 0; font-size: 13px; }
.report-context summary { cursor: pointer; color: var(--ink-dim); }
.report-context__lines { list-style: none; margin: 6px 0 0; padding: 8px 10px; background: var(--bg-inset); border: 1px solid var(--line); max-height: 280px; overflow-y: auto; overflow-wrap: anywhere; }
.report-context__lines li + li { margin-top: 3px; }
.allowed-list { list-style: none; margin: 8px 0 12px; padding: 0; display: flex; flex-wrap: wrap; gap: 6px 16px; }
.allowed-list li { display: flex; gap: 6px; align-items: baseline; }
.flash p { margin: 0; }
/* "added … [undo]" after a single add to a playlist (partials/added-flash.eta). */
.added-flash { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: baseline; }
.added-flash span { overflow-wrap: anywhere; min-width: 0; }
.added-flash form { margin: 0; }
.flash p + p { margin-top: 4px; }

/* ---------- genre chips ---------- */
.genre-chip {
  display: inline-flex; align-items: center; gap: 4px; width: fit-content; padding: 3px 7px;
  font-family: var(--ui); font-size: 10px; font-weight: 700;
  color: var(--chip-ink); background: var(--chip-brown);
}
/* Palette keys come from GENRE_COLORS (rooms/genres.ts): a fixed set, never user text. */
.chip--violet { background: var(--chip-violet); }
.chip--blue { background: var(--chip-blue); }
.chip--rust { background: var(--chip-rust); }
.chip--gold { background: var(--chip-gold); }
.chip--green { background: var(--chip-green); }
.chip--brown { background: var(--chip-brown); }
.chip--rose { background: var(--chip-rose); }
.chip--teal { background: var(--chip-teal); }
.chip--slate { background: var(--chip-slate); }
/* Pixel genre icons (public/icons/genre-<icon>.svg), drawn in the text's colour on chips and the
   browse filters. An admin picks a genre's icon from the set in rooms/genres.ts (GENRE_ICONS); each
   one needs its file and its line here (test/unit/genre-icons.test.ts checks all three match). */
.gi::before {
  content: ""; flex: none; width: 12px; height: 12px; background: currentColor;
  -webkit-mask: var(--gi) no-repeat; mask: var(--gi) no-repeat;
}
.gi--guitar { --gi: url('/static/icons/genre-guitar.svg'); }
.gi--waves { --gi: url('/static/icons/genre-waves.svg'); }
.gi--cassette { --gi: url('/static/icons/genre-cassette.svg'); }
.gi--headphones { --gi: url('/static/icons/genre-headphones.svg'); }
.gi--notes { --gi: url('/static/icons/genre-notes.svg'); }
.gi--record { --gi: url('/static/icons/genre-record.svg'); }
.gi--microphone { --gi: url('/static/icons/genre-microphone.svg'); }
.gi--piano { --gi: url('/static/icons/genre-piano.svg'); }
.gi--drum { --gi: url('/static/icons/genre-drum.svg'); }
.gi--turntable { --gi: url('/static/icons/genre-turntable.svg'); }
.gi--radio { --gi: url('/static/icons/genre-radio.svg'); }
.gi--bolt { --gi: url('/static/icons/genre-bolt.svg'); }
.gi--skull { --gi: url('/static/icons/genre-skull.svg'); }
.gi--cowboy-hat { --gi: url('/static/icons/genre-cowboy-hat.svg'); }
.gi--palm { --gi: url('/static/icons/genre-palm.svg'); }
.gi--moon { --gi: url('/static/icons/genre-moon.svg'); }
.gi--sun { --gi: url('/static/icons/genre-sun.svg'); }
.gi--heart { --gi: url('/static/icons/genre-heart.svg'); }
.gi--globe { --gi: url('/static/icons/genre-globe.svg'); }
.gi--star { --gi: url('/static/icons/genre-star.svg'); }
.gi--coffee { --gi: url('/static/icons/genre-coffee.svg'); }
.gi--flame { --gi: url('/static/icons/genre-flame.svg'); }
.gi--drop { --gi: url('/static/icons/genre-drop.svg'); }
.gi--mountain { --gi: url('/static/icons/genre-mountain.svg'); }
.gi--wind { --gi: url('/static/icons/genre-wind.svg'); }
.gi--teapot { --gi: url('/static/icons/genre-teapot.svg'); }
.gi--lotus { --gi: url('/static/icons/genre-lotus.svg'); }
.gi--capture-ball { --gi: url('/static/icons/genre-capture-ball.svg'); }
.gi--handheld { --gi: url('/static/icons/genre-handheld.svg'); }
.gi--egg { --gi: url('/static/icons/genre-egg.svg'); }
.gi--gamepad { --gi: url('/static/icons/genre-gamepad.svg'); }
.gi--die { --gi: url('/static/icons/genre-die.svg'); }
.gi--ghost { --gi: url('/static/icons/genre-ghost.svg'); }
.gi--ufo { --gi: url('/static/icons/genre-ufo.svg'); }
.gi--alien { --gi: url('/static/icons/genre-alien.svg'); }
.gi--cat { --gi: url('/static/icons/genre-cat.svg'); }
.gi--frog { --gi: url('/static/icons/genre-frog.svg'); }
.gi--duck { --gi: url('/static/icons/genre-duck.svg'); }
.gi--mushroom { --gi: url('/static/icons/genre-mushroom.svg'); }
.gi--cactus { --gi: url('/static/icons/genre-cactus.svg'); }
.gi--sprout { --gi: url('/static/icons/genre-sprout.svg'); }
.gi--blossom { --gi: url('/static/icons/genre-blossom.svg'); }
.gi--leaf { --gi: url('/static/icons/genre-leaf.svg'); }
.gi--snowflake { --gi: url('/static/icons/genre-snowflake.svg'); }
.gi--cloud { --gi: url('/static/icons/genre-cloud.svg'); }
.gi--ramen { --gi: url('/static/icons/genre-ramen.svg'); }
.gi--pizza { --gi: url('/static/icons/genre-pizza.svg'); }
.gi--potion { --gi: url('/static/icons/genre-potion.svg'); }
.gi--eight-ball { --gi: url('/static/icons/genre-eight-ball.svg'); }
.gi--eye { --gi: url('/static/icons/genre-eye.svg'); }
.gi--crown { --gi: url('/static/icons/genre-crown.svg'); }
.gi--rocket { --gi: url('/static/icons/genre-rocket.svg'); }
.gi--floppy { --gi: url('/static/icons/genre-floppy.svg'); }
.gi--tv { --gi: url('/static/icons/genre-tv.svg'); }
.gi--sword { --gi: url('/static/icons/genre-sword.svg'); }

/* ---------- LCD bits: ticker, hit counter, cost bar ---------- */
.ticker { background-color: var(--lcd-bg); background-image: var(--lcd-matrix); background-size: 3px 3px; border: 2px inset var(--line); overflow: hidden; white-space: nowrap; padding: 7px 0; margin-bottom: 18px; }
.ticker__track {
  display: inline-block; white-space: pre;
  font-family: var(--lcd); font-size: 12px; letter-spacing: .03em; color: var(--lcd-ink);
  animation: ticker-scroll 24s linear infinite;
}
/* The line, then its repeats (frame.ts adds enough to fill the bar, and sets the duration so the
   speed is the same whatever the length): two equal halves, scrolled by one half, so it loops. */
.ticker__sep { opacity: .55; }
@keyframes ticker-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .ticker__track { animation: none; padding-left: 12px; }
  .ticker__echo, .ticker__sep { display: none; }
}

.site-footer { display: flex; flex-wrap: wrap; gap: 18px; align-items: center; margin-top: 24px; }
.site-footer__links { font-family: var(--ui); font-size: 11px; display: flex; gap: 12px; }
.site-footer__est { font-family: var(--ui); font-size: 11px; color: var(--ink-dim); }
.lcd-stat { display: inline-flex; align-items: center; gap: 8px; font-family: var(--ui); font-size: 11px; color: var(--ink-dim); }
.lcd-digits { font-family: var(--lcd); background: var(--lcd-bg); border: 2px inset var(--line); color: var(--lcd-ink); padding: 5px 8px; letter-spacing: 3px; font-weight: 700; }
.cost-bar progress, .cost-row progress {
  appearance: none; width: 130px; height: 13px;
  background: var(--lcd-bg); border: 2px inset var(--line); overflow: hidden;
}
.cost-bar progress::-webkit-progress-bar, .cost-row progress::-webkit-progress-bar { background: var(--lcd-bg); }
.cost-bar progress::-webkit-progress-value, .cost-row progress::-webkit-progress-value { background: var(--lcd-ink); }
.cost-bar progress::-moz-progress-bar, .cost-row progress::-moz-progress-bar { background: var(--lcd-ink); }
.cost-row.is-hot progress::-webkit-progress-value { background: #ffcf5a; }
.cost-row.is-hot progress::-moz-progress-bar { background: #ffcf5a; }
.cost-bar a { font-size: 11px; }

/* ---------- forms ---------- */
.form-card { max-width: 460px; display: flex; flex-direction: column; gap: 16px; padding: 22px; }
.field label, .field .label {
  display: block; margin-bottom: 6px;
  font-family: var(--ui); font-size: 12px; font-weight: 700; color: var(--ink);
}
.field input, .field textarea, .field select {
  width: 100%; padding: 9px 10px; border-radius: 0; resize: vertical;
  font-family: var(--sans); font-size: 13px;
  background: var(--bg-inset); border: 2px inset var(--line); color: var(--ink);
}
.field input::placeholder, .field textarea::placeholder { color: var(--ink-dim); }
.field input[aria-invalid="true"] { border-color: var(--danger); }
.field .hint { font-family: var(--ui); font-size: 11px; color: var(--ink-dim); margin-top: 5px; }
.form-note { font-family: var(--ui); font-size: 11px; color: var(--ink-dim); line-height: 1.6; }

.auth-wrap { display: flex; justify-content: center; padding-block: 20px; }
.auth-card { width: 100%; max-width: 380px; }
.auth-tabs { display: flex; margin-bottom: 16px; border: 2px outset var(--line); overflow: hidden; }
.auth-tab {
  flex: 1; text-align: center; padding: 9px 0; text-decoration: none;
  font-family: var(--mono); font-size: 12px; background: var(--bg-panel); color: var(--ink-dim);
}
.auth-tab:visited { color: var(--ink-dim); }
.auth-tab[aria-current="page"] { background: var(--accent); color: var(--accent-ink); }
.auth-form { display: flex; flex-direction: column; gap: 14px; }

/* ---------- error page ---------- */
.error-page { max-width: 520px; }
.error-page h1 { font-size: 15px; margin-bottom: 10px; }
.error-page .ref { font-family: var(--ui); font-size: 11px; color: var(--ink-dim); }

/* ---------- long-form text (terms, privacy) ---------- */
.prose { max-width: 70ch; }
.prose h1 { font-size: 15px; margin-bottom: 6px; }
.prose h2 { font-family: var(--ui); font-size: 13px; color: var(--ink); margin: 20px 0 6px; }
.prose p, .prose li { font-size: 13px; }
.prose ul { padding-left: 20px; }
.prose__updated { margin: 0 0 10px; font-size: 11px !important; color: var(--ink-dim); }

/* ---------- browse ---------- */
.browse-tools { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.genre-filter { display: flex; flex-wrap: wrap; gap: 6px; }
.filter-chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-family: var(--mono); font-size: 11px; padding: 5px 9px; text-decoration: none;
  background: var(--bg-panel); color: var(--ink-dim); border: 2px outset var(--line);
}
.filter-chip:visited { color: var(--ink-dim); }
.filter-chip[aria-current="page"] { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); border-style: inset; }
.search-form { display: flex; gap: 6px; }
.search-form input {
  min-width: 0; width: 200px; padding: 6px 9px; border-radius: 0;
  font-family: var(--ui); font-size: 12px; background: var(--bg-inset); border: 2px inset var(--line); color: var(--ink);
}

.room-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 12px; }
.room-card {
  position: relative; display: flex; flex-direction: column; gap: 8px; padding: 14px;
  background: var(--bg-panel); border: 2px outset var(--line);
}
.room-card:hover, .room-card:focus-within { border-color: var(--accent); }
.room-card:active { border-style: inset; }
/* The whole card is clickable via the name link's stretched hit area. */
.room-card__link::after { content: ""; position: absolute; inset: 0; }
.curated-badge { position: absolute; top: 10px; right: 10px; font-family: var(--ui); font-size: 10px; color: var(--ink-dim); }
.room-name { font-size: 15px; font-weight: 700; color: var(--link); text-decoration: none; overflow-wrap: anywhere; }
.room-name:visited { color: var(--visited); }
.room-name:hover { text-decoration: underline; }
.room-desc { font-size: 12px; color: var(--ink-dim); flex: 1; margin: 0; overflow-wrap: anywhere; }
.room-np { margin: 0; font-size: 12px; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.room-np__label { color: var(--ink-dim); }
.room-foot { display: flex; justify-content: space-between; align-items: center; font-family: var(--ui); font-size: 11px; color: var(--ink-dim); }

.community-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; border: 2px outset var(--line); }
.community-row {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding: 10px 14px; background: var(--bg-panel); border-bottom: 1px solid var(--line); font-size: 13px;
}
.community-row:last-child { border-bottom: none; }
.community-row .room-name { font-size: 13px; }
.community-main { display: flex; flex-direction: column; min-width: 0; }
.community-desc { font-size: 12px; color: var(--ink-dim); overflow-wrap: anywhere; }
.community-meta { display: flex; gap: 12px; align-items: center; flex-shrink: 0; font-family: var(--ui); font-size: 11px; color: var(--ink-dim); }

/* ---------- room ---------- */
.room-layout { display: grid; grid-template-columns: 200px minmax(0, 1fr) 260px; gap: 14px; align-items: start; }
@media (max-width: 820px) { .room-layout { grid-template-columns: 1fr; } .rail { order: 3; } }
.rail { background: var(--bg-panel); border: 2px outset var(--line); padding: 12px; display: flex; flex-direction: column; }
.rail h3, .stage h3, .chat-panel h3 { font-family: var(--ui); font-size: 12px; color: var(--ink); margin-bottom: 10px; }
.rail-gap { margin-top: 16px; }
.rail-room { display: flex; align-items: center; gap: 6px; font-size: 12px; padding: 6px 4px; color: var(--ink); text-decoration: none; overflow-wrap: anywhere; }
.rail-room:visited { color: var(--ink); }
.rail-room:hover { background: var(--bg-inset); }
.rail-room.active { background: var(--bg-inset); font-weight: 700; }
.rail-room .n { margin-left: auto; font-family: var(--ui); font-size: 10px; color: var(--ink-dim); }

.stage { background: var(--bg-panel); border: 2px outset var(--line); padding: 16px; display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.room-title { font-size: 15px; margin: 0 2px 0 0; min-width: 0; overflow-wrap: anywhere; }
.room-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.room-badge { font-family: var(--ui); font-size: 10px; color: var(--ink-dim); border: 1px dashed var(--line); padding: 2px 6px; }
.room-host { font-family: var(--ui); font-size: 11px; color: var(--ink-dim); }
.room-host strong { color: var(--ink); font-weight: 700; }
.room-settings-link { margin-left: auto; font-family: var(--ui); font-size: 11px; }
.np-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
/* The faceplate: what's playing, the clock and the listeners on one LCD, like a radio's display.
   The title is cut off rather than wrapped, so a long one never changes the faceplate's height. */
.faceplate {
  display: flex; align-items: center; gap: 14px; padding: 10px 14px;
  background-color: var(--lcd-bg); background-image: var(--lcd-matrix); background-size: 3px 3px;
  border: 2px inset var(--line); color: var(--lcd-ink); font-family: var(--lcd);
}
.fp-label { font-size: 11px; opacity: .65; letter-spacing: .04em; }
/* Hidden, not removed, while nothing plays: the faceplate keeps its height. */
.fp-label.is-idle { visibility: hidden; }
.np-title { font-size: 15px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.np-sub { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; font-size: 11px; opacity: .8; }
/* The clock: a fixed width, so ticking (or an hour-long track) never moves the text beside it. */
.np-clock { display: inline-block; min-width: 15ch; letter-spacing: 1px; white-space: nowrap; font-variant-numeric: tabular-nums; }
.queue-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.queue-head h3 { margin: 0; font-family: var(--mono); font-weight: 400; }
.add-track { display: flex; gap: 6px; }
.add-track input {
  min-width: 0; width: 220px; padding: 7px 9px; border-radius: 0;
  font-family: var(--ui); font-size: 12px; background: var(--bg-inset); border: 2px inset var(--line); color: var(--ink);
}
.add-track input:disabled { opacity: .6; }
.locked-note { font-family: var(--ui); font-size: 11px; color: var(--ink-dim); background: var(--bg-inset); border: 1px dashed var(--line); padding: 8px 10px; margin: 8px 0 0; }

.chat-panel { background: var(--bg-panel); border: 2px outset var(--line); padding: 12px; display: flex; flex-direction: column; min-height: 320px; }
.chat-log { display: flex; flex-direction: column; gap: 7px; font-size: 12px; margin-bottom: 10px; overflow-wrap: anywhere; }
.chat-input-row { display: flex; gap: 6px; }
.chat-input-row input {
  flex: 1; min-width: 0; padding: 8px 9px; border-radius: 0;
  font-family: var(--sans); font-size: 12px; background: var(--bg-inset); border: 2px inset var(--line); color: var(--ink);
}
.chat-input-row input:disabled { opacity: .5; }
.chat-input-row button {
  flex-shrink: 0; padding: 0 12px; border-radius: 0; cursor: pointer;
  font-family: var(--mono); font-size: 11px; background: var(--accent); color: var(--accent-ink); border: 2px outset var(--accent);
}
.chat-input-row button:disabled { background: var(--bg-inset); color: var(--ink-dim); border-color: var(--line); cursor: default; }

/* ---------- room form: genre radios as chips, checkbox as a switch (no JS) ---------- */
.chip-picker-field { border: 0; padding: 0; margin: 0; }
.chip-picker { display: flex; gap: 6px; flex-wrap: wrap; position: relative; }
/* The hidden radios sit at the chips' bottom-left, so the browser's "please select"
   bubble points at the chips. */
.chip-radio { left: 0; bottom: 0; }
.chip-choice {
  cursor: pointer; padding: 6px 10px; font-family: var(--mono); font-size: 11px;
  border: 2px outset var(--line); background: var(--bg-inset); color: var(--ink-dim);
}
/* Admin → genres: the icon picker, the icons alone (each named for screen readers and on hover). */
.icon-picker { display: flex; flex-direction: column; gap: 6px; }
.icon-picker__group { margin: 4px 0 0; font-family: var(--ui); font-size: 11px; color: var(--ink-dim); }
.icon-picker .icon-choice { display: inline-flex; align-items: center; justify-content: center; margin: 0; padding: 6px; }
.icon-pick { flex-basis: 100%; }
.icon-pick summary { cursor: pointer; width: fit-content; font-family: var(--ui); font-size: 12px; color: var(--ink-dim); }
.icon-pick[open] summary { margin-bottom: 6px; }
.chip-radio:focus-visible + .chip-choice { outline: 2px dashed var(--accent); outline-offset: 2px; }
.chip-radio:checked + .chip-choice { color: var(--accent-ink); border-style: inset; background: var(--accent); border-color: var(--accent); }
.chip-radio:checked + .chip-choice--brown { color: var(--chip-ink); background: var(--chip-brown); border-color: var(--chip-brown); }
.chip-radio:checked + .chip-choice--violet { color: var(--chip-ink); background: var(--chip-violet); border-color: var(--chip-violet); }
.chip-radio:checked + .chip-choice--blue { color: var(--chip-ink); background: var(--chip-blue); border-color: var(--chip-blue); }
.chip-radio:checked + .chip-choice--rust { color: var(--chip-ink); background: var(--chip-rust); border-color: var(--chip-rust); }
.chip-radio:checked + .chip-choice--gold { color: var(--chip-ink); background: var(--chip-gold); border-color: var(--chip-gold); }
.chip-radio:checked + .chip-choice--green { color: var(--chip-ink); background: var(--chip-green); border-color: var(--chip-green); }
.chip-radio:checked + .chip-choice--rose { color: var(--chip-ink); background: var(--chip-rose); border-color: var(--chip-rose); }
.chip-radio:checked + .chip-choice--teal { color: var(--chip-ink); background: var(--chip-teal); border-color: var(--chip-teal); }
.chip-radio:checked + .chip-choice--slate { color: var(--chip-ink); background: var(--chip-slate); border-color: var(--chip-slate); }
/* The box sits before its label, as checkboxes did; the markup keeps label-then-input. */
.toggle-row { display: flex; flex-direction: row-reverse; align-items: center; justify-content: flex-end; gap: 8px; }
.toggle-row label { font-family: var(--ui); font-size: 12px; font-weight: 700; color: var(--ink); }
.switch {
  appearance: none; flex-shrink: 0; position: relative; cursor: pointer; margin: 0;
  width: 16px; height: 16px; border-radius: 0; background: var(--bg-inset); border: 2px inset var(--line);
}
.switch:checked::after {
  content: ""; position: absolute; left: 3px; top: 0; width: 4px; height: 8px;
  border: solid var(--ink); border-width: 0 2px 2px 0; transform: rotate(45deg);
}

/* ---------- player (YouTube requires a visible player of at least 200x200) ---------- */
/* The video sits in a bezel: an inset screen inside a raised frame. */
.player-wrap { position: relative; width: calc(100% - 4px); max-width: 480px; aspect-ratio: 16 / 9; min-height: 200px; margin: 2px; background: var(--lcd-bg); border: 2px inset var(--line); outline: 2px outset var(--line); outline-offset: 2px; }
.player, .player-wrap iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.player-note { position: absolute; inset: 0; margin: 0; display: grid; place-items: center; font-family: var(--lcd); font-size: 12px; color: var(--lcd-ink); }
.player-controls { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
/* Fixed width in both states, so toggling mute never moves anything else. */
.unmute-btn { width: 8.5em; padding: 8px 0; font-size: 13px; text-align: center; white-space: nowrap; }
.unmute-btn.is-live { background: var(--bg-panel); color: var(--ink); border-color: var(--line); }
.unmute-btn::before {
  content: ""; display: inline-block; width: 11px; height: 11px; margin-right: 7px; vertical-align: -1px;
  background: currentColor; clip-path: polygon(0 32%, 32% 32%, 72% 0, 72% 100%, 32% 68%, 0 68%);
}

/* Rising-bars volume meter: ten bars stepping up like a right triangle. */
.vol {
  display: flex; align-items: flex-end; gap: 3px; height: 26px; padding: 3px 6px;
  cursor: pointer; touch-action: none; user-select: none;
  background: var(--lcd-bg); border: 2px inset var(--line);
}
.vol:focus-visible { outline: 2px dashed var(--accent); outline-offset: 2px; }
.vol__bar { width: 6px; background: #2a3a1f; transition: background .08s; }
.vol__bar.is-on { background: var(--lcd-ink); }
.vol.is-muted .vol__bar.is-on { background: #4d6b37; }
.vol__bar:nth-child(1) { height: 10%; }
.vol__bar:nth-child(2) { height: 20%; }
.vol__bar:nth-child(3) { height: 30%; }
.vol__bar:nth-child(4) { height: 40%; }
.vol__bar:nth-child(5) { height: 50%; }
.vol__bar:nth-child(6) { height: 60%; }
.vol__bar:nth-child(7) { height: 70%; }
.vol__bar:nth-child(8) { height: 80%; }
.vol__bar:nth-child(9) { height: 90%; }
.vol__bar:nth-child(10) { height: 100%; }
/* Fixed width: "005%" and "100%" take the same space. */
.vol__pct { min-width: 5.2ch; text-align: right; font-size: 12px; padding: 5px 6px; letter-spacing: 2px; }
.vol.is-muted + .vol__pct { color: #4d6b37; }
@media (prefers-reduced-motion: reduce) { .vol__bar { transition: none; } }
.np-listeners { align-self: flex-end; font-size: 11px; opacity: .8; white-space: nowrap; }
.dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); display: inline-block; margin-right: 5px; vertical-align: middle; }

.eq { display: flex; gap: 2px; align-items: flex-end; height: 20px; flex-shrink: 0; }
.eq span { width: 3px; height: 100%; background: var(--lcd-ink); animation: eq-bounce 1.1s ease-in-out infinite; transform-origin: bottom; }
.eq span:nth-child(2) { animation-delay: .15s; }
.eq span:nth-child(3) { animation-delay: .3s; }
.eq span:nth-child(4) { animation-delay: .45s; }
@keyframes eq-bounce { 0%, 100% { transform: scaleY(.35); } 50% { transform: scaleY(1); } }
@media (prefers-reduced-motion: reduce) { .eq span { animation: none; transform: scaleY(.7); } }

/* ---------- chat ---------- */
/* A fixed, capped height that scrolls, instead of growing with the conversation.
   flex: none + min-height: 0 matter: a flex item otherwise refuses to shrink below its content. */
.chat-log {
  list-style: none; margin: 0 0 6px; padding: 0 4px 0 0;
  flex: none; min-height: 0; height: clamp(220px, 50vh, 420px);
  overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin;
}
@media (max-width: 820px) { .chat-log { height: clamp(150px, 30vh, 260px); } }
.chat-line { line-height: 1.45; }
.chat-topic { margin: 0 0 8px; padding-bottom: 6px; border-bottom: 1px dashed var(--line); font-family: var(--ui); font-size: 11px; color: var(--ink-dim); overflow-wrap: anywhere; }
.chat-line .t { font-family: var(--ui); font-size: 10px; color: var(--ink-dim); margin-right: 5px; }
.chat-line .u { font-family: var(--ui); font-weight: 700; color: var(--accent); cursor: default; }
.chat-line .u:focus-visible { outline: 1px dashed var(--accent); outline-offset: 1px; }
.chat-line .badge { font-family: var(--ui); font-size: 10px; padding: 0 3px; border: 1px solid var(--accent); color: var(--accent); vertical-align: 1px; }
.chat-line.sys { color: var(--ink-dim); font-family: var(--ui); font-size: 11px; }
/* The day above each day's first line (client/lib/chat-days.ts): "oct 5" between two dashed rules, like the topic line's. */
.chat-day { display: flex; align-items: center; gap: 8px; margin: 2px 0; font-family: var(--ui); font-size: 10px; color: var(--ink-dim); }
.chat-day::before, .chat-day::after { content: ''; flex: 1; border-top: 1px dashed var(--line); }
.chat-typing { min-height: 1.4em; margin: 0 0 6px; font-family: var(--ui); font-size: 11px; color: var(--ink-dim); }
.chat-error { min-height: 1.3em; margin: 4px 0 0; font-family: var(--ui); font-size: 11px; color: var(--danger); }
.chat-error:empty { min-height: 0; }
.chat-login { display: flex; flex-direction: column; gap: 6px; }
.chat-login input {
  width: 100%; padding: 7px 9px; border-radius: 0;
  font-family: var(--sans); font-size: 12px; background: var(--bg-inset); border: 2px inset var(--line); color: var(--ink);
}
.chat-login .form-note { margin: 2px 0 0; }
/* Hover card: name + status, positioned by script next to the username. */
.user-card {
  position: absolute; z-index: 10; padding: 4px 8px; pointer-events: none;
  font-family: var(--lcd); font-size: 11px; color: var(--lcd-ink); background: var(--lcd-bg); border: 2px outset var(--line);
  max-width: 260px;
}
.user-card .card-name, .user-card .card-status { display: block; }
.user-card .card-status { margin-top: 2px; font-style: italic; overflow-wrap: anywhere; }

/* ---------- "see all" links and pagination ---------- */
.see-all { display: block; margin-top: 8px; font-family: var(--ui); font-size: 12px; text-align: right; }
.rail .see-all { text-align: left; margin-top: 6px; }
.pager { display: flex; gap: 12px; align-items: center; justify-content: space-between; margin-top: 12px; font-family: var(--ui); font-size: 12px; }
.pager .page-of { color: var(--ink-dim); }
/* A read YouTube playlist waiting for add or cancel (partials/import-preview.eta). */
.import-preview { margin-bottom: 14px; border-left: 4px solid var(--accent); }
.import-preview__head { margin: 0 0 8px; font-family: var(--mono); font-size: 13px; font-weight: 400; overflow-wrap: anywhere; }
.import-preview__sample { margin: 8px 0; padding-left: 24px; font-size: 12px; }
.import-preview__sample li { overflow-wrap: anywhere; }
.import-preview__actions { display: flex; gap: 8px; margin-top: 10px; }
.import-preview__actions form { margin: 0; }
/* A playlist's search line (partials/track-list.eta): how many match, and the way back to all. */
.track-search-note { margin: 0 0 8px; font-family: var(--ui); font-size: 12px; color: var(--ink-dim); }
/* Past two pages: first/previous, the jump box, next/last. The sides keep their width when a link is
   missing (page 1, the last page), so the box doesn't move between pages; on phones the box takes its own row. */
.pager--jump { display: grid; grid-template-columns: 1fr auto 1fr; }
.pager__side { display: flex; gap: 12px; flex-wrap: wrap; }
.pager__side--end { justify-content: flex-end; }
.pager__jump { display: flex; gap: 6px; align-items: center; margin: 0; }
.pager__jump input { width: 4.5em; padding: 3px 5px; font-family: var(--mono); font-size: 12px; background: var(--bg-inset); border: 2px inset var(--line); color: var(--ink); border-radius: 0; }
.pager__jump .btn { padding: 3px 10px; font-size: 11px; }
@media (max-width: 600px) {
  .pager--jump { grid-template-columns: 1fr 1fr; row-gap: 8px; }
  .pager--jump .pager__jump { grid-row: 2; grid-column: 1 / -1; justify-content: center; }
}

/* ---------- queue + skip ---------- */
.add-track button { padding: 6px 12px; }
.queue-status { min-height: 1.3em; margin: 0 0 6px; font-family: var(--ui); font-size: 11px; color: var(--accent); }
.queue-status.is-error { color: var(--danger); }
.queue-status:empty { min-height: 0; }
/* Long queues scroll inside the stage instead of pushing everything down. */
.queue-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--line); max-height: 280px; overflow-y: auto; scrollbar-width: thin; }
.queue-list:empty { border-top: 0; }
.queue-row { display: flex; align-items: center; gap: 10px; padding: 8px 2px; border-bottom: 1px dashed var(--line); font-size: 13px; }
.queue-row .idx { font-family: var(--ui); color: var(--ink-dim); width: 22px; font-size: 12px; flex-shrink: 0; }
.queue-row .qtrack { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.queue-row .who { font-family: var(--ui); font-size: 11px; color: var(--accent); margin-left: 4px; }
.queue-row .qtime { font-family: var(--ui); font-size: 11px; color: var(--ink-dim); flex-shrink: 0; }
.queue-row .remove { flex-shrink: 0; }
/* Fixed width: the count changing never moves the controls around it. */
.skip-btn { margin-left: auto; width: 8.5em; padding: 8px 0; font-size: 13px; text-align: center; white-space: nowrap; }
.skip-btn[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); border-style: inset; }
.skip-count { font-family: var(--ui); font-size: 11px; }

/* ---------- moderation ---------- */
.plain-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.plain-list li { display: flex; justify-content: space-between; align-items: center; gap: 12px; font-size: 13px; }
.inline-form { display: inline; margin: 0; }
.inline-add { display: flex; gap: 6px; }
.inline-add input {
  flex: 1; min-width: 0; padding: 7px 9px; border-radius: 0;
  font-family: var(--ui); font-size: 12px; background: var(--bg-inset); border: 2px inset var(--line); color: var(--ink);
}
.report-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.report { display: flex; flex-direction: column; gap: 8px; }
.report-head { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.report-quote { margin: 0; padding: 8px 10px; background: var(--bg-inset); border-left: 3px solid var(--line); font-size: 13px; overflow-wrap: anywhere; }
.report-reason { margin: 0; font-style: italic; color: var(--ink-dim); overflow-wrap: anywhere; }
.report-actions { display: flex; gap: 8px; }

/* Right-click moderation menu */
.mod-menu {
  position: absolute; z-index: 20; min-width: 190px; padding: 4px 0; margin: 0; list-style: none;
  background: var(--bg-panel); border: 2px outset var(--line); box-shadow: 2px 2px 0 var(--line);
  font-family: var(--ui); font-size: 12px;
}
.mod-menu li[role="separator"] { border-top: 1px dashed var(--line); margin: 4px 0; }
.mod-menu .mod-menu__title { padding: 4px 12px; color: var(--ink-dim); font-size: 11px; }
.mod-menu button {
  display: block; width: 100%; text-align: left; padding: 5px 12px; cursor: pointer;
  background: none; border: 0; color: var(--ink); font: inherit;
}
.mod-menu button:hover, .mod-menu button:focus-visible { background: var(--accent); color: var(--accent-ink); outline: none; }
.mod-menu button.danger { color: var(--danger); }
.mod-menu button.danger:hover, .mod-menu button.danger:focus-visible { background: var(--danger); color: var(--accent-ink); }
.chat-line.is-removed .body { color: var(--ink-dim); font-style: italic; }
.mod-toast { position: fixed; bottom: 16px; left: 50%; transform: translateX(-50%); z-index: 30; padding: 8px 14px; font-family: var(--lcd); font-size: 12px; background: var(--lcd-bg); color: var(--lcd-ink); border: 2px outset var(--line); }

/* ---------- dialogs (native <dialog>, styled like the rest of the site) ---------- */
.lobby-dialog {
  width: min(420px, calc(100vw - 32px)); padding: 18px; color: var(--ink);
  background: var(--bg-panel); border: 2px outset var(--line); box-shadow: 4px 4px 0 var(--line);
}
.lobby-dialog::backdrop { background: rgba(20, 17, 10, .45); }
.lobby-dialog form { display: flex; flex-direction: column; gap: 12px; }
.lobby-dialog__title { font-size: 13px; }
.lobby-dialog__msg { margin: 0; font-size: 13px; color: var(--ink-dim); }
.lobby-dialog__input {
  width: 100%; padding: 8px 10px; border-radius: 0;
  font-family: var(--sans); font-size: 13px; background: var(--bg-inset); border: 2px inset var(--line); color: var(--ink);
}
.lobby-dialog__actions { display: flex; justify-content: flex-end; gap: 8px; }
.mod-menu__note { color: var(--ink-dim); font-size: 11px; }
.mod-menu__status { display: block; max-width: 260px; margin-top: 2px; font-style: italic; overflow-wrap: anywhere; }
.mod-menu button:disabled { color: var(--ink-dim); cursor: default; background: none; }
/* Touch screens open the menu with a tap (modmenu.ts). iOS Safari only hands a tap on plain text to
   the page's click listener when the text shows a pointer cursor, so these must have one. */
@media (pointer: coarse) {
  .chat-line .u, .queue-row, .np-title { cursor: pointer; }
  .mod-menu { max-height: calc(100dvh - 16px); overflow-y: auto; font-size: 13px; }
  .mod-menu button { padding: 10px 14px; }
}
.chat-banned { margin: 0 0 6px; padding: 8px 10px; font-family: var(--ui); font-size: 12px; color: var(--danger); background: var(--bg-inset); border: 1px dashed var(--danger); }

.suggest-form { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.suggest-form input {
  flex: 1 1 180px; min-width: 0; padding: 7px 9px; border-radius: 0;
  font-family: var(--ui); font-size: 12px; background: var(--bg-inset); border: 2px inset var(--line); color: var(--ink);
}

/* ---------- admin ---------- */
.admin-nav { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; }
.admin-nav a { font-family: var(--mono); font-size: 12px; padding: 5px 10px; text-decoration: none; background: var(--bg-panel); color: var(--ink-dim); border: 2px outset var(--line); }
.admin-nav a:visited { color: var(--ink-dim); }
.admin-nav a[aria-current="page"] { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); border-style: inset; }
.admin-table-wrap { overflow-x: auto; border: 2px outset var(--line); background: var(--bg-panel); }
.admin-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.admin-table th, .admin-table td { text-align: left; padding: 7px 10px; border-bottom: 1px dashed var(--line); vertical-align: top; }
.admin-table th { font-family: var(--ui); font-size: 11px; font-weight: 700; color: var(--ink); background: var(--bg-inset); }
.admin-table td.num { font-family: var(--ui); text-align: right; }
.admin-table .mono { font-family: var(--code); font-size: 12px; overflow-wrap: anywhere; }
.admin-actions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.admin-actions input[type="text"] { width: 120px; padding: 4px 6px; font-family: var(--ui); font-size: 12px; background: var(--bg-inset); border: 2px inset var(--line); color: var(--ink); border-radius: 0; }
.badge { display: inline-block; font-family: var(--ui); font-size: 10px; padding: 1px 6px; border: 1px solid var(--line); color: var(--ink-dim); margin-right: 4px; }
.badge--danger { border-color: var(--danger); color: var(--danger); }
.badge--accent { border-color: var(--accent); color: var(--accent); }
.config-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px 16px; align-items: center; padding: 10px 12px; border-bottom: 1px dashed var(--line); scroll-margin-top: 16px; }
.config-row:target { background: var(--bg-inset); }
/* A list's heading, which its pager's links open at (pagerLinks): a little room above it. */
.section-label[id] { scroll-margin-top: 12px; }
@media (max-width: 560px) { .config-row { grid-template-columns: minmax(0, 1fr); } }
.config-row .key { font-family: var(--code); font-size: 11px; color: var(--ink-dim); }
.config-row form { display: flex; gap: 6px; align-items: center; }
/* admin overview, refused imports and adds: on a phone, cards (when and what on top, then who and
   where, then the message), not five narrow columns. The username keeps its width (it can't
   break); the place takes the rest and wraps. */
@media (max-width: 600px) {
  .refusals-table thead { display: none; }
  .refusals-table, .refusals-table tbody { display: block; }
  .refusals-table tr {
    display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "when what" "who where" "message message";
    gap: 2px 10px; padding: 9px 12px; border-bottom: 1px dashed var(--line);
  }
  .refusals-table tr:last-child { border-bottom: none; }
  .refusals-table td { display: block; padding: 0; border: 0; }
  .refusals-table .rf-when { grid-area: when; font-family: var(--ui); font-size: 11px; color: var(--ink-dim); }
  .refusals-table .rf-what { grid-area: what; font-family: var(--ui); font-size: 11px; color: var(--ink-dim); text-align: right; }
  .refusals-table .rf-who { grid-area: who; font-weight: 700; overflow-wrap: anywhere; }
  .refusals-table .rf-where { grid-area: where; text-align: right; overflow-wrap: anywhere; }
  .refusals-table .rf-message { grid-area: message; padding-top: 2px; }
}
/* "changed" and "reset" always take their space (hidden at the default), so a save moves nothing. */
.config-reset.is-unused, .config-changed.is-unused { visibility: hidden; }
.config-row input[type="number"], .config-row input[type="text"] { width: 150px; padding: 5px 7px; font-family: var(--ui); font-size: 12px; background: var(--bg-inset); border: 2px inset var(--line); color: var(--ink); border-radius: 0; }
.filter-bar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.kv { display: grid; grid-template-columns: max-content 1fr; gap: 4px 14px; font-size: 13px; }
.kv dt { font-family: var(--ui); font-size: 12px; font-weight: 700; color: var(--ink-dim); }
.kv dd { margin: 0; overflow-wrap: anywhere; }

.chat-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.chat-head h3 { margin-bottom: 10px; }
.chat-toggle { font-size: 11px; }
.chat-off { margin: 0 0 8px; padding: 10px; font-family: var(--ui); font-size: 12px; color: var(--ink-dim); background: var(--bg-inset); border: 1px dashed var(--line); }

.auth-title { font-size: 15px; margin-bottom: 12px; }

/* ---------- admin: cost guard ---------- */
.cost-guard { max-width: 640px; gap: 10px; }
.cost-row { display: grid; grid-template-columns: 1fr 140px 110px; align-items: center; gap: 12px; font-family: var(--ui); font-size: 12px; }
.cost-row progress { width: 100%; }
.cost-row .cost-num { text-align: right; }
.cost-row.is-hot, .cost-alerts .is-hot { color: var(--danger); }
.cost-alerts { margin: 0; padding-left: 18px; font-size: 12px; display: flex; flex-direction: column; gap: 4px; }
.cost-when { font-family: var(--ui); color: var(--ink-dim); }
@media (max-width: 560px) { .cost-row { grid-template-columns: 1fr 80px; } .cost-row progress { display: none; } }

/* Two-factor login setup: the key and recovery codes must be easy to read and copy, and wrap on phones. */
/* The setup QR: a fixed size (no shift as it loads), crisp pixels, and its own white frame in either theme. */
.setup-qr { margin: 4px 0 8px; }
.setup-qr img { display: block; width: 180px; height: 180px; image-rendering: pixelated; background: #fff; border: 2px inset var(--line); }
.setup-key code, .recovery-codes code { font-family: var(--code); font-size: 16px; font-weight: 700; letter-spacing: .04em; overflow-wrap: anywhere; user-select: all; }
.recovery-codes { list-style: none; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px 14px; }

/* ---------- events (album nights, hangs, shows) ---------- */
/* Home "coming up". Desktop: like a community row, title over room, the time and countdown on the
   right. Phone: a card, the title across the top with the countdown in its corner, then the room
   and the time on one line. The countdown keeps one width as it ticks, so nothing shifts. */
.event-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; grid-template-areas: "title when count" "room when count";
  column-gap: 12px; align-items: center;
}
.event-title { grid-area: title; }
.event-sub { display: contents; }
.event-room { grid-area: room; font-size: 12px; color: var(--ink-dim); overflow-wrap: anywhere; }
.event-sep { display: none; }
.event-when { grid-area: when; font-family: var(--ui); font-size: 11px; color: var(--ink-dim); }
.event-count { grid-area: count; display: inline-block; min-width: 14ch; text-align: right; font-family: var(--ui); font-size: 11px; color: var(--accent); }
@media (max-width: 600px) {
  .event-row { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "title count" "sub sub"; row-gap: 4px; padding: 10px 12px; align-items: start; }
  .event-title { font-size: 15px; line-height: 1.3; }
  .event-sub { display: block; grid-area: sub; font-size: 12px; color: var(--ink-dim); overflow-wrap: anywhere; }
  .event-sep { display: inline; }
  .event-when { font-family: inherit; font-size: inherit; }
  .event-row .event-count { min-width: 13ch; text-align: center; padding: 2px 6px; background: var(--bg-inset); border: 1px solid var(--line); white-space: nowrap; }
  .event-row.is-on .event-count { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
}

/* In the room: a quiet framed line with an accent edge, so an event stands out a little. */
.room-event {
  font-family: var(--ui); font-size: 12px; color: var(--ink); margin: 10px 0 0; padding: 7px 10px;
  background: var(--bg-inset); border: 1px solid var(--line); border-left: 3px solid var(--accent); overflow-wrap: anywhere;
}
.room-event__label { color: var(--accent); font-weight: 700; }
.room-event .event-count { min-width: 0; text-align: left; font-size: inherit; }
/* Once it's on, the label says so: the countdown would only repeat it. */
.room-event.is-on .room-event__count { display: none; }

/* A lineup room's gigs: the date in its own column, the band in bold, the venue under it. */
.room-shows { margin-top: 14px; }
.show-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-left: 3px solid var(--accent); }
.show-row {
  display: grid; grid-template-columns: 11ch minmax(0, 1fr); column-gap: 10px; font-size: 12px; padding: 7px 10px;
  background: var(--bg-panel); border-bottom: 1px solid var(--line); overflow-wrap: anywhere;
}
.show-row:last-child { border-bottom: none; }
.show-day { grid-row: span 2; font-family: var(--ui); font-size: 12px; color: var(--accent); padding-top: 1px; }
.show-band { font-weight: 700; }
.show-venue { font-size: 12px; color: var(--ink-dim); }

/* admin → events. On a phone each event is a card, not a row of narrow columns: the title with
   its status in the corner, then the room, when, and the actions along the bottom. */
.event-status { font-family: var(--ui); font-size: 11px; white-space: nowrap; }
.event-status.is-on { color: var(--accent); font-weight: 700; }
.event-until { display: block; color: var(--ink-dim); }
@media (max-width: 600px) {
  .events-table thead { display: none; }
  .events-table, .events-table tbody { display: block; }
  .events-table tr {
    display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "title status" "room room" "when when" "actions actions";
    gap: 4px 10px; padding: 10px 12px; border-bottom: 1px dashed var(--line);
  }
  .events-table tr:last-child { border-bottom: none; }
  .events-table td { display: block; padding: 0; border: 0; }
  .events-table .ev-title { grid-area: title; }
  .events-table .ev-room { grid-area: room; }
  .events-table .ev-when { grid-area: when; font-size: 12px; }
  .events-table .ev-status { grid-area: status; }
  .events-table .ev-actions { grid-area: actions; padding-top: 4px; }
  .events-table .event-status { display: inline-block; padding: 2px 6px; background: var(--bg-inset); border: 1px solid var(--line); }
  .events-table .event-status.is-on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
  .events-table .ev-actions .admin-actions { gap: 14px; }
}

/* Text people write (and video titles) stays inside its own box, so nothing in it can draw over
   the rest of the page: a "Zalgo" tower of accent marks once streaked down the home page and every
   room's sidebar (audit M3). The server now cuts such towers; this is the backstop. The small
   margin keeps ordinary accents and descenders from being trimmed. */
.room-card, .room-title, .room-desc, .community-row, .rail-room, .np-title, .chat-topic, .user-card .card-status, .mod-menu__status, .queue-row .qtrack, .report-quote, .report-reason, .room-event, .show-row, .import-preview__sample li, .track-search-note, .added-flash span {
  overflow: clip; overflow-clip-margin: 2px;
}
