/* live.zillion247.com — the public watch page.
 *
 * One stylesheet, two shapes. The breakpoint is 900px: below it the page is a
 * single column with the chat underneath; above it the chat sits alongside.
 * There is deliberately no device sniffing and no second page — a phone held
 * sideways and a narrow desktop window are the same problem, and `@media`
 * already solves it.
 *
 * Brand tokens come from /theme.css; nothing here redefines a colour. */

* { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100dvh;                 /* dvh, not vh: iOS Safari's toolbar */
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font);
  display: flex;
  flex-direction: column;
}

/* ── top bar ─────────────────────────────────────────────────────────── */

/* The announcement strip: full width, above the header, gone when empty. */
.motd {
  padding: 9px 16px; text-align: center;
  font-size: .86rem; line-height: 1.4; color: var(--ink);
  background: linear-gradient(90deg, #c56bff2e, #7b5bff2e);
  border-bottom: 1px solid #ffffff1f;
}
.motd[hidden] { display: none; }
@media (max-width: 560px) { .motd { padding: 8px 12px; font-size: .8rem; } }

.bar {
  display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap;
  padding: 12px clamp(12px, 3vw, 28px);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 10;
  background: color-mix(in srgb, var(--ground) 88%, transparent);
  backdrop-filter: blur(8px);
}
/* ⚠️ Taller than the old wordmark on purpose: this lockup stacks "Zillion"
   over "24/7", so a height that suited one line leaves each of them half of it
   and the 24/7 unreadable. */
.bar .logo img { height: 42px; width: auto; display: block; }
.bar .meta {
  font-size: .72rem; letter-spacing: .06em; color: var(--dim);
  white-space: nowrap;
}
.bar .meta b { color: var(--ink); font-weight: 700; font-size: .92rem; }
.bar #pbuf { margin-left: 5px; opacity: .7; }

.bar .live {
  margin-left: auto; display: inline-flex; align-items: center; gap: 8px;
  font-size: .76rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--dim);
}
.bar .live .dot {
  width: 8px; height: 8px; border-radius: 50%; background: #3a3a42;
  transition: background .3s, box-shadow .3s;
}
.bar .live[data-on="1"] .dot {
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent);
  animation: pulse 2s ease-in-out infinite;
}
.bar .live[data-on="1"] .what { color: var(--ink); }
@keyframes pulse { 50% { opacity: .45; } }

/* ⚠️ Respect the setting. A pulsing dot is decoration; for someone with
   vestibular sensitivity it is not. */
@media (prefers-reduced-motion: reduce) {
  .bar .live[data-on="1"] .dot { animation: none; }
}

/* ⚠️ The chat toggle lives in the header now, so it must not stretch. */
.bar .chat-toggle { padding: 7px 14px; font-size: .8rem; }

/* ── the shell: one column, then two ─────────────────────────────────── */

.shell {
  flex: 1;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(12px, 2vw, 22px);
  padding: clamp(12px, 2.5vw, 28px);
  max-width: 1500px; width: 100%; margin: 0 auto;
  align-content: start;
}

.stage { min-width: 0; }              /* min-width:0 or the grid refuses to shrink */



.chat-toggle {
  font: inherit; font-weight: 600; font-size: .9rem;
  border: 1px solid var(--line); border-radius: 999px;
  padding: 10px 20px; cursor: pointer; flex: none;
  background: var(--panel-2); color: var(--ink);
}
.chat-toggle:hover { border-color: var(--accent); }
:root[data-chat="closed"] .ct-close,
:root[data-chat="open"]   .ct-open { display: none; }

/* ⚠️ `hidden` would unload the chat's websocket every time it is collapsed.
   Keep it in the tree and take it out of layout instead, so reopening is
   instant and no message is missed while it is shut. */
:root[data-chat="closed"] zillion-chat { display: none; }

/* ⚠️ THE TOGGLE HIDES THE CHAT, NOT THE COLUMN. It used to hide `.side`, which
   also holds the account panel — so "hide chat" hid the registration gate and
   the profile pane with it.

   The expensive half was not the one that got reported: `data-chat` defaults to
   CLOSED below 900px, so every first-time visitor on a phone loaded /live/ with
   the column hidden, the stage hidden by the gate, and therefore NOTHING on the
   page at all. Measured on 13 oct 2026 at 695px: side, stage and account panel
   all display:none together.

   The column now collapses only when it genuinely has nothing to show: signed
   in (so no gate is needed), not looking at the account pane, and the chat shut
   by hand. */
:root[data-chat="closed"][data-account="in"]:not([data-pane="account"]) .side {
  display: none;
}
.side { min-width: 0; }

@media (min-width: 900px) {
  :root[data-chat="open"] .shell {
    grid-template-columns: minmax(0, 1fr) clamp(300px, 26vw, 400px);
  }
  /* The toggle is for small screens; on a wide one the chat simply sits there.
     It stays available, because someone may still want the video full width. */
}

/* ── account gate and the profile pane ───────────────────────────────── */
/*
 * Two independent facts, two attributes on <html>:
 *   data-account  in | out   -- does this visitor have a session
 *   data-pane     watch | account   -- which pane they asked for
 *
 * ⚠️ The pane exists because hiding the account panel on sign-in removed the
 * only route to signing out, renaming and DELETING the account -- and App Store
 * guideline 5.1.1(v) requires that last one to be reachable from inside. Built
 * and caught the same hour. The app sketch had it right all along: there is a
 * Profiel tab in the bottom bar.
 *
 * ⚠️ Default is signed OUT and the attribute is only set once the server has
 * answered, so the chat never flashes into view for an expired session.
 */
:root[data-gate="on"]:not([data-account="in"]) zillion-chat,
:root[data-pane="account"] zillion-chat { display: none; }

:root[data-account="in"]:not([data-pane="account"]) #account { display: none; }

/* The video is behind the gate too: the live shows are what an account unlocks.
   The 24/7 audio stream is a different URL and stays open -- the panel says so
   and links there. */
:root[data-gate="on"]:not([data-account="in"]) .stage,
:root[data-pane="account"] .stage { display: none; }

:root[data-gate="on"]:not([data-account="in"]) .shell,
:root[data-pane="account"] .shell { grid-template-columns: minmax(0, 520px); justify-content: center; }

:root[data-gate="on"]:not([data-account="in"]) .chat-toggle { display: none; }

/* Gate off: the account panel is not in the way, but the profile button
   still is -- signing in voluntarily must stay possible, because the chat
   needs a name either way. */
:root[data-gate="off"]:not([data-pane="account"]) #account { display: none; }
:root[data-gate="off"] .account-btn { display: inline-flex; }

/* The profile button only means anything once there is a session to manage. */
.account-btn {
  display: none; align-items: center; gap: 7px;
  padding: 7px 12px; border: 1px solid var(--line); border-radius: 999px;
  background: transparent; color: var(--ink); font: inherit; font-size: .82rem;
  font-weight: 600; cursor: pointer;
}
:root[data-account="in"] .account-btn { display: inline-flex; }
.account-btn:hover { border-color: var(--accent); }
.account-btn .nick { max-width: 12ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }


/* The navigation strip, full bleed under the header. */
zillion-nav { --zn-fg: var(--ink); --zn-dim: var(--dim); --zn-line: var(--line); --zn-panel: var(--panel); }
.navstrip { padding: 6px clamp(12px, 3vw, 28px) 0; border-bottom: 1px solid var(--line); }

/* ══ the phone: the viewport IS the frame ═══════════════════════════════════
 *
 * ⚠️ An ATTRIBUTE, not a bare media query. `data-frame` is set on <html> by
 * live.js from `matchMedia('(max-width: 899px)')`, and `?phone=1` forces it.
 *
 * A layout that lives only inside a media query cannot be inspected anywhere but
 * on a phone: every check becomes "please look at your device and describe it",
 * and three rounds of that went by without even establishing which rules were
 * reaching it. One attribute makes the phone frame reproducible on a desk, which
 * is the difference between testing it and hoping.
 *
 * The frame: nothing scrolls but the chat log. Player under the bar, chat filling
 * what is left, composer on the bottom edge. Both on screen at once, always.
 *
 * ⚠️ `100dvh`, never `100vh`. On iOS Safari `vh` excludes the browser chrome, so
 * a 100vh column puts the composer behind the toolbar with the last line of chat
 * under it. `dvh` follows the toolbar as it hides and returns.
 */
:root[data-frame="phone"],
:root[data-frame="phone"] body { height: 100dvh; overflow: hidden; }

:root[data-frame="phone"] body {
  display: flex; flex-direction: column; min-height: 0;
}

:root[data-frame="phone"] .bar { padding: 7px 12px; gap: 9px; }
:root[data-frame="phone"] .bar .logo img { height: 32px; }

/* The player's buffer reading is desk detail; the viewer count is not, and it
   moves up beside the logo instead of being hidden with it. */
:root[data-frame="phone"] .bar .meta-player { display: none; }

/* ⚠️ The page menu is GONE on a phone, not merely thinner. Six destinations
   across the top of a watch screen is the opposite of what this layout is for,
   and the logo reaches all of them. */
:root[data-frame="phone"] .navstrip { display: none; }

:root[data-frame="phone"] .shell {
  /* ⚠️ No max-width here. The base rule centres the page at 1500px, which on a
     wide screen in this frame produced the very gutter the frame exists to
     remove — and it is what a landscape phone or a tablet would hit too. */
  max-width: none;
  flex: 1 1 auto;
  min-height: 0;                        /* or the grid refuses to shrink at all */
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-columns: 1fr;
  gap: 0;
  padding: 0;
  align-content: stretch;
}

/* Edge to edge: a letterboxed video inside a rounded, inset card wastes the one
   dimension a phone has none of. No frame, no radius, no gutter.
   ⚠️ `--radius: 0` as well as `border: 0` — the player draws its own frame from
   `var(--radius, 12px)` inside its shadow root. A `video` selector from here
   would miss entirely: that element is in the shadow DOM. */
/* ⚠️ The picture is CAPPED, not merely sized. Its row is `auto`, so it takes
   whatever 16:9 asks for — fine at 390px wide (219px tall, a quarter of the
   screen) and ruinous on a landscape phone or a tablet, where it swallows the
   frame and leaves the chat entirely below the fold. A ceiling makes "both
   always on screen" a guarantee instead of a happy consequence of portrait
   arithmetic. */
:root[data-frame="phone"] .stage { min-height: 0; max-height: 42dvh; }
/* ⚠️ The ceiling is applied to the WIDTH, not the height. Capping the height on
   a 16:9 element crops it — the first version cut the top and bottom off the
   picture in landscape, where a video page is most likely to be watched. Limiting
   the width to what 42dvh of height allows keeps the whole frame and simply makes
   it narrower, centred. In portrait the limit is wider than the screen, so the
   picture stays edge to edge and nothing changes. */
:root[data-frame="phone"] .stage zillion-video {
  --radius: 0; border: 0; display: block;
  width: 100%; max-width: calc(42dvh * 16 / 9); margin: 0 auto;
}

/* ⚠️ `height: 100%`, and it is not belt-and-braces. A grid item's default
   stretch did NOT bound this one: the row measured 424px while the column
   rendered 620 and pushed the composer off the bottom. An explicit height
   resolves against the row and the whole chain below it — chat, log, composer —
   finally shrinks. Proven by setting it by hand in the browser first: 620 became
   424 and the composer landed 21px above the viewport edge. */
:root[data-frame="phone"] .side {
  min-height: 0; height: 100%; display: flex; flex-direction: column;
}

/* ⚠️ The chat is ALWAYS shown here, and the toggle is hidden rather than merely
   ignored. A control that is visible and does nothing is worse than no control,
   and with both panes fixed on screen there is nothing left to toggle. */
:root[data-frame="phone"][data-chat="closed"] zillion-chat { display: flex; }
:root[data-frame="phone"] .chat-toggle { display: none; }

:root[data-frame="phone"] zillion-chat {
  flex: 1 1 auto;
  min-height: 0;
  border-radius: 0;
  border-left: 0; border-right: 0; border-bottom: 0;
  /* ⚠️ The line cap belongs to a page that SCROLLS. Here the log takes exactly
     the room that is left, so the cap is lifted and the flex parent decides.
     Leaving it would strand the composer halfway up the screen. */
  --zc-log-lines: 999;
}

/* The account pane takes the whole frame when open: a form and a video fighting
   over 700px of phone is a form nobody completes. */
:root[data-frame="phone"][data-pane="account"] .stage { display: none; }
:root[data-frame="phone"][data-pane="account"] .side { overflow-y: auto; }

/* ⚠️ The gate still wins on a phone. The "chat is ALWAYS shown" rule above has
   the same specificity as the gate's hide rule and comes later, so until
   15 oct 2026 a signed-out phone got the chat AND the account form, the form
   squeezed to a strip with its fields cut off. One more attribute is enough to
   outrank it; the side then scrolls so the whole form is reachable. */
:root[data-frame="phone"][data-gate="on"]:not([data-account="in"]) zillion-chat,
:root[data-frame="phone"][data-pane="account"] zillion-chat { display: none; }
:root[data-frame="phone"][data-gate="on"]:not([data-account="in"]) .side { overflow-y: auto; }

/* ⚠️ And the other half, same day: SIGNED IN, the column-collapse rule further
   up (`data-chat="closed"` + `data-account="in"` hides .side) took the whole
   chat away on a phone, because data-chat defaults to closed below 900px and
   the phone frame has no toggle to open it. The phone frame shows the chat
   always, so the collapse does not apply here. One attribute more to outrank it. */
:root[data-frame="phone"][data-chat="closed"][data-account="in"]:not([data-pane="account"]) .side {
  display: flex;
}

/* ══ the desk ══════════════════════════════════════════════════════════════ */
@media (min-width: 900px) {
  /* The picker only has a place to live once the account pane is open; in the
     watch pane it would be a stray row of letters under the chat. */
  .langs-pane { margin-top: 14px; justify-content: center; }
}
:root:not([data-pane="account"]) .langs-pane { display: none; }
