/* Shared design system for server/public/* pages.

   Implements viewracle-brand-ui-guide.md v1.0. The `--vr-*` block below is
   the brand contract (guide §13) and is the only place raw brand hexes are
   allowed; everything downstream goes through the semantic aliases so a
   palette change never has to be chased through component rules.

   The broadcaster ships the same system at broadcaster/public/common/style.css
   and, inline, at broadcaster/public/control/index.html. Keep the three in
   step if any of them moves. */

:root {
  color-scheme: dark;

  /* ---- Brand tokens (guide §13) — do not hand-pick colours from artwork ---- */
  --vr-cyan: #12BFF3;
  /* Channels, for translucent washes — same reason as --vr-danger-rgb. */
  --vr-cyan-rgb: 18 191 243;
  --vr-cyan-bright: #5AD4F8;
  --vr-magenta: #F23AC6;
  --vr-light-gray: #D7DADF;
  --vr-slate: #344154;

  --vr-bg: #080C11;
  --vr-surface-1: #0F151D;
  --vr-surface-2: #171F29;
  --vr-surface-3: #1C2632;
  --vr-border: #2A3441;
  --vr-border-strong: #3A4757;
  --vr-text: #F4F6F8;
  --vr-text-muted: #9DA8B6;
  --vr-text-faint: #6B7787;

  /* Semantic ≠ brand (guide §4): these carry meaning, so they never borrow
     cyan or magenta. Red stays reserved for LIVE/REC/stop and hard errors. */
  --vr-success: #36C98F;
  --vr-warning: #F5B942;
  --vr-danger: #F05B63;
  /* Same colour as channels, for the translucent washes below: CSS cannot
     take an alpha off a hex token, and a second literal is a second place
     to forget. */
  --vr-danger-rgb: 240 91 99;

  --vr-radius-sm: 6px;
  --vr-radius-md: 8px;
  --vr-radius-lg: 12px;

  --vr-motion-fast: 120ms;
  --vr-motion-ui: 180ms;
  --vr-motion-layout: 220ms;

  /* ---- Semantic aliases: what the pages actually consume ---- */
  --bg: var(--vr-bg);
  --surface: var(--vr-surface-1);
  --surface-hover: var(--vr-surface-2);
  --border: var(--vr-border);
  --border-strong: var(--vr-border-strong);
  --text: var(--vr-text);
  --text-muted: var(--vr-text-muted);
  --text-faint: var(--vr-text-faint);
  --accent: var(--vr-cyan);
  --accent-strong: var(--vr-cyan-bright);
  --success: var(--vr-success);
  --success-strong: #5FDCAB;
  --danger: var(--vr-danger);
  --danger-strong: #FF8A90;
  --radius-lg: var(--vr-radius-lg);

  /* Text that sits ON cyan. Near-black rather than pure, to match the rest
     of the surface stack (guide §5: no #000 anywhere). */
  --on-accent: #04121A;

  --font-sans: Inter, -apple-system, "Segoe UI", system-ui, sans-serif;
  --font-mono: ui-monospace, "Cascadia Code", "SF Mono", "JetBrains Mono", Consolas, monospace;
}

/* Vendored rather than fetched from Google Fonts — see fonts/PROVENANCE.md.
   The wordmark is live text, so a substituted family is a brand error here. */
@font-face {
  font-family: Inter; font-style: normal; font-weight: 400; font-display: swap;
  src: url("/common/fonts/inter-latin-400-normal.woff2") format("woff2");
}
@font-face {
  font-family: Inter; font-style: normal; font-weight: 500; font-display: swap;
  src: url("/common/fonts/inter-latin-500-normal.woff2") format("woff2");
}
@font-face {
  font-family: Inter; font-style: normal; font-weight: 600; font-display: swap;
  src: url("/common/fonts/inter-latin-600-normal.woff2") format("woff2");
}
@font-face {
  font-family: Inter; font-style: normal; font-weight: 700; font-display: swap;
  src: url("/common/fonts/inter-latin-700-normal.woff2") format("woff2");
}

* { box-sizing: border-box; }

html, body { height: 100%; }

/* Always reserve the vertical scrollbar's width, even on pages short enough
   that nothing actually scrolls — otherwise the header (sticky, full-width)
   shifts a few pixels sideways when navigating from a page with a scrollbar
   to one without, since the available content width differs. */
html { scrollbar-gutter: stable; background: var(--vr-bg); }

body {
  font-family: var(--font-sans);
  /* 70/20/10 (guide §3): the wash is the only decorative use of brand colour
     on a page, and it is kept below the threshold where it reads as a tint. */
  background:
    radial-gradient(1200px 600px at 15% -10%, rgba(18, 191, 243, 0.06), transparent 60%),
    var(--bg);
  color: var(--text);
  margin: 0;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }
a.link { color: var(--accent-strong); }
a.link:hover { text-decoration: underline; }

h1, h2 { margin: 0; font-weight: 600; }

/* Guide §9: one very evident ring, everywhere, for keyboard users. */
:focus-visible { outline: 2px solid var(--vr-cyan); outline-offset: 2px; }

/* ---- Brand ----
   .brand is the horizontal lockup: symbol + wordmark. The symbol is a
   background image rather than inline SVG so every page keeps its existing
   one-line <span class="brand-mark"></span> markup. */
.brand { display: flex; align-items: center; gap: 0.6rem; }
.brand-mark {
  /* Guide §2.5: never below 20px for the UI symbol. The 790:598 ratio is the
     artwork's own, so the panels never stretch (§2.6). */
  height: 22px;
  aspect-ratio: 790 / 598;
  flex: none;
  background: url("/common/brand/viewracle-mark.svg") center / contain no-repeat;
}
.brand h1 {
  /* Guide §2.1: lowercase, Inter 700, tight tracking, dot on the i kept. */
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: -0.035em;
  text-transform: lowercase;
  line-height: 1;
}
.brand-sub {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-top: 0.15rem;
}

/* Guide §12: splash / about / onboarding / marketing only — never inside a
   control or a working area. */
.tagline {
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--vr-light-gray);
  margin: 0;
}
.tagline em { font-style: normal; color: var(--vr-cyan); }

/* Stacked lockup for hero/marketing use: symbol above the wordmark, tagline
   under it. Guide §2.4 — the gaps below are the 25% clear zone. */
.lockup { display: flex; flex-direction: column; align-items: center; gap: 1.1rem; }
/* Sized so the symbol keeps roughly the 0.55 width ratio to the wordmark that
   the master artwork has — the lockup's proportions are part of the mark. */
.lockup .brand-mark { height: clamp(62px, 13vw, 100px); }
.lockup-word {
  font-size: clamp(2.4rem, 8vw, 3.4rem);
  font-weight: 700;
  letter-spacing: -0.035em;
  text-transform: lowercase;
  line-height: 1;
  margin: 0;
}
.lockup .tagline { font-size: clamp(0.72rem, 2.2vw, 0.85rem); }

/* ---- Top bar ---- */
header.topbar {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 1rem clamp(1rem, 4vw, 2.5rem);
  /* Extra right-side room for Windows' own minimize/maximize/close overlay
     buttons (see main.js's titleBarOverlay) — env(titlebar-area-width) is a
     live CSS environment variable Electron/Chromium updates in lockstep with
     layout (resize, maximize/restore, DPI/monitor changes included), so this
     never lags a JS event by a frame the way a hand-computed value would —
     that lag is exactly what caused the nav to visibly jump on maximize/
     restore. Outside Electron's titleBarOverlay mode the variable is simply
     unsupported, so the fallback (100vw, i.e. no reservation) applies. */
  padding-right: calc(clamp(1rem, 4vw, 2.5rem) + max(0px, 100vw - env(titlebar-area-width, 100vw)));
  background: rgba(8, 12, 17, 0.86);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  -webkit-app-region: drag;
}
header.topbar nav { display: flex; align-items: center; gap: 1.5rem; -webkit-app-region: no-drag; }
header.topbar nav a {
  color: var(--text-muted);
  font-size: 0.9rem;
  font-weight: 500;
  transition: color var(--vr-motion-fast) ease-out;
}
header.topbar nav a:hover { color: var(--text); }

/* Only ever shown inside the installed app's own window (see the inline
   <head> script on welcome/dashboard/join — it tags <html> before first
   paint, so this never flashes visible then hidden like a post-load JS
   toggle would). A public visitor's browser never gets that class. */
.control-panel-link { display: none; }
html.is-electron .control-panel-link { display: inline; }

/* ---- User menu (icon button + dropdown, in the topbar nav) ---- */
.user-menu { position: relative; }
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.2rem;
  height: 2.2rem;
  padding: 0;
  border-radius: 50%;
  background: var(--surface-hover);
  border: 1px solid var(--border-strong);
  color: var(--text-muted);
}
.icon-btn:hover { color: var(--text); background: var(--vr-surface-3); }
.user-menu-dropdown {
  position: absolute;
  top: calc(100% + 0.6rem);
  right: 0;
  min-width: 180px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--vr-radius-md);
  padding: 0.4rem;
  display: none;
  flex-direction: column;
  gap: 0.15rem;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
  z-index: 20;
}
.user-menu-dropdown.open { display: flex; }
.user-menu-dropdown a, .user-menu-dropdown button {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.55rem 0.7rem;
  border-radius: var(--vr-radius-sm);
  background: none;
  border: none;
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
}
.user-menu-dropdown a:hover, .user-menu-dropdown button:hover { background: var(--surface-hover); }

/* ---- Buttons (guide §9) ---- */
button, .button {
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  min-height: 38px;
  color: var(--text);
  background: var(--surface-hover);
  border: 1px solid var(--border-strong);
  border-radius: var(--vr-radius-md);
  padding: 0.6rem 1.1rem;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition:
    background-color var(--vr-motion-ui) ease-out,
    border-color var(--vr-motion-ui) ease-out,
    opacity var(--vr-motion-ui) ease-out,
    transform var(--vr-motion-fast) ease-out;
}
button:hover, .button:hover { background: var(--vr-surface-3); border-color: var(--border-strong); }
button:active, .button:active { transform: translateY(1px); }
button:disabled { opacity: 0.5; cursor: not-allowed; }
button.secondary, .button.secondary { background: var(--surface); }

button.primary, .button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}
/* Guide §9: a moderate luminance step on hover, never a glow. */
button.primary:hover, .button.primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); }
button.primary:disabled { background: var(--surface-hover); border-color: var(--border-strong); color: var(--text-muted); }

/* Guide §9: destructive actions use the semantic danger red, never the brand
   magenta — magenta means "another signal", not "this will break something". */
button.danger, .button.danger {
  background: rgb(var(--vr-danger-rgb) / 0.12);
  border-color: rgb(var(--vr-danger-rgb) / 0.4);
  color: var(--danger-strong);
}
button.danger:hover, .button.danger:hover { background: var(--danger); border-color: var(--danger); color: #fff; }

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
}

/* ---- Cards ---- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 1.5rem;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.card h2 {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 0.9rem;
}

/* ---- Form controls ---- */
input[type="text"], input[type="email"], input[type="password"] {
  font: inherit;
  padding: 0.65rem 0.85rem;
  width: 100%;
  border-radius: var(--vr-radius-md);
  border: 1px solid var(--border-strong);
  background: var(--bg);
  color: var(--text);
  margin-bottom: 1rem;
  transition: border-color var(--vr-motion-ui) ease-out, box-shadow var(--vr-motion-ui) ease-out;
}
input::placeholder { color: var(--text-faint); }
/* Focus is carried by the border AND a ring, so it does not rest on colour
   alone (guide §5, §15). */
input:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(18, 191, 243, 0.18);
}
input:read-only { color: var(--text-muted); }
input:disabled { opacity: 0.6; }

hr { border: none; border-top: 1px solid var(--border); margin: 1.2rem 0; }

/* ---- Status text ---- */
.status { color: var(--text-muted); font-size: 0.85rem; }
.status.error, .error { color: var(--danger-strong); }
.status.success, .success { color: var(--success-strong); }

/* ---- Banner (matches /control's #link-banner) ---- */
.banner {
  padding: 1rem 1.2rem;
  border-radius: var(--radius-lg);
  background: rgba(18, 191, 243, 0.08);
  border: 1px solid rgba(18, 191, 243, 0.35);
  color: var(--accent-strong);
  font-size: 0.9rem;
  line-height: 1.5;
}
.banner a.link { font-weight: 600; }

footer { text-align: center; color: var(--text-faint); padding: 2rem; font-size: 0.85rem; }
