/* theme-skin.css — Customization C0 (v1.46.0). Loaded by the crew app AND the console.
   Every themed rule is scoped under :root[data-skin] and reads only theme variables
   (written by applyTheme() in theme.js). With the A-Comm (original) preset there is no
   data-skin attribute, so nothing below matches and the page is the stock stylesheet,
   pixel for pixel. Never put a colour literal in a skinned rule: C1's editor drives these
   tokens, and AA contrast is checked on the tokens, not here.
   Exception: neutral black shadows (rgba(0,0,0,…)) which carry no brand colour. */

/* Logo slots exist on every page but only show for a skin that ships a logo. */
.skin-logo { display: none; }

/* ── Logos: join screen, waiting room, admin login (hero) + app/admin header ── */
:root[data-skin][data-has-logo] .skin-logo {
  display: block; flex-shrink: 0;
  background: var(--t-logo) left center / contain no-repeat;
  aspect-ratio: 2401 / 449;
}
:root[data-skin][data-has-logo] .skin-logo-hero {
  width: min(300px, 78vw); margin: 0 auto 22px; background-position: center;
}
:root[data-skin][data-has-logo] .skin-logo-header { height: 28px; }
@media (max-width: 540px) { :root[data-skin][data-has-logo] .skin-logo-header { height: clamp(22px, 7vw, 28px); } }
:root[data-skin][data-has-logo] #setup-overlay .hero-logo,
:root[data-skin][data-has-logo] #setup-overlay > h2,
:root[data-skin][data-has-logo] #waiting-overlay .hero-logo,
:root[data-skin][data-has-logo] #waiting-overlay > h2,
:root[data-skin][data-has-logo] #login-box .hero-logo,
:root[data-skin][data-has-logo] #login-box > h1,
:root[data-skin][data-has-logo] .header-badge,
:root[data-skin][data-has-logo] #header h1,
:root[data-skin][data-has-logo] .header-left .admin-logo,
:root[data-skin][data-has-logo] .header-left h1 .wm-text { display: none; }

/* ── Join screen + main actions ── */
/* Primary buttons carry the brand action colour. White on RaceOn red is AA for LARGE
   text only (4.15:1), so the label is set at 1.2rem bold (19.2px >= 18.66px). */
:root[data-skin] #setup-overlay button:not(.btn-alt),
:root[data-skin] #waiting-leave-btn {
  background: var(--t-primary); color: var(--t-primary-text);
  font-size: 1.2rem; font-weight: 800; border-radius: var(--t-radius);
}
:root[data-skin] #setup-overlay button:not(.btn-alt):hover { box-shadow: 0 0 20px var(--t-live-glow); }
:root[data-skin] #setup-overlay button.btn-alt { color: var(--text); border-color: var(--border2); border-radius: var(--t-radius); }
:root[data-skin] #setup-overlay input { border-radius: var(--t-radius); }
:root[data-skin] #setup-overlay input:focus { border-color: var(--text); box-shadow: 0 0 0 3px var(--glass-brd); }

/* ── Channel buttons ── */
:root[data-skin] .channel-btn { border-radius: var(--t-radius); }
:root[data-skin] .channel-btn.selected {
  background: var(--cyan-dim); border-color: var(--t-primary);
  box-shadow: inset 0 0 0 1px var(--t-primary);
}
:root[data-skin] .channel-btn.selected .ch-label { color: var(--text); }
:root[data-skin] .channel-btn.selected .ch-indicator { background: var(--t-primary); border-color: var(--t-primary); box-shadow: none; }
:root[data-skin] .channel-btn.transmitting { border-color: var(--t-talk-rx); animation: skin-ch-rx 1.1s ease-in-out infinite; }
:root[data-skin] .channel-btn.transmitting .ch-tx { color: var(--text); }
:root[data-skin] .channel-btn.transmitting .ch-indicator { background: var(--t-talk-rx); border-color: var(--t-talk-rx); }
:root[data-skin] .channel-btn.i-am-tx .ch-indicator { background: var(--t-talk-live); border-color: var(--t-talk-live); box-shadow: none; }
@keyframes skin-ch-rx {
  0%, 100% { box-shadow: inset 0 0 0 1px var(--t-talk-rx), 0 0 4px var(--t-rx-glow); }
  50%      { box-shadow: inset 0 0 0 1px var(--t-talk-rx), 0 0 18px var(--t-rx-glow); }
}

/* ── Talk buttons (orbs): the mark is the button. Fill = state:
   idle = talk_idle, someone else talking = talk_rx, you live (hold or latch) = talk_live.
   State words sit in a pill so small text is never set on a saturated fill. ── */
:root[data-skin] .ptt-ch-btn {
  background: var(--t-talk-idle); border-color: var(--t-talk-idle-ring);
  border-radius: var(--t-talk-radius); gap: 5%;
  box-shadow: 0 8px 28px rgba(0,0,0,.32);
}
:root[data-skin][data-theme="light"] .ptt-ch-btn { box-shadow: 0 6px 18px rgba(0,0,0,.12); }
:root[data-skin][data-has-mark] .ptt-ch-btn::before {
  content: ""; display: block; flex-shrink: 0; width: 40%; aspect-ratio: 692 / 449;
  background: var(--t-mark-idle) center / contain no-repeat;
}
:root[data-skin] .ptt-ch-label {
  color: var(--t-talk-idle-text); font-family: var(--font-display); font-weight: 800;
  font-size: clamp(1.2rem, 15cqw, 2.6rem); letter-spacing: .04em; line-height: 1; max-width: 82%;
}
:root[data-skin] .ptt-ch-state { color: var(--muted); }
:root[data-skin] .ptt-ch-key { top: auto; bottom: 5%; }
/* the pill */
:root[data-skin] .ptt-ch-btn:is(.rx, .talking, .latched, .muted, .locked) .ptt-ch-state {
  background: var(--t-pill-bg); color: var(--t-pill-text);
  padding: .3em .9em; border-radius: 999px; font-size: clamp(0.5rem, 6.2cqw, 0.9rem); max-width: 86%;
}
/* receiving */
:root[data-skin] .ptt-ch-btn.rx {
  background: var(--t-talk-rx); border-color: var(--t-talk-rx);
  box-shadow: 0 0 0 6px var(--t-rx-glow), 0 8px 28px rgba(0,0,0,.3);
}
/* live: holding or latched (wins over receiving when both apply) */
:root[data-skin] .ptt-ch-btn:is(.talking, .latched) {
  background: var(--t-talk-live); border-color: var(--t-talk-live);
  box-shadow: 0 0 0 8px var(--t-live-glow), 0 8px 28px rgba(0,0,0,.3);
  animation: skin-live-pulse 1.6s ease-in-out infinite;
}
:root[data-skin] .ptt-ch-btn:is(.rx, .talking, .latched) .ptt-ch-label { color: var(--t-talk-on-text); }
:root[data-skin][data-has-mark] .ptt-ch-btn:is(.rx, .talking, .latched)::before { background-image: var(--t-mark-live); }
:root[data-skin] .ptt-ch-btn:is(.rx, .talking, .latched) .ptt-ch-key { background: var(--t-pill-bg); color: var(--t-pill-text); opacity: 1; }
:root[data-skin] .ptt-ch-btn:is(.talking, .latched) .ptt-ch-ring { border-color: var(--t-talk-live); }
/* muted / locked: idle fill, danger edge, state in the pill */
:root[data-skin] .ptt-ch-btn:is(.muted, .locked) { background: var(--t-talk-idle); border-color: var(--red); }
:root[data-skin] .ptt-ch-btn:is(.muted, .locked) .ptt-ch-label { color: var(--t-talk-idle-text); }
@keyframes skin-live-pulse {
  0%, 100% { box-shadow: 0 0 0 6px var(--t-live-glow), 0 8px 28px rgba(0,0,0,.3); }
  50%      { box-shadow: 0 0 0 14px var(--t-live-glow), 0 8px 28px rgba(0,0,0,.3); }
}
/* 5+ talk buttons: the orbs get small, so on a fill the channel name moves into a pill
   too (never small text on red), and with 9+ the mark steps aside for the name. */
:root[data-skin] #ptt-buttons:is([data-many="some"], [data-many="lots"]) .ptt-ch-label { font-size: clamp(0.62rem, 12cqw, 1.3rem); }
:root[data-skin] #ptt-buttons:is([data-many="some"], [data-many="lots"]) .ptt-ch-btn:is(.rx, .talking, .latched) .ptt-ch-label {
  background: var(--t-pill-bg); color: var(--t-pill-text); padding: .2em .55em; border-radius: 999px;
}
:root[data-skin] #ptt-buttons[data-many="lots"] .ptt-ch-btn::before { display: none; }

/* ── Simple Mode slabs follow the theme ── */
:root[data-skin] .simple-slab {
  background: var(--t-talk-idle); border-color: var(--t-talk-idle-ring);
  border-radius: var(--simple-radius); box-shadow: 0 8px 28px rgba(0,0,0,.3);
}
:root[data-skin][data-theme="light"] .simple-slab { box-shadow: 0 6px 18px rgba(0,0,0,.12); }
:root[data-skin] .simple-slab-l { color: var(--t-talk-idle-text); }
:root[data-skin] .simple-slab-s { color: var(--muted); }
:root[data-skin][data-has-mark] .simple-talk::before {
  content: ""; display: block; flex-shrink: 0; height: clamp(24px, 24cqh, 140px); aspect-ratio: 692 / 449; max-width: 40%;
  background: var(--t-mark-idle) center / contain no-repeat;
}
:root[data-skin] .simple-slab:focus-visible { outline-color: var(--text); }
:root[data-skin] .simple-talk.rx { background: var(--t-talk-rx); border-color: var(--t-talk-rx); }
:root[data-skin] .simple-talk.talking,
:root[data-skin] .simple-latch.on {
  background: var(--t-talk-live); border-color: var(--t-talk-live);
  box-shadow: 0 0 0 6px var(--t-live-glow), 0 8px 28px rgba(0,0,0,.3);
}
:root[data-skin] .simple-talk:is(.rx, .talking) .simple-slab-l,
:root[data-skin] .simple-latch.on .simple-slab-l { color: var(--t-talk-on-text); }
:root[data-skin][data-has-mark] .simple-talk:is(.rx, .talking)::before { background-image: var(--t-mark-live); }
:root[data-skin] .simple-talk:is(.rx, .talking) .simple-slab-s,
:root[data-skin] .simple-latch.on .simple-slab-s,
:root[data-skin] .simple-slab:is(.muted, .locked) .simple-slab-s {
  background: var(--t-pill-bg); color: var(--t-pill-text); padding: .3em 1em; border-radius: 999px;
}
:root[data-skin] .simple-slab:is(.muted, .locked) { background: var(--t-talk-idle); border-color: var(--red); }
:root[data-skin] .simple-slab:is(.muted, .locked) .simple-slab-l { color: var(--red); }
:root[data-skin] .simple-strip.latched .simple-talker,
:root[data-skin] .simple-strip.self .simple-talker { color: var(--t-talk-live); }
:root[data-skin] .simple-strip.rx .simple-talker { color: var(--text); }
:root[data-skin] .simple-switch input:checked + .simple-switch-track { background: var(--t-primary); }
:root[data-skin] .simple-cog, :root[data-skin] .simple-full-btn { border-radius: var(--t-radius); background: var(--t-talk-idle); color: var(--t-talk-idle-text); border-color: var(--t-talk-idle-ring); }
:root[data-skin] .simple-full-btn { border-color: var(--t-primary); }
:root[data-skin] .simple-cog:focus-visible, :root[data-skin] .simple-full-btn:focus-visible { outline-color: var(--text); }

/* ── Console (admin.html) ── */
:root[data-skin] .btn-primary { background: var(--text); color: var(--bg); border-radius: var(--t-radius); }
:root[data-skin] .btn-primary:hover { box-shadow: 0 0 16px var(--glass-brd); }
:root[data-skin] .admin-badge { background: var(--t-pill-bg); color: var(--t-pill-text); }
:root[data-skin] .admin-ch-btn { border-radius: var(--t-radius); }
:root[data-skin] .admin-ch-btn.selected { border-color: var(--t-primary); color: var(--text); background: var(--cyan-dim); }
:root[data-skin] .admin-ch-btn.active-ch { border-color: var(--t-primary); color: var(--text); background: var(--cyan-dim); box-shadow: 0 0 0 2px var(--t-live-glow); }
:root[data-skin] .admin-ch-btn.has-tx { border-color: var(--t-talk-rx); color: var(--text); background: var(--cyan-dim); }
:root[data-skin] #admin-ptt-btn {
  background: var(--t-talk-idle); border-color: var(--t-talk-idle-ring); border-radius: var(--t-talk-radius);
  box-shadow: 0 6px 24px rgba(0,0,0,.3);
}
:root[data-skin] #admin-ptt-btn .ptt-icon { color: var(--t-talk-idle-text); }
:root[data-skin] #admin-ptt-btn:is(.transmitting, .open-mic) {
  background: var(--t-talk-live); border-color: var(--t-talk-live);
  box-shadow: 0 0 0 8px var(--t-live-glow), 0 6px 24px rgba(0,0,0,.3);
}
:root[data-skin] #admin-ptt-btn:is(.transmitting, .open-mic) .ptt-icon { color: var(--t-talk-on-text); }
:root[data-skin] #admin-ptt-btn:is(.transmitting, .open-mic) #admin-ptt-label {
  background: var(--t-pill-bg); color: var(--t-pill-text); border-radius: 999px; padding: 3px 9px;
}

/* ── Badges and small buttons that print black on the accent (or warn) fill. In a skin the
   accent can be dark (RaceOn light = navy), so their text takes the page background colour
   instead. Server contrast rules: bg on accent and bg on warn >= 4.5. ── */
:root[data-skin] .ch-roster-badge,
:root[data-skin] #chat-badge,
:root[data-skin] .dm-unread-dot,
:root[data-skin] .inbox-unread,
:root[data-skin] #servers-add-btn,
:root[data-skin] .server-switch-btn[data-armed="1"],
:root[data-skin] #waiting-staff-count,
:root[data-skin] #login-btn,
:root[data-skin] .perm-btn.allowed:hover { color: var(--bg); }
:root[data-skin] .chat-input-row button svg { color: var(--bg); stroke: var(--bg); }
/* The stock header gear is 40px (known issue in tests/mobile-layout.known.json, left alone so
   the original stays pixel-identical); a skin brings it up to the 44pt floor. */
:root[data-skin] #header .icon-btn { width: 44px; height: 44px; }
/* The admin login box is narrower than the join screen: keep the hero logo inside it. */
:root[data-skin][data-has-logo] #login-box .skin-logo-hero { width: 100%; max-width: 240px; }
/* My own transmission: my tile reads live (red), not receiving (blue). */
:root[data-skin] .channel-btn.transmitting.i-am-tx { border-color: var(--t-talk-live); animation: none; box-shadow: inset 0 0 0 1px var(--t-talk-live); }

/* ── Size tokens (C1 wiring, 2026-10-19) ──────────────────────────────────────────────────────
   theme.js has emitted --t-scale-* since v1.46 but nothing consumed them. Under a skin: body type,
   channel tiles, the talk orb and the footer text scale with the preset's `sizes`. Stock look
   (no data-skin) is untouched. Bounds in server/theme.js keep every target at or above 44 pt. */
:root[data-skin] { font-size: calc(100% * var(--t-scale-font-body, 1)); }
:root[data-skin] #channels { grid-template-columns: repeat(auto-fit, minmax(calc(64px * var(--t-scale-channel, 1)), 1fr)); gap: calc(8px * var(--t-scale-channel, 1)); }
:root[data-skin] .channel-btn { padding: max(19px, calc(14px * var(--t-scale-rows, 1))) 4px calc(12px * var(--t-scale-rows, 1)); }
/* letters/numbers only — named channels keep the .ch-name clamp (1.51.0, was beating it) */
:root[data-skin] .channel-btn .ch-label:not(.ch-name) { font-size: calc(1.65rem * var(--t-scale-channel, 1) / var(--t-scale-font-body, 1)); }
/* talk orbs fill their area (1.51.0 grid in index.html); the talk size token raises the cap */
:root[data-skin] #ptt-buttons { --orb-max: calc(260px * var(--t-scale-talk, 1)); }
:root[data-skin] #header .icon-btn { width: calc(44px * var(--t-scale-ui, 1)); height: calc(44px * var(--t-scale-ui, 1)); }
:root[data-skin] #footer, :root[data-skin] #channel-status { font-size: calc(1em * var(--t-scale-ui, 1)); }
