/* ============================================================
 * style_glass.css — the Liquid Glass design system
 * ============================================================
 *
 * The refraction lives in JS (ui/liquid_glass.js), because it needs a per-element
 * displacement map. This file supplies everything the shader cannot:
 *
 *   - the SPECULAR RIM: a lit edge and a shaded edge. Two-tone, not one. A single
 *     uniform border is why the old panels read as "a box with a stroke" — real glass has
 *     a bright side and a dark side, because light comes from somewhere.
 *   - the INNER BLOOM: light that got caught inside the pane.
 *   - the ELEVATION: a shadow that says "floating above the scene", not "drop shadow".
 *   - the FALLBACK: a deliberate frosted look for Firefox/Safari, which cannot use an SVG
 *     filter as a backdrop-filter. It must look intentional, never broken.
 *
 * AND THE RULE THAT FIXES THE SCROLLING:
 * A panel is sized by the VIEWPORT, not by its content. If the content will not fit, the
 * content collapses (tabs, grids) — the panel never grows and then asks the user to scroll
 * to find its own action button. That was the single worst UX failure in the last pass.
 * ============================================================ */

:root {
  /* Glass is a stack of layers, not a colour. */
  --lg-tint:      oklch(100% 0 0 / 0.13);
  --lg-tint-warm: oklch(100% 0 0 / 0.20);
  --lg-rim-lit:   oklch(100% 0 0 / 0.75);   /* the side facing the light */
  --lg-rim-dark:  oklch(55% 0.03 260 / 0.22); /* the side facing away     */
  --lg-bloom:     oklch(100% 0 0 / 0.55);
  --lg-shadow:    oklch(28% 0.05 262 / 0.30);

  --lg-ink:       oklch(26% 0.03 262);
  --lg-ink-soft:  oklch(38% 0.02 262 / 0.74);
  --lg-accent:    oklch(62% 0.17 235);

  --lg-r:         26px;
  --lg-ease:      cubic-bezier(0.22, 1, 0.36, 1);
  --lg-spring:    cubic-bezier(0.34, 1.56, 0.64, 1);
}

@property --lg-sheen { syntax: '<angle>'; inherits: false; initial-value: 0deg; }

/* ── The pane ──────────────────────────────────────────────────────────────── */

.lg {
  position: relative;
  isolation: isolate;
  border-radius: var(--lg-r);

  /* The body. Kept LOW opacity on purpose: the refraction is the effect, and a heavy
     tint would drown it. The old panels were opaque enough to hide the very thing that
     makes them glass. */
  background: linear-gradient(158deg, var(--lg-tint-warm), var(--lg-tint) 45%);

  /* Fallback until JS upgrades it (and permanently on Firefox/Safari). */
  backdrop-filter: blur(24px) saturate(1.7);
  -webkit-backdrop-filter: blur(24px) saturate(1.7);

  border: 1px solid transparent;

  box-shadow:
    /* lit rim, top-left */
    inset 1.2px 1.2px 0 var(--lg-rim-lit),
    /* shaded rim, bottom-right — the pair is what gives it THICKNESS */
    inset -1.2px -1.2px 0 var(--lg-rim-dark),
    /* light caught inside the pane */
    inset 0 22px 46px -26px var(--lg-bloom),
    /* floating */
    0 28px 80px -24px var(--lg-shadow),
    0 5px 16px -8px oklch(28% 0.05 262 / 0.2);
}

/* Once refraction is live we can pull the frosting right back — the lens is doing the
   work now, and a heavy blur would just smear what it bent. */
.lg.lg-live {
  background: linear-gradient(158deg, oklch(100% 0 0 / 0.10), oklch(100% 0 0 / 0.05) 50%);
}

/* The travelling specular. Real glass catches a highlight that MOVES across it. */
.lg::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: -1;
  background: conic-gradient(from var(--lg-sheen),
    transparent 0deg,
    oklch(100% 0 0 / 0.20) 32deg,
    oklch(100% 0 0 / 0.05) 62deg,
    transparent 100deg,
    transparent 360deg);
}
@media (prefers-reduced-motion: no-preference) {
  .lg::before { animation: lg-sheen 16s linear infinite; }
}
@keyframes lg-sheen { to { --lg-sheen: 360deg; } }

/* A hairline of light along the very top edge — the "wet" look. */
.lg::after {
  content: '';
  position: absolute;
  top: 0; left: 12%; right: 12%;
  height: 1px;
  border-radius: 1px;
  pointer-events: none;
  background: linear-gradient(90deg,
    transparent,
    oklch(100% 0 0 / 0.9) 35%,
    oklch(100% 0 0 / 0.9) 65%,
    transparent);
}

/* Firefox / Safari: no SVG backdrop filter. Lean into frost rather than fake refraction —
   a deliberate material, not a broken one. */
html.lg-fallback .lg {
  background: linear-gradient(158deg, oklch(100% 0 0 / 0.30), oklch(100% 0 0 / 0.18) 50%);
  backdrop-filter: blur(30px) saturate(1.9);
  -webkit-backdrop-filter: blur(30px) saturate(1.9);
}

/* Transparency off, or high contrast: go solid. Legibility beats material every time. */
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .lg, html.lg-fallback .lg {
    background: oklch(98% 0.005 250 / 0.97);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border-color: var(--lg-ink);
  }
  .lg::before, .lg::after { display: none; }
}

/* ── THE CLOSE CHIP — top RIGHT, always ─────────────────────────────────────
   It was a bare ✕ in the top-LEFT, which is simply the wrong corner and the wrong
   component. This is a glass chip: circular, hairline rim, lift on hover, and the X
   rotates into place. */

.lg-close {
  position: absolute;
  top: 14px;
  right: 14px;              /* RIGHT. */
  z-index: 5;

  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;

  border-radius: 50%;
  border: 1px solid oklch(100% 0 0 / 0.5);
  background: oklch(100% 0 0 / 0.32);
  backdrop-filter: blur(12px) saturate(1.6);
  -webkit-backdrop-filter: blur(12px) saturate(1.6);
  box-shadow:
    inset 0 1px 0 oklch(100% 0 0 / 0.8),
    0 3px 10px -3px oklch(28% 0.05 262 / 0.3);

  color: var(--lg-ink);
  cursor: pointer;
  transition: transform 0.28s var(--lg-spring),
              background 0.2s var(--lg-ease),
              box-shadow 0.2s var(--lg-ease);
}
/* 44px touch target without inflating the visual size. */
.lg-close::after {
  content: '';
  position: absolute;
  inset: 50% auto auto 50%;
  translate: -50% -50%;
  width: 44px; height: 44px;
}
.lg-close svg {
  width: 14px; height: 14px;
  transition: rotate 0.35s var(--lg-spring);
}
.lg-close:hover {
  background: oklch(100% 0 0 / 0.5);
  transform: scale(1.08);
  box-shadow:
    inset 0 1px 0 oklch(100% 0 0 / 0.9),
    0 6px 16px -4px oklch(28% 0.05 262 / 0.35);
}
.lg-close:hover svg { rotate: 90deg; }
.lg-close:active { transform: scale(0.94); }
.lg-close:focus-visible {
  outline: 2px solid var(--lg-accent);
  outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .lg-close, .lg-close svg { transition: none; }
  .lg-close:hover { transform: none; }
  .lg-close:hover svg { rotate: none; }
}

/* ── PANELS FIT THE VIEWPORT. FULL STOP. ────────────────────────────────────
   The old dialogs were sized by their content and then capped with overflow-y, so on a
   phone you had to scroll to reach the button you came for. Inverted here: the panel is
   a viewport-sized frame with a fixed header, a flexible middle, and a PINNED action row
   that is always on screen. */

.lg-sheet {
  position: fixed;
  inset: 0;
  margin: auto;

  width: min(460px, calc(100vw - 24px));
  max-height: calc(100dvh - max(24px, env(safe-area-inset-top))
                          - max(24px, env(safe-area-inset-bottom)));

  display: grid;
  grid-template-rows: auto 1fr auto;   /* head | body | pinned actions */
  gap: 0;

  padding: 0;
  border: none;
  overflow: visible;                    /* the sheet itself NEVER scrolls */
  color: var(--lg-ink);
}
.lg-sheet::backdrop {
  /* Was a heavy dark scrim, which killed the bright aurora and made the whole thing feel
     murky. Glass should sit IN the light, not on top of a dimmed photo. Lighter, warmer,
     and it leans on blur for separation rather than darkness. */
  background: oklch(72% 0.03 250 / 0.30);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
}

.lg-head {
  padding: 22px 56px 12px 24px;   /* right padding clears the close chip */
}
.lg-title {
  font-size: 19px;
  font-weight: 640;
  letter-spacing: -0.02em;
  line-height: 1.25;
  text-wrap: balance;
}
.lg-sub {
  margin-top: 5px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--lg-ink-soft);
  text-wrap: pretty;
}

.lg-body {
  min-height: 0;                  /* the magic that lets 1fr actually shrink */
  padding: 4px 20px 8px;
  overflow: hidden;               /* content COLLAPSES; it does not scroll */
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Pinned. The action is never below the fold. */
.lg-actions {
  padding: 12px 20px max(16px, env(safe-area-inset-bottom));
  display: flex;
  gap: 9px;
  border-top: 1px solid oklch(100% 0 0 / 0.16);
}

.lg-btn {
  flex: 1 1 0;
  min-height: 46px;
  border-radius: 14px;
  font: inherit;
  font-size: 14.5px;
  font-weight: 640;
  cursor: pointer;
  border: 1px solid oklch(100% 0 0 / 0.45);
  background: oklch(100% 0 0 / 0.34);
  color: var(--lg-ink);
  box-shadow: inset 0 1px 0 oklch(100% 0 0 / 0.7);
  transition: transform 0.18s var(--lg-ease), background 0.18s var(--lg-ease);
}
.lg-btn:hover  { background: oklch(100% 0 0 / 0.5); transform: translateY(-1px); }
.lg-btn:active { transform: translateY(0) scale(0.99); }
.lg-btn:focus-visible { outline: 2px solid var(--lg-accent); outline-offset: 2px; }

.lg-btn-primary {
  background: linear-gradient(180deg, oklch(70% 0.16 235), oklch(58% 0.17 240));
  border-color: oklch(78% 0.14 235 / 0.85);
  color: oklch(99% 0 0);
  box-shadow:
    inset 0 1px 0 oklch(100% 0 0 / 0.45),
    0 8px 22px -8px oklch(58% 0.17 240 / 0.5);
}
.lg-btn-primary:hover { filter: brightness(1.07); }

.lg-btn-danger {
  color: oklch(52% 0.2 25);
  border-color: oklch(62% 0.2 25 / 0.4);
  background: oklch(62% 0.2 25 / 0.1);
}
.lg-btn-danger:hover { background: oklch(62% 0.2 25 / 0.2); }

/* ── Segmented tabs ─────────────────────────────────────────────────────────
   Two groups, one visible at a time. This is what keeps the panel small enough to never
   scroll — the tabs are a LAYOUT device, not decoration. */

.lg-tabs {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 3px;
  padding: 3px;
  margin: 0 0 4px;
  border-radius: 13px;
  background: oklch(50% 0.02 260 / 0.13);
  border: 1px solid oklch(100% 0 0 / 0.28);
}

.lg-tab {
  position: relative;
  min-height: 38px;
  border: none;
  border-radius: 10px;
  background: transparent;
  color: var(--lg-ink-soft);
  font: inherit;
  font-size: 13px;
  font-weight: 640;
  cursor: pointer;
  transition: color 0.2s var(--lg-ease);
}
.lg-tab[aria-selected="true"] {
  color: var(--lg-ink);
  background: oklch(100% 0 0 / 0.62);
  box-shadow:
    inset 0 1px 0 oklch(100% 0 0 / 0.9),
    0 2px 6px -2px oklch(28% 0.05 262 / 0.25);
}
.lg-tab:focus-visible { outline: 2px solid var(--lg-accent); outline-offset: 1px; }

/* ── The 9-up grid ──────────────────────────────────────────────────────────
   auto-fit + minmax: three across on a phone, more when there is room, and it reflows on
   rotate. Nine tiles always fit — no scrolling, ever. */

.lg-grid {
  display: grid;
  /* EXACTLY 3 columns. Nine items want a 3x3 square — it is symmetric, it reads as a
     complete set, and it leaves no ragged empty cells. auto-fit gave 4 columns on a wide
     screen and left three holes in the last row, which looked like a mistake (and, on
     software rasterisers, actively attracted compositing artifacts into the empty space).
     A fixed 3-up also means the layout is identical on every device — one less thing to
     go wrong in an orientation change. */
  grid-template-columns: repeat(3, 1fr);
  gap: 7px;
  min-height: 0;
}

.lg-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;

  aspect-ratio: 1 / 0.82;
  min-height: 62px;
  padding: 6px 4px;

  border-radius: 14px;
  border: 1px solid oklch(100% 0 0 / 0.4);
  background: oklch(100% 0 0 / 0.3);
  box-shadow: inset 0 1px 0 oklch(100% 0 0 / 0.6);

  color: var(--lg-ink);
  font: inherit;
  cursor: pointer;
  transition: transform 0.2s var(--lg-spring), background 0.18s var(--lg-ease),
              border-color 0.18s var(--lg-ease);
}
.lg-tile:hover { transform: translateY(-2px); background: oklch(100% 0 0 / 0.45); }
.lg-tile:active { transform: scale(0.96); }
.lg-tile:focus-visible { outline: 2px solid var(--lg-accent); outline-offset: 2px; }

.lg-tile[aria-pressed="true"] {
  background: linear-gradient(180deg, oklch(72% 0.15 235 / 0.32), oklch(62% 0.17 240 / 0.22));
  border-color: var(--lg-accent);
  box-shadow:
    inset 0 1px 0 oklch(100% 0 0 / 0.8),
    0 4px 14px -4px oklch(62% 0.17 240 / 0.45);
}
/* Selected state carries a MARK, not just a colour (WCAG 1.4.1). */
.lg-tile[aria-pressed="true"]::after {
  content: '';
  position: absolute;
  top: 5px; right: 5px;
  width: 13px; height: 13px;
  border-radius: 50%;
  background: var(--lg-accent);
  box-shadow: 0 0 0 2px oklch(100% 0 0 / 0.85);
}

.lg-tile-ico  { font-size: 17px; line-height: 1; }
.lg-tile-name { font-size: 11px; font-weight: 620; letter-spacing: -0.01em; }

/* The little animated bars that show a tile is currently sounding. */
.lg-tile-eq {
  display: flex;
  align-items: flex-end;
  gap: 1.5px;
  height: 9px;
}
.lg-tile-eq i {
  width: 2px;
  border-radius: 1px;
  background: var(--lg-accent);
  height: 3px;
}
.lg-tile.is-playing .lg-tile-eq i { animation: lg-eq 0.55s ease-in-out infinite alternate; }
.lg-tile.is-playing .lg-tile-eq i:nth-child(2) { animation-delay: 0.12s; }
.lg-tile.is-playing .lg-tile-eq i:nth-child(3) { animation-delay: 0.24s; }
@keyframes lg-eq { to { height: 9px; } }
@media (prefers-reduced-motion: reduce) {
  .lg-tile.is-playing .lg-tile-eq i { animation: none; height: 6px; }
}

/* ── Landscape phone: the tightest case in the whole product ────────────────
   844×390. Everything shrinks, nothing scrolls. */
@media (max-height: 460px) and (orientation: landscape) {
  .lg-sheet { width: min(620px, calc(100vw - 20px)); }
  .lg-head  { padding: 14px 52px 8px 18px; }
  .lg-title { font-size: 16px; }
  .lg-sub   { display: none; }
  .lg-body  { padding: 2px 16px 6px; gap: 7px; }
  .lg-grid  { grid-template-columns: repeat(3, 1fr); gap: 5px; }
  .lg-tile  { min-height: 50px; aspect-ratio: 1 / 0.62; }
  .lg-tile-name { font-size: 10px; }
  .lg-actions { padding: 8px 16px 10px; }
  .lg-btn { min-height: 40px; font-size: 13.5px; }
  .lg-tabs { margin-bottom: 2px; }
  .lg-tab { min-height: 32px; }
}

/* Very small phones (320px). */
@media (max-width: 360px) {
  .lg-grid { grid-template-columns: repeat(3, 1fr); gap: 5px; }
  .lg-tile { min-height: 56px; }
  .lg-head { padding: 18px 50px 10px 16px; }
  .lg-body { padding: 4px 14px 6px; }
  .lg-actions { padding: 10px 14px max(12px, env(safe-area-inset-bottom)); }
}

/* ── Sound picker extras ──────────────────────────────────────────────────── */

.rt-mine { min-height: 0; }
.rt-mine-label {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--lg-ink-soft);
  margin: 6px 0 4px;
}
.rt-mine-row { display: flex; flex-wrap: wrap; gap: 5px; }

.rt-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 6px 11px;
  min-height: 34px;
  border-radius: 999px;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  color: var(--lg-ink);
  background: oklch(100% 0 0 / 0.34);
  border: 1px solid oklch(100% 0 0 / 0.45);
}
.rt-chip.is-on {
  background: oklch(70% 0.15 235 / 0.3);
  border-color: var(--lg-accent);
}
.rt-chip-x {
  display: grid;
  place-items: center;
  width: 18px; height: 18px;
  border-radius: 50%;
  font-size: 13px;
  line-height: 1;
  color: var(--lg-ink-soft);
  background: oklch(0% 0 0 / 0.08);
}
.rt-chip-x:hover { color: oklch(52% 0.2 25); background: oklch(62% 0.2 25 / 0.18); }

/* Review card — explicit playback, never automatic. */
.rt-review {
  padding: 10px;
  border-radius: 14px;
  background: oklch(70% 0.15 235 / 0.12);
  border: 1px solid oklch(70% 0.15 235 / 0.45);
}
.rt-review[hidden] { display: none; }

.rt-review-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }

.rt-review-play {
  flex: 0 0 auto;
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border-radius: 50%;
  cursor: pointer;
  color: oklch(99% 0 0);
  background: var(--lg-accent);
  border: 1px solid oklch(74% 0.15 235);
  box-shadow: 0 3px 10px -3px oklch(62% 0.17 240 / 0.5);
  transition: transform 0.18s var(--lg-spring);
}
.rt-review-play:hover  { transform: scale(1.08); }
.rt-review-play:active { transform: scale(0.94); }
.rt-review-play:focus-visible { outline: 2px solid var(--lg-accent); outline-offset: 2px; }

.rt-review-name {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 36px;
  padding: 0 10px;
  border-radius: 10px;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--lg-ink);
  background: oklch(100% 0 0 / 0.55);
  border: 1px solid oklch(100% 0 0 / 0.5);
}
.rt-review-name:focus { outline: none; border-color: var(--lg-accent); }

.rt-review-len {
  flex: 0 0 auto;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--lg-ink-soft);
}
.rt-review-actions { display: flex; gap: 7px; }
.rt-review-actions .lg-btn { min-height: 40px; font-size: 13.5px; }

.rt-rec-status {
  font-size: 11.5px;
  text-align: center;
  color: var(--lg-ink-soft);
  font-variant-numeric: tabular-nums;
  padding: 2px 0;
}
.rt-rec-status[hidden] { display: none; }

#rt-record.is-rec {
  background: linear-gradient(180deg, oklch(66% 0.22 25), oklch(56% 0.22 25));
  border-color: oklch(72% 0.2 25);
  color: oklch(99% 0 0);
}

/* The buttons in the pinned action row carry icons. */
.lg-actions .lg-btn { display: inline-flex; align-items: center; justify-content: center; gap: 7px; }

/* ── "Become a Node" — sits BESIDE Install App ─────────────────────────────────
   Same glass chip, same size, same corner. Deliberately the SECOND offer: installing is
   for everyone, running infrastructure is not, and the visual hierarchy should say so
   without a word — Install is the filled primary, this is the quiet neighbour. */

.node-btn {
  position: fixed;
  bottom: max(18px, env(safe-area-inset-bottom));
  right: calc(max(18px, env(safe-area-inset-right)) + 148px);  /* left of Install */
  z-index: 900;

  display: flex;
  align-items: center;
  gap: 7px;

  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 11px 15px;
  min-height: 44px;
  border-radius: 999px;
  cursor: pointer;

  color: var(--lg-ink);
  background: oklch(100% 0 0 / 0.34);
  border: 1px solid oklch(100% 0 0 / 0.55);
  backdrop-filter: blur(20px) saturate(1.8);
  -webkit-backdrop-filter: blur(20px) saturate(1.8);
  box-shadow:
    inset 0 1px 0 oklch(100% 0 0 / 0.7),
    0 8px 24px -10px var(--lg-shadow);

  transition: transform 0.2s var(--lg-ease), background 0.2s var(--lg-ease);
}
.node-btn:hover { transform: translateY(-2px); background: oklch(100% 0 0 / 0.5); }
.node-btn:focus-visible { outline: 3px solid var(--lg-accent); outline-offset: 3px; }

/* Only offered on the join screen — never over a live call. */
#dashboard:not([style*="display: none"]) ~ .node-btn,
.pwa-standalone .node-btn { display: none; }

/* When Install is absent (already installed, or iOS non-Safari), take its place. */
html:not(:has(#pwa-install-btn:not([hidden]))) .node-btn {
  right: max(18px, env(safe-area-inset-right));
}

@media (max-width: 560px) {
  .node-btn { font-size: 12px; padding: 10px 12px; right: calc(max(14px, env(safe-area-inset-right)) + 128px); }
  .node-btn span { display: none; }          /* icon-only when space is tight */
  .node-btn { padding: 10px; width: 44px; justify-content: center; }
}

/* ── The node dialog ──────────────────────────────────────────────────────── */

.node-what { display: flex; flex-direction: column; gap: 8px; }
.node-row {
  display: flex;
  gap: 9px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--lg-ink-soft);
}
.node-row strong { color: var(--lg-ink); font-weight: 640; }
.node-dot {
  flex: 0 0 auto;
  width: 7px; height: 7px;
  margin-top: 7px;
  border-radius: 50%;
  background: var(--lg-accent);
}

.node-need {
  padding: 10px 12px;
  border-radius: 12px;
  background: oklch(100% 0 0 / 0.3);
  border: 1px solid oklch(100% 0 0 / 0.45);
}
.node-need-t {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--lg-ink-soft);
  margin-bottom: 5px;
}
.node-need ul { margin: 0; padding-left: 16px; }
.node-need li {
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--lg-ink-soft);
}
.node-need strong { color: var(--lg-ink); }

/* The warning that saves someone a weekend. */
.node-warn {
  padding: 10px 12px;
  border-radius: 0 11px 11px 0;
  border-left: 3px solid oklch(72% 0.16 70);
  background: oklch(85% 0.09 80 / 0.3);
  font-size: 12px;
  line-height: 1.5;
  color: var(--lg-ink);
}

.node-cmd-label {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--lg-ink-soft);
  margin-top: 2px;
}
.node-cmd {
  margin: 0;
  padding: 10px 12px;
  border-radius: 11px;
  background: oklch(24% 0.02 262 / 0.9);
  color: oklch(92% 0.02 160);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px;
  line-height: 1.65;
  white-space: pre;
  overflow-x: auto;
}
.node-dialog .lg-actions a.lg-btn { display: inline-flex; align-items: center; justify-content: center; text-decoration: none; }

/* ── Stage (solution.md R5/R6) ─────────────────────────────────────────────────
   The LAYOUT is untouched — it was already a 1fr stage over an auto strip, with 4-8px of
   padding and no brand chrome. What was missing was the policy for who belongs on the
   stage. These rules only add the affordances that policy needs. */

/* Whoever is on the stage is marked in the strip, so you can see where they went. */
.video-slot.is-on-stage {
  outline: 2px solid oklch(75% 0.15 235);
  outline-offset: -2px;
}
/* A PIN is a different state from "happens to be on stage", and must look different —
   otherwise you cannot tell whether tapping again will do anything. */
.video-slot.is-pinned::after {
  content: '';
  position: absolute;
  top: 5px; left: 5px;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: oklch(75% 0.15 235);
  box-shadow: 0 0 0 2px oklch(20% 0.02 260 / 0.6);
  z-index: 3;
}

.video-slot.is-dragging,
.stage-pip.is-dragging {
  z-index: 999;
  cursor: grabbing;
  scale: 1.04;
  box-shadow: 0 20px 50px -12px oklch(10% 0 0 / 0.6);
}
.video-slot.is-floating {
  position: fixed;
  z-index: 980;
  width: clamp(120px, 18vw, 200px);
  aspect-ratio: 16 / 10;
  border-radius: 14px;
  overflow: hidden;
}

/* The strip lights up when you are about to drop something into it. */
#video-list-container.is-drop-target {
  outline: 2px dashed oklch(78% 0.14 235 / 0.8);
  outline-offset: -3px;
  border-radius: 12px;
}

/* Per-tile fit ↔ fill, toggled from the overlay. */
.video-slot.is-contain video,
.stage-pip.is-contain video { object-fit: contain; background: #000; }

/* The speaker, floating over a presentation. */
.stage-pip {
  position: absolute;
  right: 14px;
  bottom: 14px;
  z-index: 60;
  width: clamp(120px, 17vw, 210px);
  aspect-ratio: 16 / 10;
  border-radius: 14px;
  overflow: hidden;
  cursor: grab;
  touch-action: none;
}
.stage-pip video { width: 100%; height: 100%; object-fit: cover; display: block; }
.stage-pip-name {
  position: absolute;
  left: 6px; bottom: 5px;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  color: #fff;
  background: oklch(15% 0 0 / 0.6);
  backdrop-filter: blur(6px);
}

/* ── The 10-second tile overlay ──────────────────────────────────────────────
   Ten seconds, because controls that live permanently on a video tile are clutter, and
   controls that vanish in two are a trap. */

.tile-ov {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;

  border-radius: inherit;
  background: oklch(12% 0.01 260 / 0.55);
  backdrop-filter: blur(6px) saturate(1.2);
  -webkit-backdrop-filter: blur(6px) saturate(1.2);

  opacity: 0;
  transition: opacity 0.18s var(--lg-ease);
}
.tile-ov.is-in { opacity: 1; }

.tile-ov-name {
  max-width: 92%;
  padding: 0 6px;
  font-size: 12px;
  font-weight: 650;
  color: #fff;
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-shadow: 0 1px 3px oklch(0% 0 0 / 0.6);
}
.tile-ov-btns { display: flex; gap: 7px; }

.tile-ov-b {
  width: 36px; height: 36px;
  display: grid; place-items: center;
  border-radius: 10px;
  cursor: pointer;
  color: #fff;
  background: oklch(100% 0 0 / 0.16);
  border: 1px solid oklch(100% 0 0 / 0.32);
  backdrop-filter: blur(8px);
  transition: background 0.15s var(--lg-ease), transform 0.15s var(--lg-spring);
}
.tile-ov-b:hover  { background: oklch(100% 0 0 / 0.3); transform: scale(1.07); }
.tile-ov-b:active { transform: scale(0.93); }
.tile-ov-b[aria-pressed="true"] {
  background: oklch(66% 0.2 25 / 0.75);
  border-color: oklch(74% 0.2 25);
}
.tile-ov-b:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .tile-ov { transition: none; }
  .tile-ov-b:hover { transform: none; }
}
