/* ============================================================
 * 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);
}
/* #6 FIX — a floating box must keep its SOURCE shape, and be freely resizable.
 *
 * The old rule forced `aspect-ratio: 16/10` on every floating box, which is exactly the
 * "illogical aspect ratio" deformation — a portrait phone camera got stretched into a
 * letterbox the moment you dragged it out, and there was no way back. Now: a width, but
 * height: auto so the container follows the video's natural ratio, and `resize: both` so
 * the user can size it however they like once it's out of the strip (per the spec). */
.video-slot.is-floating {
  position: fixed;
  z-index: 980;
  width: clamp(140px, 22vw, 280px);
  height: auto;
  aspect-ratio: var(--tile-ar, 16 / 9);  /* floats at the SOURCE shape; the grip's inline w+h override it */
  block-size: auto;            /* override the strip's fixed tile height */
  min-width: 100px;
  min-height: 70px;
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 14px 34px -12px oklch(15% 0.04 265 / 0.75), 0 0 0 1px oklch(100% 0 0 / 0.14);
}
/* Show the WHOLE frame while floating (contain), undistorted, whatever box the user resizes to. */
.video-slot.is-floating video,
.video-slot.is-floating .participant-card {
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
}

/* The resize grip — bottom-right, glass, touch-first (its ::before extends the hit area to 44px).
   CSS `resize:both` was retired: the tile's drag handler captured the pointer before the native
   corner could act, and CSS resize does not exist on touch. Visible only while floating; pulses
   for 10 seconds after each float so the affordance is discovered, then settles quiet. */
.tile-resize-grip {
  position: absolute;
  right: 3px; bottom: 3px;
  width: 26px; height: 26px;
  display: none;
  place-items: center;
  z-index: 6;
  color: #fff;
  border-radius: 9px;
  background: oklch(25% 0.03 265 / 0.6);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border: 1px solid oklch(100% 0 0 / 0.28);
  cursor: nwse-resize;
  touch-action: none;
  opacity: 0.55;
  transition: opacity 0.2s;
}
.tile-resize-grip::before { content: ''; position: absolute; inset: -9px; }   /* 44px touch target */
.video-slot.is-floating .tile-resize-grip,
.stage-pip.is-floating .tile-resize-grip { display: grid; }
.tile-resize-grip:hover { opacity: 1; }
.video-slot.show-resize-hint .tile-resize-grip {
  opacity: 1;
  animation: grip-pulse 1.5s ease-in-out infinite;
}
@keyframes grip-pulse { 50% { transform: scale(1.22); box-shadow: 0 0 0 5px oklch(80% 0.1 265 / 0.25); } }
@media (prefers-reduced-motion: reduce) { .video-slot.show-resize-hint .tile-resize-grip { animation: none; } }

/* 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; }
}

/* ── Recording explainer / intro dialog ───────────────────────────────────── */

.rec-explainer {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 12px 14px;
  border-radius: 14px;
  cursor: pointer;
  text-align: left;
  color: var(--lg-ink);
  background: linear-gradient(150deg, oklch(70% 0.15 25 / 0.16), oklch(62% 0.17 25 / 0.08));
  border: 1px solid oklch(66% 0.18 25 / 0.4);
  transition: transform 0.16s var(--lg-ease), background 0.16s var(--lg-ease);
}
.rec-explainer:hover { transform: translateY(-1px); background: oklch(66% 0.17 25 / 0.2); }
.rec-explainer:focus-visible { outline: 2px solid var(--lg-accent); outline-offset: 2px; }

.rec-explainer-ico {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 42px; height: 42px;
  border-radius: 11px;
  color: oklch(60% 0.2 25);
  background: oklch(100% 0 0 / 0.5);
}
.rec-explainer-txt { display: flex; flex-direction: column; gap: 1px; }
.rec-explainer-txt strong { font-size: 13.5px; font-weight: 640; }
.rec-explainer-sub { font-size: 11px; color: var(--lg-ink-soft); }

.rec-explainer-host { margin: 2px 0 4px; }
.rec-explainer-host video {
  width: 100%;
  border-radius: 12px;
  background: #000;
  max-height: 34dvh;
}
.rec-explainer-missing {
  font-size: 12px;
  color: var(--lg-ink-soft);
  padding: 10px 12px;
  border-radius: 10px;
  background: oklch(100% 0 0 / 0.3);
}

.rec-how { list-style: none; margin: 2px 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.rec-how li { display: flex; gap: 10px; font-size: 13px; line-height: 1.5; color: var(--lg-ink-soft); }
.rec-how strong { color: var(--lg-ink); font-weight: 620; }
.rec-how-n {
  flex: 0 0 auto;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: 50%;
  font-size: 11.5px; font-weight: 700;
  color: oklch(99% 0 0);
  background: var(--lg-accent);
}

.rec-honest {
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--lg-ink-soft);
  background: oklch(85% 0.06 85 / 0.28);
  border-left: 3px solid oklch(72% 0.15 70);
  border-radius: 0 8px 8px 0;
  padding: 9px 11px;
  margin: 2px 0 0;
}

.rec-start-dot {
  display: inline-block;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: currentColor;
  margin-right: 2px;
}

/* ── The small live indicator (top-left, minimal) ─────────────────────────── */

#rec-indicator {
  position: fixed;
  top: max(10px, env(safe-area-inset-top));
  left: max(10px, env(safe-area-inset-left));
  z-index: 985;

  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 11px 6px 9px;
  min-height: 34px;
  border-radius: 999px;
  cursor: pointer;

  color: #fff;
  background: oklch(30% 0.03 25 / 0.8);
  border: 1px solid oklch(66% 0.2 25 / 0.6);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  box-shadow: 0 4px 14px -4px oklch(40% 0.1 25 / 0.5);

  font-size: 12px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}
#rec-indicator:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

.rec-ind-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: oklch(66% 0.24 25);
}
@media (prefers-reduced-motion: no-preference) {
  .rec-ind-dot { animation: rec-ind-pulse 1.4s ease-in-out infinite; }
}
@keyframes rec-ind-pulse { 50% { opacity: 0.35; } }

@media (pointer: coarse) {
  #rec-indicator::after {
    content: ''; position: absolute; inset: -6px; /* pad the hit area to >=44px */
  }
}

/* ── #9 Share toolbox ───────────────────────────────────────────────────────
   Reuses .rec-consent-dialog / .rec-consent-body shells; adds the message field, the link row,
   the native Share button, and the fallback grid. Theme-aware; fits without scrolling. */
.share-sheet .share-body { display: flex; flex-direction: column; gap: 12px; max-width: 380px; }
.share-msg-label { font-size: 13px; font-weight: 600; color: var(--lg-ink, #e8eaf0); display: flex; flex-direction: column; gap: 6px; }
.share-msg-label span { font-weight: 400; opacity: 0.6; }
.share-msg {
  width: 100%; box-sizing: border-box; resize: none; border-radius: 12px;
  border: 1px solid oklch(100% 0 0 / 0.16); background: oklch(100% 0 0 / 0.06);
  color: inherit; padding: 9px 11px; font: inherit; font-size: 14px; min-height: 44px;
}
.share-msg:focus-visible { outline: 2px solid var(--lg-accent, #6aa8ff); outline-offset: 1px; }
.share-link-row { display: flex; gap: 8px; }
.share-url {
  flex: 1 1 auto; min-width: 0; border-radius: 12px; padding: 0 12px; height: 44px;
  border: 1px solid oklch(100% 0 0 / 0.16); background: oklch(100% 0 0 / 0.06);
  color: inherit; font-size: 13px; text-overflow: ellipsis;
}
.share-copy {
  flex: 0 0 auto; height: 44px; padding: 0 16px; border-radius: 12px; cursor: pointer;
  border: 1px solid oklch(100% 0 0 / 0.2); background: oklch(100% 0 0 / 0.1); color: inherit;
  font-weight: 650; font-size: 13px;
}
.share-copy:hover { background: oklch(100% 0 0 / 0.16); }
.share-native { width: 100%; }
.share-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.share-opt {
  display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 12px 4px;
  min-height: 44px; border-radius: 14px; cursor: pointer; color: inherit;
  border: 1px solid oklch(100% 0 0 / 0.14); background: oklch(100% 0 0 / 0.06);
  font-size: 11px; font-weight: 600; transition: background 0.15s, transform 0.1s;
}
.share-opt svg { opacity: 0.92; }
.share-opt:hover { background: oklch(100% 0 0 / 0.13); }
.share-opt:active { transform: scale(0.95); }
.share-opt:focus-visible { outline: 2px solid var(--lg-accent, #6aa8ff); outline-offset: 2px; }
.share-note { font-size: 11.5px; line-height: 1.4; opacity: 0.62; margin: 0; text-align: center; }

.share-toast {
  position: fixed; left: 50%; bottom: calc(env(safe-area-inset-bottom, 0px) + 24px);
  transform: translate(-50%, 12px); z-index: 1200; padding: 10px 18px; border-radius: 999px;
  background: oklch(22% 0.03 265 / 0.9); color: #fff; font-size: 13px; font-weight: 600;
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  box-shadow: 0 10px 30px -10px oklch(20% 0.05 265 / 0.8);
  opacity: 0; pointer-events: none; transition: opacity 0.22s, transform 0.22s;
}
.share-toast.is-in { opacity: 1; transform: translate(-50%, 0); }

@media (max-width: 380px) { .share-grid { grid-template-columns: repeat(2, 1fr); } }
@media (prefers-reduced-motion: reduce) { .share-toast { transition: none; } }

/* ── R-P3: LIQUID-GLASS VIDEO TILES ──────────────────────────────────────────
   The iOS-glass finish on the attendee boxes themselves. A video is opaque, so the glass
   reads through EDGE OPTICS: a lit specular top rim, a hairline refractive border, real
   elevation, and a moving sheen — all compositor-only (no per-frame script). */
.video-slot {
  border: 1px solid oklch(100% 0 0 / 0.22);
  box-shadow:
    inset 0 1.5px 0 oklch(100% 0 0 / 0.42),        /* lit top rim — the "thick glass" edge   */
    inset 0 -1px 0 oklch(0% 0 0 / 0.35),           /* dark base edge — physical depth        */
    0 10px 26px -12px oklch(10% 0.03 262 / 0.65),  /* elevation                              */
    0 1px 3px oklch(10% 0.03 262 / 0.35);
  isolation: isolate;
}
/* The sheen: a soft diagonal light sweep sitting ON the glass, above the video. */
.video-slot::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 3;
  background:
    linear-gradient(155deg, oklch(100% 0 0 / 0.22) 0%, oklch(100% 0 0 / 0.05) 22%, transparent 46%),
    radial-gradient(120% 60% at 50% -20%, oklch(100% 0 0 / 0.14), transparent 60%);
}
.video-slot.is-on-stage {
  border-color: oklch(78% 0.13 235 / 0.85);
  box-shadow:
    inset 0 1.5px 0 oklch(100% 0 0 / 0.5),
    0 0 0 2px oklch(72% 0.15 235 / 0.45),
    0 12px 30px -12px oklch(60% 0.15 235 / 0.5);
}
.video-slot.is-floating {
  border: 1px solid oklch(100% 0 0 / 0.3);
  box-shadow:
    inset 0 2px 0 oklch(100% 0 0 / 0.5),
    inset 0 -1px 0 oklch(0% 0 0 / 0.4),
    0 22px 48px -16px oklch(5% 0.02 262 / 0.85),
    0 2px 8px oklch(10% 0.02 262 / 0.4);
}

/* The 10-second overlay becomes a true glass sheet. */
.tile-ov {
  background: linear-gradient(180deg, oklch(30% 0.02 262 / 0.5), oklch(18% 0.02 262 / 0.62)) !important;
  -webkit-backdrop-filter: blur(14px) saturate(1.5);
  backdrop-filter: blur(14px) saturate(1.5);
  border-radius: inherit;
  box-shadow: inset 0 1px 0 oklch(100% 0 0 / 0.28);
}
.tile-ov-name {
  font-weight: 700;
  letter-spacing: 0.01em;
  text-shadow: 0 1px 3px oklch(0% 0 0 / 0.6);
}
.tile-ov-b {
  background: oklch(100% 0 0 / 0.14) !important;
  border: 1px solid oklch(100% 0 0 / 0.3) !important;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border-radius: 11px !important;
  box-shadow: inset 0 1px 0 oklch(100% 0 0 / 0.35), 0 3px 8px -3px oklch(0% 0 0 / 0.5);
  transition: transform 0.12s cubic-bezier(0.16,1,0.3,1), background 0.15s;
}
.tile-ov-b:hover  { background: oklch(100% 0 0 / 0.24) !important; }
.tile-ov-b:active { transform: scale(0.92); }
@media (prefers-reduced-motion: reduce) { .tile-ov-b { transition: none; } }

/* Tiles are controls, not documents: no text selection artefacts on double-click. */
.video-slot, .video-slot *, .tile-ov, .tile-ov * { user-select: none; -webkit-user-select: none; }
/* Narrow (portrait) tiles: the button row wraps instead of overflowing the glass. */
.tile-ov-btns { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; max-width: 100%; }

/* ── ACROSS-THE-BOARD GLASS (brand round) ────────────────────────────────────
   The last opaque panels join the material system. */

/* The call-control cluster was rgba(10,12,16,.85) — a slab, not glass. */
#hex-menu:not(.collapsed) .hex-cluster {
  background: linear-gradient(165deg, oklch(30% 0.02 262 / 0.5), oklch(16% 0.02 262 / 0.62)) !important;
  -webkit-backdrop-filter: blur(22px) saturate(1.6);
  backdrop-filter: blur(22px) saturate(1.6);
  border: 1px solid oklch(100% 0 0 / 0.22) !important;
  box-shadow:
    inset 0 1.5px 0 oklch(100% 0 0 / 0.35),
    inset 0 -1px 0 oklch(0% 0 0 / 0.35),
    0 14px 36px -14px oklch(0% 0 0 / 0.7) !important;
}

/* The background editor modal was 98% opaque. */
.bg-editor-modal {
  background: linear-gradient(170deg, oklch(26% 0.02 262 / 0.72), oklch(15% 0.02 262 / 0.82)) !important;
  -webkit-backdrop-filter: blur(24px) saturate(1.5);
  backdrop-filter: blur(24px) saturate(1.5);
  border: 1px solid oklch(100% 0 0 / 0.2) !important;
  box-shadow: inset 0 1px 0 oklch(100% 0 0 / 0.28), 0 28px 70px -22px oklch(0% 0 0 / 0.85) !important;
}

/* The landing CTA joins the brand ramp (was its own blue). */
#join-room-button {
  background: linear-gradient(160deg, var(--brand-bright, #6aa8ff), var(--brand, #4a7ae8)) !important;
  box-shadow: inset 0 1px 0 oklch(100% 0 0 / 0.45), 0 10px 26px -10px var(--brand-glow, rgba(90,140,255,0.5)) !important;
  font-family: var(--font-display);
  letter-spacing: 0.01em;
}
