/* ==========================================================================
   xCloud Web — visual identity
   Grounded in the Xbox dashboard's own language: signature green used as a
   single saturated accent (not a wash), a blocky geometric display face,
   and a recurring angular "power glyph" motif that stands in for the
   product's actual job — turning something on and connecting to it.

   Type: Space Grotesk (display) / Inter (body) / JetBrains Mono (data) —
   real webfonts committed to on purpose, replacing system-font fallback
   stacks, while keeping the same condensed-geometric-display +
   monospace-data personality the identity already established.
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;700;800&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap');

:root {
  --bg: #0a0e0c;
  --bg-raised: #121712;
  --panel: #151b16;
  --border: #232b24;
  --border-hover: #2f3d30;
  --text: #f2f4f2;
  --muted: #7c877d;
  --muted-dim: #565f57;
  --accent: #107c10;
  --accent-bright: #4cc74c;
  --signal: #ffb020;
  --error: #e5484d;

  --font-display: "Space Grotesk", "Segoe UI", "Arial Narrow", sans-serif;
  --font-body: "Inter", -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "JetBrains Mono", "SF Mono", "Cascadia Code", Consolas, monospace;

  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  /* Two additional curves used only by the boot sequence, layered
     alongside --ease rather than replacing it. Using one curve for
     every kind of motion is what makes CSS animation read as "UI
     transitions" instead of "motion design" -- a professional
     animator picks the curve per physical action, not per file. */
  --ease-arrive: cubic-bezier(0.34, 1.56, 0.64, 1); /* slight overshoot + settle, for things locking into place */
  --ease-glide: cubic-bezier(0.22, 0.61, 0.36, 1);  /* soft, longer decel, for ambient/continuous reveals */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 8px 24px -12px rgba(0, 0, 0, 0.6);
  --shadow-lg: 0 24px 60px -20px rgba(0, 0, 0, 0.7);
  --shadow-glow: 0 0 0 1px rgba(16, 124, 16, 0.4), 0 8px 28px -8px rgba(76, 199, 76, 0.35);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
}

body {
  background-image:
    radial-gradient(circle at 15% 20%, rgba(16, 124, 16, 0.08), transparent 45%),
    radial-gradient(circle at 85% 80%, rgba(16, 124, 16, 0.06), transparent 40%),
    radial-gradient(circle at 50% 100%, rgba(76, 199, 76, 0.04), transparent 50%);
  background-attachment: fixed;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

.hidden { display: none !important; }

/* ==========================================================================
   Boot sequence — plays once per page load, full-viewport, on top of
   everything. Built entirely from the same tokens as the rest of the
   identity (no new colors introduced) — this is the existing power-glyph
   language pushed to its most elaborate expression, not a separate look.
   Total run time ~9.2s intro + ~0.5s exit wipe. The mark now builds in
   three facet passes with orbiting rings and radial spokes, framed by a
   HUD corner/telemetry readout, with a three-stage status line that
   reads like independent subsystems reporting in rather than one bar.
   Respects reduced-motion by cutting straight to a short fade (see the
   media query at the end).
   ========================================================================== */

#boot-screen {
  position: fixed;
  inset: 0;
  z-index: 2000;
  background: var(--bg);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.5s var(--ease), visibility 0.5s var(--ease);
}

#boot-screen.boot-exit {
  opacity: 0;
  pointer-events: none;
}
#boot-screen.boot-done {
  visibility: hidden;
}

/* power-on bloom — the very first beat, a soft ignition from black
   before the grid or mark appear, echoing a display waking up */
.boot-poweron {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 50%, rgba(76, 199, 76, 0.22), transparent 55%);
  opacity: 0;
  animation: boot-poweron-fade 1.4s var(--ease) forwards;
  animation-delay: 0.15s;
}

@keyframes boot-poweron-fade {
  0%   { opacity: 0; }
  45%  { opacity: 1; }
  100% { opacity: 0; }
}

.boot-grid {
  position: absolute;
  inset: -10% -10%;
  background-image:
    linear-gradient(rgba(76, 199, 76, 0.14) 1px, transparent 1px),
    linear-gradient(90deg, rgba(76, 199, 76, 0.14) 1px, transparent 1px);
  background-size: 44px 44px;
  background-position: 0 0;
  transform: perspective(600px) rotateX(62deg) scale(1.6);
  transform-origin: center 70%;
  opacity: 0;
  /* fade-in is one-shot; the drift is continuous and starts once the
     fade completes, animating background-position (not transform,
     which is already fully committed to the perspective tilt above)
     for a slow sense of moving forward across the floor plane */
  animation-name: boot-grid-fade, boot-grid-drift;
  animation-duration: 2s, 9s;
  animation-timing-function: var(--ease), linear;
  animation-delay: 0.9s, 2.9s;
  animation-iteration-count: 1, infinite;
  animation-fill-mode: forwards, none;
  mask-image: radial-gradient(ellipse 70% 60% at 50% 65%, black 40%, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 65%, black 40%, transparent 78%);
}

/* second, fainter grid layer at a different scale/depth behind the
   first — pure parallax, gives the floor genuine depth instead of one
   flat plane */
.boot-grid-far {
  position: absolute;
  inset: -20% -20%;
  background-image:
    linear-gradient(rgba(76, 199, 76, 0.06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(76, 199, 76, 0.06) 1px, transparent 1px);
  background-size: 88px 88px;
  background-position: 0 0;
  transform: perspective(700px) rotateX(62deg) scale(1.9);
  transform-origin: center 70%;
  opacity: 0;
  /* a touch of blur sells this as further away / out of focus, the
     way a camera lens renders depth, rather than just fainter */
  filter: blur(0.6px);
  /* drifts slower than .boot-grid above (6.3px/s vs 9.8px/s) — real
     parallax depth requires the far layer to move slower, not just
     look fainter */
  animation-name: boot-grid-fade, boot-grid-drift-far;
  animation-duration: 2.4s, 14s;
  animation-timing-function: var(--ease), linear;
  animation-delay: 1.1s, 3.5s;
  animation-iteration-count: 1, infinite;
  animation-fill-mode: forwards, none;
  mask-image: radial-gradient(ellipse 75% 65% at 50% 65%, black 30%, transparent 80%);
  -webkit-mask-image: radial-gradient(ellipse 75% 65% at 50% 65%, black 30%, transparent 80%);
}

@keyframes boot-grid-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}
/* 88px = exactly two 44px tiles, so the infinite loop wraps with no
   visible seam at the restart point */
@keyframes boot-grid-drift {
  from { background-position: 0 0; }
  to   { background-position: 0 88px; }
}
/* seamless at this layer's own 88px tile size — a single full tile,
   not a coincidental reuse of the near layer's distance value */
@keyframes boot-grid-drift-far {
  from { background-position: 0 0; }
  to   { background-position: 0 88px; }
}

.boot-particles {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.boot-particles span {
  position: absolute;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--accent-bright);
  opacity: 0;
  animation: boot-particle-drift 6.5s ease-in-out infinite;
  box-shadow: 0 0 6px var(--accent-bright);
}
.boot-particles span:nth-child(1)  { top: 22%; left: 18%; animation-duration: 6.2s; animation-delay: 1.3s; }
.boot-particles span:nth-child(2)  { top: 68%; left: 12%; animation-duration: 5.1s; animation-delay: 1.6s; }
.boot-particles span:nth-child(3)  { top: 34%; left: 82%; animation-duration: 5.8s; animation-delay: 1.4s; }
.boot-particles span:nth-child(4)  { top: 78%; left: 76%; animation-duration: 4.9s; animation-delay: 1.9s; }
.boot-particles span:nth-child(5)  { top: 14%; left: 55%; animation-duration: 6.6s; animation-delay: 1.7s; }
.boot-particles span:nth-child(6)  { top: 88%; left: 46%; animation-duration: 5.3s; animation-delay: 2.1s; }
.boot-particles span:nth-child(7)  { top: 50%; left: 8%;  animation-duration: 5.9s; animation-delay: 1.5s; }
.boot-particles span:nth-child(8)  { top: 42%; left: 92%; animation-duration: 5.4s; animation-delay: 2.2s; }
.boot-particles span:nth-child(9)  { top: 8%;  left: 32%; animation-duration: 6.1s; animation-delay: 1.4s; }
.boot-particles span:nth-child(10) { top: 92%; left: 62%; animation-duration: 4.8s; animation-delay: 1.9s; }
.boot-particles span:nth-child(11) { top: 60%; left: 26%; animation-duration: 6.4s; animation-delay: 1.8s; }
.boot-particles span:nth-child(12) { top: 26%; left: 68%; animation-duration: 5.6s; animation-delay: 2.3s; }
.boot-particles span:nth-child(13) { top: 16%; left: 74%; animation-duration: 5.7s; animation-delay: 2.6s; }
.boot-particles span:nth-child(14) { top: 82%; left: 34%; animation-duration: 6.3s; animation-delay: 2.8s; }
.boot-particles span:nth-child(15) { top: 46%; left: 16%; animation-duration: 5.2s; animation-delay: 3.0s; }
.boot-particles span:nth-child(16) { top: 6%;  left: 60%; animation-duration: 6.0s; animation-delay: 3.2s; }

@keyframes boot-particle-drift {
  0%   { opacity: 0; transform: translateY(0) scale(0.8); }
  15%  { opacity: 0.9; }
  50%  { opacity: 0.35; transform: translateY(-22px) scale(1.1); }
  85%  { opacity: 0.9; }
  100% { opacity: 0; transform: translateY(-44px) scale(0.8); }
}

.boot-scanline {
  position: absolute;
  left: 0; right: 0;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent-bright), transparent);
  box-shadow: 0 0 16px 2px var(--accent-bright);
  opacity: 0;
  top: -5%;
  animation: boot-scan-sweep 2.3s var(--ease) forwards;
  animation-delay: 1.1s;
}
/* a second, later sweep — the first pass reads as the initial power-up
   scan, this one as a confirmation pass once the mark has assembled */
.boot-scanline-2 {
  animation-delay: 3.6s;
  animation-duration: 2s;
}

@keyframes boot-scan-sweep {
  0%   { top: -5%; opacity: 0; }
  8%   { opacity: 0.9; }
  92%  { opacity: 0.7; }
  100% { top: 105%; opacity: 0; }
}

.boot-vignette {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 60% 55% at 50% 42%, transparent 40%, rgba(10, 14, 12, 0.9) 100%);
  pointer-events: none;
}

/* HUD corner brackets + telemetry — a diagnostics-readout frame around
   the whole screen, the clearest signal of "high-end hardware splash"
   register. Purely decorative, stays lit for the whole sequence once
   drawn in. */
.boot-hud {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.boot-corner {
  position: absolute;
  width: 46px;
  height: 46px;
  opacity: 0;
  transform: scale(0.85);
  animation: boot-corner-in 0.7s var(--ease-arrive) forwards;
}
.boot-corner svg { width: 100%; height: 100%; overflow: visible; }
.boot-corner path {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1.5;
  stroke-dasharray: 52;
  stroke-dashoffset: 52;
  animation: boot-draw 0.9s var(--ease) forwards;
}
.boot-corner.tl { top: 40px; left: 40px; animation-delay: 1.5s; }
.boot-corner.tl path { animation-delay: 1.6s; }
.boot-corner.tr { top: 40px; right: 40px; animation-delay: 1.6s; }
.boot-corner.tr path { animation-delay: 1.7s; }
.boot-corner.bl { bottom: 40px; left: 40px; animation-delay: 1.6s; }
.boot-corner.bl path { animation-delay: 1.7s; }
.boot-corner.br { bottom: 40px; right: 40px; animation-delay: 1.7s; }
.boot-corner.br path { animation-delay: 1.8s; }

@keyframes boot-corner-in {
  to { opacity: 0.55; transform: scale(1); }
}

.boot-telemetry {
  position: absolute;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  color: var(--muted-dim);
  opacity: 0;
  animation: boot-subword-in 0.6s var(--ease-glide) forwards;
  text-transform: uppercase;
}
.boot-telemetry.a { top: 44px; left: 96px; animation-delay: 2.0s; }
.boot-telemetry.b { top: 44px; right: 96px; text-align: right; animation-delay: 2.15s; }
.boot-telemetry.c { bottom: 44px; left: 96px; animation-delay: 2.3s; }
.boot-telemetry.d { bottom: 44px; right: 96px; text-align: right; animation-delay: 2.45s; }
.boot-telemetry span { color: var(--accent-bright); }

/* Both boot-center ignites (mid-sequence flash once the mark locks in,
   and the bigger end-of-sequence "ready" flash) run on this same
   element, so they're combined here as one rule using CSS's native
   comma-separated multi-animation syntax — each animation-* property
   gets two comma-separated values, positionally matched by index.
   This is NOT the same as giving the element two classes that each set
   animation-name independently: two separate declarations of the same
   property on the same element only ever let one of them win, longhand
   or not. A single rule with a two-item comma list is what actually
   layers two animations on one element. */
.boot-center {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  animation-name: boot-ignite, boot-ignite-big;
  animation-duration: 0.5s, 0.7s;
  animation-timing-function: var(--ease), var(--ease);
  animation-fill-mode: forwards, forwards;
  animation-delay: 3.55s, 8.5s;
}

@keyframes boot-ignite {
  0%   { filter: brightness(1); }
  35%  { filter: brightness(1.55); }
  100% { filter: brightness(1); }
}

.boot-mark-wrap {
  position: relative;
  width: 168px;
  height: 168px;
  margin-bottom: 8px;
  /* a constant soft glow on the mark's linework itself (not tied to
     the flash beats, which .boot-mark-wrap::before/::after already
     cover) — this is what makes the green strokes read as lit from
     within rather than flat-colored vector lines once the sequence
     settles */
  filter: drop-shadow(0 0 6px rgba(76, 199, 76, 0.35));
}
.boot-mark-wrap::before {
  content: "";
  position: absolute;
  inset: -30%;
  background: radial-gradient(circle, rgba(76, 199, 76, 0.5), transparent 65%);
  opacity: 0;
  animation: boot-flash 1.1s var(--ease) forwards;
  animation-delay: 1.05s;
}
/* a second flash bloom tied to the mid-sequence ignite above, echoing
   the opening flash now that the mark is fully built */
.boot-mark-wrap::after {
  content: "";
  position: absolute;
  inset: -45%;
  background: radial-gradient(circle, rgba(76, 199, 76, 0.4), transparent 60%);
  opacity: 0;
  animation: boot-flash 1s var(--ease) forwards;
  animation-delay: 3.55s;
}

.boot-mark { width: 100%; height: 100%; overflow: visible; }

/* orbital rings — slow continuous rotation once drawn in, counter to
   each other for a layered turbine effect around the static mark */
.boot-orbit {
  fill: none;
  stroke: var(--accent);
  stroke-width: 0.75;
  opacity: 0;
  stroke-dasharray: 4 10;
  transform-origin: 100px 100px;
}
.boot-orbit-1 {
  animation: boot-draw 1.8s var(--ease) forwards, boot-orbit-fade-in 0.4s linear forwards, boot-spin 14s linear infinite;
  animation-delay: 0.15s, 0.15s, 1.95s;
  stroke-dasharray: 820;
  stroke-dashoffset: 820;
}
.boot-orbit-2 {
  stroke: var(--accent-bright);
  stroke-dasharray: 4 14;
  animation: boot-orbit-fade-in 0.5s linear forwards, boot-spin-rev 10s linear infinite;
  animation-delay: 1.35s, 1.35s;
}

@keyframes boot-orbit-fade-in {
  to { opacity: 0.4; }
}
@keyframes boot-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
@keyframes boot-spin-rev {
  from { transform: rotate(0deg); }
  to { transform: rotate(-360deg); }
}

.boot-mark-halo {
  fill: none;
  stroke: var(--accent-bright);
  stroke-width: 1;
  opacity: 0.5;
  stroke-dasharray: 560;
  stroke-dashoffset: 560;
  /* two animations on this element: the one-shot draw-on, and a
     continuous subtle "breathing" opacity drift that starts once
     everything else has settled, so the held frame is never fully
     static. Comma-separated longhand (not a second class) — see the
     .boot-center rule above for why a second class would silently
     lose this animation instead of layering it. */
  animation-name: boot-draw, boot-halo-breathe;
  animation-duration: 1.4s, 3.4s;
  animation-timing-function: var(--ease), ease-in-out;
  animation-delay: 0.3s, 4.2s;
  animation-iteration-count: 1, infinite;
  animation-direction: normal, alternate;
  animation-fill-mode: forwards, none;
}

.boot-mark-facet {
  fill: none;
  stroke: var(--accent);
  stroke-width: 3;
  stroke-linejoin: round;
  stroke-dasharray: 480;
  stroke-dashoffset: 480;
  animation: boot-draw 1.1s var(--ease) forwards;
}
.boot-mark-facet-1 { animation-delay: 0.5s; stroke: var(--accent); }
.boot-mark-facet-2 { animation-delay: 0.85s; stroke: var(--accent-bright); stroke-dasharray: 360; }
/* a third, innermost facet pass — the hex mark now assembles from the
   outside in across three strokes instead of two, reading as a more
   deliberate multi-stage build */
.boot-mark-facet-3 {
  animation-delay: 1.15s;
  stroke: var(--accent-bright);
  stroke-dasharray: 240;
  stroke-width: 2;
  opacity: 0.85;
}

.boot-mark-stem {
  stroke: var(--accent-bright);
  stroke-width: 4;
  stroke-linecap: square;
  stroke-dasharray: 60;
  stroke-dashoffset: 60;
  animation: boot-draw 0.5s var(--ease) forwards;
  animation-delay: 1.4s;
}

.boot-mark-core {
  fill: var(--accent-bright);
  opacity: 0;
  transform-origin: 100px 122px;
  animation-name: boot-core-pulse, boot-core-breathe;
  animation-duration: 0.6s, 2.6s;
  animation-timing-function: var(--ease), ease-in-out;
  animation-delay: 1.6s, 4.2s;
  animation-iteration-count: 1, infinite;
  animation-direction: normal, alternate;
  animation-fill-mode: forwards, none;
}

/* radial spokes fire outward once the mark locks into place — six
   short strokes fanning from the halo edge, like energy discharging
   the instant the build completes */
.boot-spoke {
  stroke: var(--accent);
  stroke-width: 1;
  opacity: 0;
  transform-origin: 100px 100px;
  stroke-dasharray: 30;
  stroke-dashoffset: 30;
  animation: boot-spoke-fire 0.7s var(--ease) forwards;
}

@keyframes boot-spoke-fire {
  0%   { opacity: 0; stroke-dashoffset: 30; }
  30%  { opacity: 0.7; }
  100% { opacity: 0; stroke-dashoffset: 0; }
}

@keyframes boot-draw {
  to { stroke-dashoffset: 0; }
}
/* subtle continuous idle drift for .boot-mark-halo — small enough
   that it reads as the ring gently pulsing with light rather than
   as a distinct "effect", which is what keeps a held frame feeling
   alive without drawing attention to itself */
@keyframes boot-halo-breathe {
  from { opacity: 0.5; }
  to   { opacity: 0.72; }
}
@keyframes boot-flash {
  0% { opacity: 0; transform: scale(0.5); }
  40% { opacity: 1; transform: scale(1.05); }
  100% { opacity: 0; transform: scale(1.5); }
}
@keyframes boot-core-pulse {
  0% { opacity: 0; transform: scale(0.3); }
  60% { opacity: 1; transform: scale(1.4); }
  100% { opacity: 1; transform: scale(1); }
}

/* continuous idle drift for the core dot, picking up from scale(1)
   where boot-core-pulse leaves off — a faint breathing pulse rather
   than a static full stop */
@keyframes boot-core-breathe {
  from { transform: scale(1); }
  to   { transform: scale(1.18); }
}

.boot-wordmark {
  display: flex;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 2.8rem;
  letter-spacing: 0.02em;
  color: var(--text);
  margin-top: 22px;
}
.boot-letter {
  opacity: 0;
  display: inline-block;
  transform: translateY(14px);
  filter: blur(4px);
  animation: boot-letter-in 0.6s var(--ease-arrive) forwards;
  animation-delay: calc(3.75s + (var(--i) * 0.1s));
}
.boot-letter:first-child { color: var(--accent-bright); }

@keyframes boot-letter-in {
  to { opacity: 1; transform: translateY(0); filter: blur(0); }
}

.boot-subword {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  letter-spacing: 0.5em;
  color: var(--muted);
  margin-top: 8px;
  padding-left: 0.5em;
  opacity: 0;
  transform: translateY(6px);
  animation: boot-subword-in 0.6s var(--ease-glide) forwards;
  animation-delay: 4.75s;
}

@keyframes boot-subword-in {
  to { opacity: 1; transform: translateY(0); }
}

/* tagline — a second line beneath the subword, thin divider rules on
   either side, reinforcing what the product actually does now that
   there's more time in the sequence to say it */
.boot-tagline {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 14px;
  opacity: 0;
  animation: boot-subword-in 0.6s var(--ease-glide) forwards;
  animation-delay: 5.15s;
}
.boot-tagline-line {
  width: 20px;
  height: 1px;
  background: var(--border-hover);
}
.boot-tagline-text {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.15em;
  color: var(--muted-dim);
  text-transform: uppercase;
}

.boot-status {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  margin-top: 40px;
  opacity: 0;
  animation: boot-subword-in 0.5s var(--ease-glide) forwards;
  animation-delay: 5.6s;
}

.boot-status-bar {
  width: 160px;
  height: 2px;
  background: var(--border);
  position: relative;
  overflow: hidden;
  border-radius: 1px;
}
/* three sequential fill stages instead of one continuous fill — reads
   as independent subsystems reporting in one after another, timed to
   match each status line change below rather than a single sweep */
.boot-status-bar::after {
  content: "";
  position: absolute;
  inset: 0;
  /* brighter at the trailing edge than the body of the fill, so the
     bar reads as having a lit leading tip pushing forward rather than
     a flat block sliding into place */
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent-bright) 82%, #d4ffd4 100%);
  transform-origin: left;
  transform: scaleX(0);
  animation: boot-bar-stage-1 1s var(--ease) forwards,
             boot-bar-stage-2 1s var(--ease) forwards,
             boot-bar-stage-3 1.3s var(--ease) forwards;
  animation-delay: 5.6s, 6.7s, 7.8s;
}

@keyframes boot-bar-stage-1 { to { transform: scaleX(0.38); } }
@keyframes boot-bar-stage-2 { to { transform: scaleX(0.72); } }
@keyframes boot-bar-stage-3 { to { transform: scaleX(1); } }

#boot-status-text {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--muted-dim);
  text-transform: uppercase;
  position: relative;
  display: inline-block;
  height: 1.2em;
}
.boot-status-line {
  position: absolute;
  left: 0;
  right: 0;
  opacity: 0;
  white-space: nowrap;
  animation: boot-status-cycle 1.3s var(--ease) forwards;
}
.boot-status-line:nth-child(1) { animation-delay: 5.6s; }
.boot-status-line:nth-child(2) { animation-delay: 6.7s; }
/* the final line uses a dedicated class rather than nth-child, so it
   unambiguously stays lit instead of cycling back out like the two
   before it — matches the real "Establishing session" copy the app
   itself used previously, now arrived at rather than starting there */
.boot-status-line.is-final {
  animation-name: boot-status-cycle-final;
  animation-delay: 7.8s;
  color: var(--accent-bright);
}

@keyframes boot-status-cycle {
  0%   { opacity: 0; transform: translateY(4px); }
  12%  { opacity: 1; transform: translateY(0); }
  82%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(-4px); }
}
@keyframes boot-status-cycle-final {
  0%   { opacity: 0; transform: translateY(4px); }
  12%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 1; transform: translateY(0); }
}

/* the "ready" flash keyframes referenced by .boot-center's second
   animation-name entry above — bigger brightness spike than the first
   ignite, timed for once every subsystem line has reported in and the
   status bar has fully filled */
@keyframes boot-ignite-big {
  0%   { filter: brightness(1); }
  30%  { filter: brightness(1.9); }
  100% { filter: brightness(1); }
}

#boot-skip {
  position: absolute;
  bottom: 28px;
  right: 32px;
  display: flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: none;
  color: var(--muted-dim);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.05em;
  cursor: pointer;
  opacity: 0;
  animation: boot-subword-in 0.5s var(--ease-glide) forwards;
  animation-delay: 1.6s;
  z-index: 2;
}
#boot-skip:hover { color: var(--text); }
.boot-skip-key {
  border: 1px solid var(--border-hover);
  border-radius: 3px;
  padding: 1px 6px;
  font-size: 0.68rem;
}

/* Narrow viewports: the HUD corner brackets + telemetry readouts are
   a desktop-scale flourish, comfortably spaced at 40px+ from each
   screen edge. Below ~560px there isn't room for both the frame and
   the telemetry text without them colliding, so the telemetry text
   drops and the brackets pull in — the core mark/wordmark/status
   sequence is unaffected either way. */
@media (max-width: 560px) {
  .boot-telemetry { display: none; }
  .boot-corner { width: 34px; height: 34px; }
  .boot-corner.tl, .boot-corner.tr { top: 22px; }
  .boot-corner.bl, .boot-corner.br { bottom: 22px; }
  .boot-corner.tl, .boot-corner.bl { left: 22px; }
  .boot-corner.tr, .boot-corner.br { right: 22px; }
  .boot-wordmark { font-size: 2.1rem; }
  .boot-mark-wrap { width: 132px; height: 132px; }
}

@media (prefers-reduced-motion: reduce) {
  #boot-screen * { animation: none !important; }
  .boot-mark-halo { stroke-dashoffset: 0; opacity: 0.6; }
  .boot-mark-facet, .boot-mark-stem { stroke-dashoffset: 0; opacity: 1; }
  .boot-mark-core, .boot-letter, .boot-subword, .boot-tagline, .boot-status, .boot-corner, #boot-skip {
    opacity: 1; transform: none; filter: none;
  }
  .boot-corner { opacity: 0.55; }
  .boot-status-bar::after { transform: scaleX(1); }
  .boot-grid, .boot-grid-far { opacity: 1; }
  .boot-poweron, .boot-scanline, .boot-mark-wrap::before, .boot-mark-wrap::after,
  .boot-spoke, .boot-corner path { opacity: 0; }
  .boot-orbit-1, .boot-orbit-2 { opacity: 0; }
  .boot-telemetry { opacity: 1; }
  /* only the final status line should render; the two that precede it
     would otherwise all sit stacked at full opacity simultaneously
     once animation is disabled, since nothing is left to sequence
     them apart */
  .boot-status-line { opacity: 0; }
  .boot-status-line.is-final { opacity: 1; transform: none; }
}
.muted { color: var(--muted); }
.small { font-size: 0.85rem; }

:focus-visible {
  outline: 2px solid var(--accent-bright);
  outline-offset: 2px;
}

.screen { height: 100%; }

/* --------------------------------------------------------------------
   Signature element: the power glyph. A ring broken by a vertical
   stroke — the universal "power" symbol, redrawn angular/geometric to
   match the rest of the identity. Idle: static outline. Working:
   segments pulse in sequence, like a console boot animation.
   -------------------------------------------------------------------- */

.power-glyph {
  width: 84px;
  height: 84px;
  display: block;
}

.power-glyph .ring {
  fill: none;
  stroke: var(--accent);
  stroke-width: 6;
  stroke-linecap: square;
  transition: stroke 0.3s var(--ease);
}

.power-glyph .stem {
  stroke: var(--accent);
  stroke-width: 6;
  stroke-linecap: square;
  transition: stroke 0.3s var(--ease);
}

.power-glyph.active .ring {
  stroke: var(--accent-bright);
  animation: glyph-pulse 1.6s ease-in-out infinite;
}
.power-glyph.active .stem {
  stroke: var(--accent-bright);
  animation: glyph-pulse 1.6s ease-in-out infinite 0.15s;
}

@keyframes glyph-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

/* --------------------------------------------------------------------
   Signature element #2: signal bars. A small angular bar-graph, the
   same vocabulary as broadcast/connection-strength indicators, driven
   by REAL connection state rather than looping decoratively — idle
   (all bars dim), connecting (bars climb in sequence), connected (all
   lit, steady), error (bars flatten red). app.js sets data-state on
   .signal-bars to switch between these; nothing here animates unless
   the state genuinely changes.
   -------------------------------------------------------------------- */

.signal-bars {
  display: inline-flex;
  align-items: flex-end;
  gap: 3px;
  height: 16px;
}

.signal-bars .bar {
  width: 4px;
  background: var(--muted-dim);
  border-radius: 1px;
  transition: background 0.25s var(--ease), transform 0.25s var(--ease);
  transform-origin: bottom;
}
.signal-bars .bar:nth-child(1) { height: 40%; }
.signal-bars .bar:nth-child(2) { height: 65%; }
.signal-bars .bar:nth-child(3) { height: 85%; }
.signal-bars .bar:nth-child(4) { height: 100%; }

.signal-bars[data-state="connecting"] .bar {
  background: var(--signal);
  animation: bar-climb 1.1s var(--ease) infinite;
}
.signal-bars[data-state="connecting"] .bar:nth-child(1) { animation-delay: 0s; }
.signal-bars[data-state="connecting"] .bar:nth-child(2) { animation-delay: 0.1s; }
.signal-bars[data-state="connecting"] .bar:nth-child(3) { animation-delay: 0.2s; }
.signal-bars[data-state="connecting"] .bar:nth-child(4) { animation-delay: 0.3s; }

@keyframes bar-climb {
  0%, 100% { opacity: 0.3; transform: scaleY(0.5); }
  50% { opacity: 1; transform: scaleY(1); }
}

.signal-bars[data-state="connected"] .bar {
  background: var(--accent-bright);
}

.signal-bars[data-state="error"] .bar {
  background: var(--error);
  transform: scaleY(0.35);
}

/* --------------------------------------------------------------------
   Sign-in / status — asymmetric split, console-tile texture on the
   idle side rather than a centered generic card.
   -------------------------------------------------------------------- */

#screen-signin, #screen-status {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  min-height: 100%;
}

@media (max-width: 760px) {
  #screen-signin, #screen-status {
    grid-template-columns: 1fr;
  }
  .brand-pane { display: none; }
}

.brand-pane {
  background: var(--bg-raised);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  padding: 0 10%;
  position: relative;
  overflow: hidden;
}

.brand-pane::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
    115deg,
    transparent 0 68px,
    rgba(16, 124, 16, 0.05) 68px 69px
  );
  pointer-events: none;
}

.brand-pane .power-glyph { margin-bottom: 28px; }

.brand-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent-bright);
  margin: 0 0 10px;
}

.brand-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-stretch: condensed;
  font-size: 2.6rem;
  letter-spacing: -0.01em;
  line-height: 1.02;
  margin: 0;
  z-index: 1;
}

.brand-sub {
  color: var(--muted);
  font-size: 0.95rem;
  max-width: 34ch;
  margin: 14px 0 0;
  z-index: 1;
}

.action-pane {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px;
}

.card {
  width: 100%;
  max-width: 380px;
  text-align: left;
}

.card h1 { display: none; } /* title now lives in .brand-pane */

.card-kicker {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-dim);
  margin: 0 0 6px;
}

.card-heading {
  font-size: 1.3rem;
  font-weight: 700;
  margin: 0 0 20px;
}

.tab-row {
  display: flex;
  gap: 4px;
  margin-bottom: 24px;
  border-bottom: 1px solid var(--border);
}

.tab-btn {
  background: none;
  border: none;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 10px 4px 12px;
  margin-right: 20px;
  cursor: pointer;
  position: relative;
  transition: color 0.15s ease;
}
.tab-btn:hover { color: var(--text); }
.tab-btn.active { color: var(--accent-bright); }
.tab-btn.active::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--accent-bright);
  box-shadow: 0 0 6px var(--accent-bright);
}

.account-form { display: flex; flex-direction: column; }

.field-label {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--muted);
  margin: 14px 0 6px;
}
.field-label:first-of-type { margin-top: 0; }

.field-input {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 11px 12px;
  color: var(--text);
  font-family: var(--font-body);
  font-size: 0.92rem;
  width: 100%;
}
.field-input:focus {
  outline: none;
  border-color: var(--accent);
}

.field-hint {
  font-size: 0.78rem;
  color: var(--muted-dim);
  margin: 6px 0 0;
}

.account-form .btn-primary { margin-top: 22px; }

.btn-primary {
  width: 100%;
  padding: 13px 18px;
  border: none;
  border-radius: 4px;
  background: var(--accent);
  color: #eafff0;
  font-weight: 600;
  font-size: 0.95rem;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background 0.2s var(--ease), transform 0.15s var(--ease), box-shadow 0.2s var(--ease);
}
.btn-primary:hover {
  background: var(--accent-bright);
  color: #06130a;
  box-shadow: var(--shadow-glow);
}
.btn-primary:active { transform: scale(0.98); box-shadow: var(--shadow-sm); }

.btn-link {
  background: none;
  border: none;
  color: var(--muted);
  cursor: pointer;
  font-size: 0.9rem;
  padding: 0;
}
.btn-link:hover { color: var(--text); }

.error {
  color: var(--error);
  margin-top: 16px;
  font-size: 0.9rem;
  padding-left: 10px;
  border-left: 2px solid var(--error);
}

#device-code-box {
  margin-top: 24px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
}

.link-big {
  display: inline-block;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--accent-bright);
  text-decoration: none;
  margin: 4px 0;
  font-family: var(--font-mono);
}
.link-big:hover { text-decoration: underline; }

.code {
  font-family: var(--font-mono);
  font-size: 2rem;
  letter-spacing: 0.35rem;
  font-weight: 700;
  margin: 12px 0;
  color: var(--text);
  background: #00000059;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 4px;
  padding: 12px 0 12px 0.35rem;
}

#screen-status .action-pane { flex-direction: column; }
#screen-status .power-glyph { margin: 0 auto 24px; }
#screen-status .card { text-align: center; }
#screen-status .code { display: none; }

/* --------------------------------------------------------------------
   Library — the dashboard proper.
   -------------------------------------------------------------------- */

#screen-library { display: flex; flex-direction: column; }

.topbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 28px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-raised);
  position: relative;
}
.topbar::after {
  content: "";
  position: absolute;
  bottom: -1px; left: 0; right: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(76, 199, 76, 0.4), transparent);
}

.topbar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  font-family: var(--font-display);
  font-stretch: condensed;
  letter-spacing: -0.01em;
}

.topbar-brand .power-glyph { width: 26px; height: 26px; }

.topbar-actions {
  display: flex;
  align-items: center;
  gap: 16px;
}

.topbar-username {
  font-family: var(--font-mono);
}

.topbar-divider {
  width: 1px;
  height: 16px;
  background: var(--border);
}

.library-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--border);
  overflow-y: auto;
}

.panel {
  background: var(--bg);
  padding: 28px;
}

.panel-consoles { flex: 0 0 auto; }
.panel-catalog { flex: 1; }

.panel h2 {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted-dim);
  margin: 0 0 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}

.panel-heading-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 12px;
  margin-bottom: 16px;
}
.panel-heading-row h2 { border-bottom: none; padding-bottom: 0; margin: 0; }

.catalog-search input {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 7px 12px;
  color: var(--text);
  font-size: 0.85rem;
  width: 200px;
  max-width: 100%;
  font-family: var(--font-body);
}
.catalog-search input:focus {
  outline: none;
  border-color: var(--accent);
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 14px;
}

.grid-consoles {
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}

.grid-catalog {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 20px 16px;
  margin-bottom: 20px;
}

.console-tile {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 18px;
  cursor: pointer;
  text-align: left;
  position: relative;
  transition: border-color 0.2s var(--ease), transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.console-tile:hover {
  border-color: var(--accent);
  transform: translateY(-3px);
  box-shadow: var(--shadow-glow);
}
.console-tile:hover::after { opacity: 1; }
.console-tile:focus-visible {
  border-color: var(--accent);
  transform: translateY(-3px);
  box-shadow: var(--shadow-glow);
}
.console-tile:focus-visible::after { opacity: 1; }
.console-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 6px;
  box-shadow: 0 0 0 1px var(--accent) inset;
  opacity: 0;
  transition: opacity 0.2s var(--ease);
  pointer-events: none;
}
.console-tile h3 {
  margin: 0 0 6px;
  font-size: 0.95rem;
  font-weight: 700;
}
.console-tile .status-row {
  display: flex;
  align-items: center;
  gap: 6px;
}
.console-tile .status-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--muted-dim);
  flex-shrink: 0;
}
.console-tile:not(.offline) .status-dot {
  background: var(--accent-bright);
  box-shadow: 0 0 6px var(--accent-bright);
}
.console-tile.offline {
  opacity: 0.55;
  cursor: not-allowed;
}
.console-tile.offline:hover {
  transform: none;
  border-color: var(--border);
}
.console-tile.offline:hover::after { opacity: 0; }

/* Game Pass catalog cards — box art is the whole point, so the card is
   mostly image with a thin caption, not a text-forward tile like the
   console cards. */
.game-card {
  cursor: pointer;
  border-radius: 6px;
  outline-offset: 3px;
}

.game-art {
  position: relative;
  aspect-ratio: 2 / 3;
  border-radius: 6px;
  overflow: hidden;
  background: var(--panel);
  border: 1px solid var(--border);
  transition: border-color 0.2s var(--ease), transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
/* HUD corner brackets — the same device and color used to frame the
   mark in the boot sequence, reused here as the selection indicator
   rather than a new, disconnected hover treatment. A single
   pseudo-element, 8 comma-matched gradient layers (2 short segments
   per corner), inset from the edges so it reads as framing the art
   rather than touching it. Sits within .game-art's own box, so the
   parent's overflow:hidden never clips it. */
.game-art::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.2s var(--ease);
  pointer-events: none;
  background-repeat: no-repeat;
  background-image:
    linear-gradient(var(--accent-bright), var(--accent-bright)),
    linear-gradient(var(--accent-bright), var(--accent-bright)),
    linear-gradient(var(--accent-bright), var(--accent-bright)),
    linear-gradient(var(--accent-bright), var(--accent-bright)),
    linear-gradient(var(--accent-bright), var(--accent-bright)),
    linear-gradient(var(--accent-bright), var(--accent-bright)),
    linear-gradient(var(--accent-bright), var(--accent-bright)),
    linear-gradient(var(--accent-bright), var(--accent-bright));
  background-position:
    left 8px top 8px, left 8px top 8px,
    right 8px top 8px, right 8px top 8px,
    left 8px bottom 8px, left 8px bottom 8px,
    right 8px bottom 8px, right 8px bottom 8px;
  background-size:
    18px 2px, 2px 18px,
    18px 2px, 2px 18px,
    18px 2px, 2px 18px,
    18px 2px, 2px 18px;
}
.game-card:hover .game-art,
.game-card:focus-visible .game-art {
  border-color: var(--accent);
  transform: translateY(-4px);
  box-shadow: var(--shadow-glow);
}
.game-card:hover .game-art::after,
.game-card:focus-visible .game-art::after {
  opacity: 1;
}

.game-art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.game-art-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
}
.game-art-fallback::before {
  content: "";
  width: 32px;
  height: 32px;
  border: 4px solid var(--muted-dim);
  border-radius: 50%;
  border-top-color: transparent;
  transform: rotate(45deg);
}
.game-art-fallback img { display: none; }

.game-play-badge {
  position: absolute;
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%) translateY(6px);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 13px;
  border-radius: 4px;
  border: 1px solid var(--accent-bright);
  background: var(--bg);
  box-shadow: var(--shadow-glow);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-bright);
  opacity: 0;
  transition: opacity 0.2s var(--ease), transform 0.2s var(--ease);
}
/* "Play" label goes first via ::before, ahead of the triangle glyph
   app.js sets as the badge's actual text content — no JS change
   needed to get a "Play ▶" chip instead of a bare icon */
.game-play-badge::before {
  content: "Play";
}
.game-card:hover .game-play-badge,
.game-card:focus-visible .game-play-badge {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.game-title {
  margin: 8px 2px 0;
  font-size: 0.82rem;
  font-weight: 600;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.manual-launch {
  margin-top: 8px;
  border-top: 1px solid var(--border);
  padding-top: 16px;
}
.manual-launch summary {
  cursor: pointer;
  color: var(--muted);
  font-size: 0.85rem;
  user-select: none;
}
.manual-launch summary:hover { color: var(--text); }
.manual-launch .cloud-launch { margin-top: 12px; }

.cloud-launch { display: flex; gap: 8px; }
.cloud-launch input {
  flex: 1;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 11px 12px;
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 0.9rem;
}
.cloud-launch input:focus {
  outline: none;
  border-color: var(--accent);
}
.cloud-launch .btn-primary { width: auto; padding: 11px 20px; }

/* --------------------------------------------------------------------
   Stream screen
   -------------------------------------------------------------------- */

#screen-stream { position: relative; background: #000; }

#streamHolder, #streamHolder video {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.hud {
  position: absolute;
  top: 0; left: 0; right: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 12px 20px;
  background: linear-gradient(to bottom, rgba(0,0,0,0.75), transparent);
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.hud .btn-link { font-weight: 600; }

.hud-right {
  display: flex;
  align-items: center;
  gap: 10px;
}

.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  padding: 5px 10px 5px 8px;
  border-radius: 4px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.35);
  color: var(--muted);
  transition: border-color 0.25s var(--ease), color 0.25s var(--ease);
}
.status-badge[data-state="connecting"] { border-color: rgba(255, 176, 32, 0.35); color: var(--signal); }
.status-badge[data-state="connected"] {
  border-color: rgba(76, 199, 76, 0.4);
  color: var(--accent-bright);
  /* deliberately smaller than --shadow-glow (that token's 28px blur is
     sized for elevated cards) — this sits persistently on top of
     active video, so it stays a subtle accent rather than competing
     for attention the way a card-scale glow would */
  box-shadow: 0 0 10px -2px rgba(76, 199, 76, 0.45);
}
.status-badge[data-state="error"] { border-color: rgba(229, 72, 77, 0.4); color: var(--error); }

.status-badge .signal-bars { height: 12px; }
.status-badge .signal-bars .bar { width: 3px; }

#input-indicator {
  font-family: var(--font-mono);
  padding: 3px 8px;
  border: 1px solid var(--border);
  border-radius: 3px;
}

.btn-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
  cursor: pointer;
}
.btn-icon:hover { border-color: var(--accent); background: rgba(255, 255, 255, 0.08); }
/* app.js toggles this on fullscreen enter/exit — no rule existed for
   it at all, so the button gave zero visual confirmation either way */
.btn-icon.is-active {
  border-color: var(--accent-bright);
  background: rgba(76, 199, 76, 0.12);
  color: var(--accent-bright);
}
.btn-icon svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* While actually in fullscreen, fade the HUD out unless the pointer is
   moving / a key was just pressed — app.js toggles .hud-visible on
   #screen-stream to control this. Not fullscreen: HUD stays put, no
   surprises for the non-fullscreen case. */
#screen-stream:fullscreen .hud,
#screen-stream:-webkit-full-screen .hud {
  opacity: 0;
  pointer-events: none;
}
#screen-stream.hud-visible .hud {
  opacity: 1;
  pointer-events: auto;
}

/* --------------------------------------------------------------------
   Toasts — transient confirmations (code copied, signed out, catalog
   refreshed). Persistent/blocking errors stay as inline .error text
   next to their source, on purpose: a toast that disappears is wrong
   for something the person still needs to act on.
   -------------------------------------------------------------------- */

#toast-stack {
  position: fixed;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1000;
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  gap: 8px;
  pointer-events: none;
}

.toast {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  border-radius: 6px;
  background: var(--bg-raised);
  border: 1px solid var(--border-hover);
  box-shadow: var(--shadow-lg);
  font-size: 0.85rem;
  color: var(--text);
  animation: toast-in 0.3s var(--ease);
}
.toast.leaving { animation: toast-out 0.25s var(--ease) forwards; }
.toast::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--accent-bright);
  flex-shrink: 0;
}
.toast.toast-error::before { background: var(--error); }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px) scale(0.96); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes toast-out {
  to { opacity: 0; transform: translateY(8px) scale(0.96); }
}

/* --------------------------------------------------------------------
   Skeleton loaders — catalog grid placeholders while /api/catalog is
   in flight, matching the real game-card shape so the layout doesn't
   jump once real cards arrive.
   -------------------------------------------------------------------- */

.skeleton-card { pointer-events: none; }
.skeleton-art {
  aspect-ratio: 2 / 3;
  border-radius: 6px;
  background: linear-gradient(100deg, var(--panel) 40%, var(--bg-raised) 50%, var(--panel) 60%);
  background-size: 200% 100%;
  animation: skeleton-sweep 1.6s ease-in-out infinite;
  border: 1px solid var(--border);
}
.skeleton-title {
  height: 12px;
  width: 80%;
  margin: 10px 2px 0;
  border-radius: 3px;
  background: linear-gradient(100deg, var(--panel) 40%, var(--bg-raised) 50%, var(--panel) 60%);
  background-size: 200% 100%;
  animation: skeleton-sweep 1.6s ease-in-out infinite;
}

@keyframes skeleton-sweep {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* --------------------------------------------------------------------
   Copy button — device code, quality-of-life addition next to the
   large code readout on the sign-in screen.
   -------------------------------------------------------------------- */

.code-row {
  display: flex;
  align-items: stretch;
  gap: 8px;
}
.code-row .code { flex: 1; margin: 12px 0; }

.btn-copy {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  flex-shrink: 0;
  margin: 12px 0;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--bg-raised);
  color: var(--muted);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.btn-copy:hover { border-color: var(--accent); color: var(--accent-bright); }
.btn-copy svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.btn-copy.copied { border-color: var(--accent-bright); color: var(--accent-bright); }
