/* Cloud IFB (test): Softglass v4 for /listen/ (index.html).
   Fog ground with a soft wash of one hue (blue), half-transparent glass cards (.card) and solid ones
   (.card.solid), one aura card per screen that follows the sound (--lvl, set by app.js), light display
   numbers, pills that lift out of the surface and sink in when pressed.
   Main buttons: ink (default) or blue (html[data-btn="blue"]). Themes: auto, or html[data-theme].
   No inline styles anywhere: the strict CSP for /listen/* blocks them. */

@font-face{font-family:'DM Sans';src:url(/listen/fonts/dm-sans-wght.woff2) format('woff2');font-weight:100 1000;font-style:normal;font-display:swap}

:root{
  --font:'DM Sans',system-ui,-apple-system,'Segoe UI',Roboto,'PingFang SC','Microsoft YaHei',sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --ease-out:cubic-bezier(.22,.61,.36,1); --ease-soft:cubic-bezier(.16,1,.3,1); --ease-io:cubic-bezier(.62,.03,.28,.99);
  --hue:#2f6ae0; --hue-deep:#1f4fb8; --hue-2:#6f9bff; --hue-3:#c4d7ff;
  --fog:#e9ecf1; --fog-2:#f5f6f8;
  --card:rgba(255,255,255,.36); --card-strong:rgba(255,255,255,.72); --card-solid:#fff; --edge:rgba(255,255,255,.75);
  --tile:rgba(232,236,242,.62); --tile-2:rgba(214,220,230,.75);
  --ink:#121418; --ink-2:#2b2f37; --muted:#545b68; --faint:#8d94a1; --line:rgba(18,20,24,.08); --hi:rgba(255,255,255,.95);
  --hue-ink:#1f4fb8; --hue-soft:rgba(47,106,224,.11); --danger:#b42330;
  --sh-card:0 1px 1px rgba(16,22,34,.04),0 20px 44px -20px rgba(16,22,34,.2);
  --sh-lift:-3px -3px 8px rgba(255,255,255,.95),4px 6px 14px rgba(64,78,104,.16);
  --sh-lift-sm:-2px -2px 5px rgba(255,255,255,.95),2px 3px 8px rgba(64,78,104,.18);
  --sh-sink:inset 2px 2px 5px rgba(64,78,104,.14),inset -2px -2px 5px rgba(255,255,255,.95);
  --r-card:30px; --r-tile:22px;
  --btn-bg:var(--ink); --btn-fg:#f5f6f8; --knob-bg:#fff; --knob-fg:var(--ink); --btn-sh:0 10px 22px -12px rgba(18,20,24,.7);
  --aura-a:#2f6ae0; --aura-b:#1f4fb8; --aura-hl:rgba(196,215,255,.8); --aura-glow:rgba(47,106,224,.7);
  --bloom-1:rgba(255,255,255,.6); --bloom-2:rgba(196,215,255,.55); --bloom-3:rgba(111,155,255,.65);
  --sun-a:#c4d7ff; --sun-b:#6f9bff; --sun-c:#2f6ae0;
  --grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  /* Light and dark specks on a clear ground: on the aura it looks like the old overlay grain, with a normal blend
     (mix-blend-mode made the GPU blend the whole card again on every frame). */
  --grain-ld:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='w' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch' seed='4'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 2.2 0 0 0 -1.1'/%3E%3C/filter%3E%3Cfilter id='b' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch' seed='4'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -2.2 0 0 0 1.1'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23w)'/%3E%3Crect width='160' height='160' filter='url(%23b)'/%3E%3C/svg%3E");
  --grain-gray:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .5 0 0 0 0 .5 0 0 0 0 .5 .6 .6 .6 0 -.9'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E"); --grain-bg:.35;
  color-scheme:light;
}
:root[data-btn="blue"]{--btn-bg:linear-gradient(180deg,#3f7aec,#2a60d4);--btn-fg:#fff;--knob-bg:#fff;--knob-fg:#2152bd;--btn-sh:0 12px 26px -12px rgba(47,106,224,.85)}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){
  --fog:#0b0d11; --fog-2:#12151b; --hue-3:#1f3a7a;
  --card:rgba(30,34,42,.38); --card-strong:rgba(30,34,42,.74); --card-solid:#1c1f26; --edge:rgba(255,255,255,.08);
  --tile:rgba(255,255,255,.05); --tile-2:rgba(255,255,255,.1);
  --ink:#f1f3f6; --ink-2:#d6dae1; --muted:#a3abb8; --faint:#6e7684; --line:rgba(255,255,255,.08); --hi:rgba(255,255,255,.07);
  --hue-ink:#8fb3ff; --hue-soft:rgba(111,155,255,.15); --danger:#ff7d86;
  --sh-card:0 1px 1px rgba(0,0,0,.4),0 20px 44px -20px rgba(0,0,0,.75);
  --sh-lift:-2px -2px 6px rgba(255,255,255,.04),4px 6px 14px rgba(0,0,0,.55);
  --sh-lift-sm:-1px -1px 4px rgba(255,255,255,.04),2px 3px 8px rgba(0,0,0,.55);
  --sh-sink:inset 2px 2px 5px rgba(0,0,0,.5),inset -2px -2px 5px rgba(255,255,255,.04);
  --btn-fg:#121418; --knob-bg:#121418; --knob-fg:#f1f3f6; --btn-sh:0 10px 22px -12px rgba(0,0,0,.8);
  --aura-a:#122a66; --aura-b:#060d20; --aura-hl:rgba(70,110,220,.28); --aura-glow:rgba(8,24,70,.6);
  --bloom-1:rgba(110,150,240,.32); --bloom-2:rgba(60,100,210,.28); --bloom-3:rgba(40,85,200,.34);
  --sun-a:#3a5db8; --sun-b:#1f3f8f; --sun-c:#122a66; --grain-bg:.18;
  color-scheme:dark;
}}
:root[data-theme="dark"]{
  --fog:#0b0d11; --fog-2:#12151b; --hue-3:#1f3a7a;
  --card:rgba(30,34,42,.38); --card-strong:rgba(30,34,42,.74); --card-solid:#1c1f26; --edge:rgba(255,255,255,.08);
  --tile:rgba(255,255,255,.05); --tile-2:rgba(255,255,255,.1);
  --ink:#f1f3f6; --ink-2:#d6dae1; --muted:#a3abb8; --faint:#6e7684; --line:rgba(255,255,255,.08); --hi:rgba(255,255,255,.07);
  --hue-ink:#8fb3ff; --hue-soft:rgba(111,155,255,.15); --danger:#ff7d86;
  --sh-card:0 1px 1px rgba(0,0,0,.4),0 20px 44px -20px rgba(0,0,0,.75);
  --sh-lift:-2px -2px 6px rgba(255,255,255,.04),4px 6px 14px rgba(0,0,0,.55);
  --sh-lift-sm:-1px -1px 4px rgba(255,255,255,.04),2px 3px 8px rgba(0,0,0,.55);
  --sh-sink:inset 2px 2px 5px rgba(0,0,0,.5),inset -2px -2px 5px rgba(255,255,255,.04);
  --btn-fg:#121418; --knob-bg:#121418; --knob-fg:#f1f3f6; --btn-sh:0 10px 22px -12px rgba(0,0,0,.8);
  --aura-a:#122a66; --aura-b:#060d20; --aura-hl:rgba(70,110,220,.28); --aura-glow:rgba(8,24,70,.6);
  --bloom-1:rgba(110,150,240,.32); --bloom-2:rgba(60,100,210,.28); --bloom-3:rgba(40,85,200,.34);
  --sun-a:#3a5db8; --sun-b:#1f3f8f; --sun-c:#122a66; --grain-bg:.18;
  color-scheme:dark;
}
@media (prefers-color-scheme:dark){:root[data-btn="blue"]:not([data-theme="light"]){--btn-fg:#fff;--knob-bg:#fff;--knob-fg:#2152bd}}
:root[data-theme="dark"][data-btn="blue"]{--btn-fg:#fff;--knob-bg:#fff;--knob-fg:#2152bd}

/* ───────── base ───────── */
*{box-sizing:border-box}
html,body{margin:0}
/* Print the QR codes: on screen the sheet never shows; on paper only the sheet shows, black on white. */
#printSheet{display:none}
@media print{
  @page{margin:14mm}
  html,body{background:#fff!important;color:#000}
  body>*:not(#printSheet),body::before,body::after{display:none!important}
  #printSheet{display:block;font-family:var(--font);color:#000}
  #printSheet .ps-title{margin:0 0 10mm;font-size:30pt;font-weight:300;letter-spacing:-.02em}
  #printSheet .ps-title b{font-weight:600}
  #printSheet .ps-cols{display:flex;flex-wrap:wrap;gap:10mm 12mm;align-items:flex-start}
  #printSheet .ps-block{flex:1 1 70mm;min-width:0;break-inside:avoid}
  #printSheet h2{margin:0 0 4mm;font-size:18pt;font-weight:600}
  #printSheet canvas{display:block;width:100%;max-width:70mm;height:auto;aspect-ratio:1;image-rendering:pixelated;margin:0 0 5mm}
  #printSheet ol{margin:0;padding-left:6mm;font-size:13pt;line-height:1.45}
  #printSheet li{margin:0 0 2mm}
  #printSheet .ps-link{margin:4mm 0 0;font:9pt/1.3 ui-monospace,Menlo,Consolas,monospace;overflow-wrap:anywhere;color:#333}
  #printSheet .ps-foot{margin:14mm 0 0;font-size:10pt;color:#555}
  #printSheet [hidden]{display:none!important}
}
/* No zoom (Softglass v4 rule P3, Ethan 2026-11-12): no pinch, no double-tap zoom, and no zoom in on a field
   (every input and select has 16 px text or more). app.js also stops Safari's pinch gesture. */
html{touch-action:manipulation;touch-action:pan-x pan-y;-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{min-height:100vh;min-height:100dvh;font:16px/1.5 var(--font);color:var(--ink);background:var(--fog);-webkit-font-smoothing:antialiased;
  padding:max(14px,env(safe-area-inset-top)) max(16px,env(safe-area-inset-right)) max(28px,env(safe-area-inset-bottom)) max(16px,env(safe-area-inset-left))}
body::before{content:'';position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(62% 42% at 6% -4%,color-mix(in srgb,var(--hue-3) 85%,transparent),transparent 72%),
    radial-gradient(48% 34% at 104% 26%,color-mix(in srgb,var(--hue-2) 30%,transparent),transparent 72%),
    radial-gradient(70% 46% at 22% 104%,color-mix(in srgb,var(--hue-3) 55%,transparent),transparent 72%),
    linear-gradient(180deg,var(--fog-2),var(--fog))}
/* The same grain as the aura card, over the whole background (fixed, so it does not move when the page scrolls). */
body::after{content:'';position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:var(--grain-bg);background-image:var(--grain-gray)}
main{max-width:1180px;margin:0 auto}
h1,h2,p{margin:0}
button,input,select{font:inherit;color:inherit}
[hidden]{display:none!important}
a{color:var(--hue-ink)}
:focus-visible{outline:2.5px solid var(--hue);outline-offset:2px}
.grow{flex:1;min-width:0}
svg.i{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round;flex:none}
svg.i .fill{fill:currentColor;stroke:none}

/* ───────── type ───────── */
.display{font-weight:300;letter-spacing:-.04em;line-height:.95;font-variant-numeric:tabular-nums}
.unit{font-size:.32em;font-weight:500;letter-spacing:0;vertical-align:top;margin-left:6px;position:relative;top:.3em}
.h1{font-size:32px;font-weight:300;letter-spacing:-.03em;line-height:1.08}
.h1 b{font-weight:600}
.h1.big{font-size:40px}
.h2{font-size:18px;font-weight:500;letter-spacing:-.01em;line-height:1.2}
.h2.sp{margin-top:10px}
.label{display:block;font-size:13px;font-weight:500;color:var(--muted);line-height:1.3;margin:0 0 8px}
.small{font-size:13.5px;line-height:1.45;color:var(--muted)}
.small:empty{display:none}
.lede{margin-top:12px;font-size:16px;line-height:1.45;color:var(--muted);max-width:34ch}
.stats{margin:0;font:12.5px/1.5 var(--mono);color:var(--muted)}
.stats:empty{display:none}
.err{font-size:14px;line-height:1.45;color:var(--danger)}
.err:empty{display:none}
.err.banner{margin:0 0 16px;padding:12px 16px;border-radius:18px;background:color-mix(in srgb,var(--danger) 10%,var(--card-strong));border:1px solid color-mix(in srgb,var(--danger) 30%,transparent)}

/* ───────── top bar ───────── */
.top{display:flex;align-items:center;gap:10px;max-width:1180px;margin:0 auto 20px}
.brandtile{width:40px;height:40px;border-radius:50%;display:grid;place-items:center;color:var(--hue);background:var(--card-solid);box-shadow:var(--sh-lift-sm)}
.brandname{font-size:18px;font-weight:600;letter-spacing:-.01em}
.chip{display:inline-flex;align-items:center;gap:6px;height:30px;padding:0 12px;border-radius:999px;font-size:12.5px;font-weight:500;white-space:nowrap;
  background:var(--tile);color:var(--ink-2);border:0}
.chip.hue{background:var(--hue-soft);color:var(--hue-ink)}
.dot{width:8px;height:8px;border-radius:50%;background:currentColor;flex:none}
.iconbtn{width:44px;height:44px;border:0;border-radius:50%;display:grid;place-items:center;cursor:pointer;padding:0;flex:none;
  background:var(--card-solid);color:var(--ink);box-shadow:var(--sh-lift);-webkit-tap-highlight-color:transparent;transition:transform .16s var(--ease-out),box-shadow .2s var(--ease-out)}
.iconbtn:active{transform:scale(.95);box-shadow:var(--sh-sink)}
#themeBtn svg{display:none}
:root:not([data-theme]) #themeBtn .ic-auto,:root[data-theme="light"] #themeBtn .ic-light,:root[data-theme="dark"] #themeBtn .ic-dark{display:block}

/* ───────── layout ───────── */
.view.narrow{max-width:460px;margin:0 auto;display:flex;flex-direction:column;gap:14px}
.head{display:flex;align-items:flex-end;flex-wrap:wrap;gap:8px 24px;margin:0 4px 18px}
.head .small{max-width:52ch;padding-bottom:4px;font-size:14px}
.grid{display:flex;flex-direction:column;gap:16px}
.col{display:contents}
#keyCard{order:0} #console{order:1} #levelsCard{order:2} #videoCard{order:3} #linkCard{order:4} #peopleCard{order:5} #inputCard{order:6}
@media (min-width:900px){
  .grid{display:grid;grid-template-columns:minmax(0,7fr) minmax(0,5fr);gap:20px;align-items:start}
  .col{display:flex;flex-direction:column;gap:20px}
}
.stack{display:flex;flex-direction:column;gap:14px}
.row{display:flex;gap:10px;align-items:center}
.btnrow{display:flex;flex-wrap:wrap;gap:8px}
.btnrow>*{flex:1 1 auto}
.cardhead{display:flex;align-items:center;gap:10px}
.cardhead .h2{flex:1}
.cardhead .label{margin:0}
.pair{display:grid;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr);gap:12px}
.chans{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
@media (max-width:520px){.pair,.chans{grid-template-columns:minmax(0,1fr)}}
.chanhead{display:flex;align-items:center;gap:10px}
.chanhead .label{margin:0}

/* ───────── surfaces ───────── */
/* Cards blur the still background under them (Ethan, 2026-11-11: keep the Softglass blur on cards). The background
   never moves and nothing animates under a card, so this is the one blur that stays; the blooms, the grain and the
   chips have none (rule 7). */
.card{position:relative;padding:22px;border-radius:var(--r-card);background:var(--card);border:1px solid var(--edge);
  box-shadow:var(--sh-card),inset 0 1px 0 var(--hi);-webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4)}
.card.solid{background:var(--card-strong)}
.tile{position:relative;padding:16px;border-radius:var(--r-tile);background:var(--tile)}
.avatar{width:32px;height:32px;border-radius:50%;display:grid;place-items:center;font-size:13px;font-weight:600;color:var(--hue-ink);background:var(--hue-soft);flex:none}

/* aura: the one colored card; grain is an SVG noise data URI (img-src allows data:) */
.aura{position:relative;overflow:hidden;isolation:isolate;color:#fff;border-radius:var(--r-card);
  background:
    radial-gradient(circle 220px at 88% 0%,var(--aura-hl),transparent 72%),
    linear-gradient(155deg,var(--aura-a) 10%,var(--aura-b) 95%);
  box-shadow:0 1px 1px rgba(16,22,34,.06),0 26px 50px -24px var(--aura-glow)}
.aura::after{content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;opacity:.16;border-radius:inherit;
  background-image:var(--grain-ld)}
.aura .label,.aura .small,.aura .stats{color:rgba(255,255,255,.84)}
.aura .chip{background:rgba(255,255,255,.2);color:#fff}
.aura .err{color:#fff;background:rgba(150,20,30,.35);padding:8px 12px;border-radius:14px}
/* Blooms: soft blobs of light that drift slowly (20 to 30 s loops) and swell gently with the sound,
   like a music player's lyrics background. --lvl is already smoothed over about a second in app.js, and it is
   written at most 10 times a second; the transitions below fill in between on the compositor.
   The soft edge is in the gradient itself (no filter: blur, which the GPU had to redo on every frame). */
.bloom{position:absolute;z-index:-1;border-radius:50%;pointer-events:none;
  scale:calc(.85 + var(--lvl,0) * .25);opacity:calc(.4 + var(--lvl,0) * .4);
  transition:scale .9s var(--ease-out),opacity .9s var(--ease-out);animation:float1 23s var(--ease-io) infinite alternate}
/* Each gradient is about the old blurred blob, measured: the element is larger by the old blur, and the stops
   fall off like a Gaussian edge. */
.bloom.b1{width:580px;height:580px;right:-200px;top:-240px;
  background:radial-gradient(closest-side,var(--bloom-1),var(--bloom-2) 48%,color-mix(in srgb,var(--bloom-2) 50%,transparent) 69%,color-mix(in srgb,var(--bloom-2) 15%,transparent) 86%,transparent)}
.bloom.b2{width:440px;height:440px;left:-160px;bottom:-210px;animation-name:float2;animation-duration:29s;
  background:radial-gradient(closest-side,color-mix(in srgb,var(--bloom-2) 85%,transparent),color-mix(in srgb,var(--bloom-2) 60%,transparent) 35%,color-mix(in srgb,var(--bloom-2) 30%,transparent) 60%,color-mix(in srgb,var(--bloom-2) 10%,transparent) 80%,transparent)}
.bloom.b3{width:480px;height:480px;left:calc(30% - 70px);top:calc(20% - 70px);animation-name:float3;animation-duration:19s;
  background:radial-gradient(closest-side,color-mix(in srgb,var(--bloom-3) 85%,transparent),color-mix(in srgb,var(--bloom-3) 60%,transparent) 35%,color-mix(in srgb,var(--bloom-3) 30%,transparent) 60%,color-mix(in srgb,var(--bloom-3) 10%,transparent) 80%,transparent)}
/* Off screen (scrolled away, another tab), the drift and the rings stop; app.js sets .still. */
.aura.still .bloom,.aura.still .sun,.aura.still .ring{animation-play-state:paused}
@keyframes float1{0%{transform:translate(0,0) rotate(0)}50%{transform:translate(-70px,50px) rotate(25deg)}100%{transform:translate(30px,-10px) rotate(-15deg)}}
@keyframes float2{0%{transform:translate(0,0)}50%{transform:translate(90px,-40px)}100%{transform:translate(20px,30px)}}
@keyframes float3{0%{transform:translate(0,0) scale(1)}50%{transform:translate(-80px,30px) scale(1.15)}100%{transform:translate(60px,-30px) scale(.9)}}
.aura.orb{color:var(--ink);background:var(--card-strong);box-shadow:var(--sh-card)}
.aura.orb::after{opacity:.07}
.aura.orb .label,.aura.orb .small{color:var(--muted)}
.aura.orb .chip{background:var(--card);color:var(--ink-2)}
/* The sun: the soft edge is a mask (painted once), not a blur filter (redone on every frame of the drift). */
.sun{position:absolute;z-index:-1;width:420px;height:420px;right:-150px;top:-130px;pointer-events:none;
  background:radial-gradient(circle 254px at calc(50% - 30px) calc(50% - 30px),var(--sun-a),var(--sun-b) 45%,var(--sun-c) 75%);
  -webkit-mask-image:radial-gradient(closest-side,#000 50%,rgba(0,0,0,.55) 68%,rgba(0,0,0,.18) 84%,transparent);
  mask-image:radial-gradient(closest-side,#000 50%,rgba(0,0,0,.55) 68%,rgba(0,0,0,.18) 84%,transparent);
  animation:drift 9s var(--ease-io) infinite alternate}
@keyframes drift{from{transform:translate(0,0) scale(1)}to{transform:translate(-18px,14px) scale(1.08)}}
.hero{padding:26px;min-height:300px;display:flex;flex-direction:column;justify-content:flex-end}

/* ───────── keys ───────── */
.btn{display:inline-flex;align-items:center;justify-content:space-between;gap:14px;height:58px;padding:0 7px 0 24px;border:0;border-radius:999px;
  font-size:16px;font-weight:500;cursor:pointer;white-space:nowrap;background:var(--btn-bg);color:var(--btn-fg);box-shadow:var(--btn-sh);
  -webkit-tap-highlight-color:transparent;touch-action:manipulation;
  transition:transform .18s var(--ease-out),opacity .2s var(--ease-out),background-color .2s var(--ease-out),color .2s var(--ease-out)}
.btn .knob{width:44px;height:44px;border-radius:50%;display:grid;place-items:center;background:var(--knob-bg);color:var(--knob-fg);transition:transform .26s var(--ease-soft)}
@media (hover:hover){.btn:hover .knob{transform:translateX(3px)}}
.btn:active{transform:scale(.97)}
.btn:disabled{opacity:.6;cursor:default;transform:none}
.btn.wide{display:flex;width:100%}
.btn.onaura{--btn-bg:#121418;--btn-fg:#f5f6f8;--knob-bg:#fff;--knob-fg:#121418;box-shadow:0 12px 26px -12px rgba(0,0,0,.55)}
:root[data-btn="blue"] .btn.onaura{--btn-bg:#fff;--btn-fg:#121418;--knob-bg:var(--hue);--knob-fg:#fff}
.btn.is-stop{--btn-bg:rgba(255,255,255,.92);--btn-fg:#121418;height:48px;padding:0 22px;box-shadow:0 8px 20px -12px rgba(0,0,0,.5)}
.btn.is-stop .knob{display:none}
.btn.is-stop:not(.onaura){--btn-bg:var(--card-solid);--btn-fg:var(--ink);box-shadow:var(--sh-lift)}
.pill{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:46px;padding:0 18px;border:0;border-radius:999px;cursor:pointer;
  font-size:15px;font-weight:500;background:var(--card-solid);color:var(--ink);box-shadow:var(--sh-lift);
  -webkit-tap-highlight-color:transparent;touch-action:manipulation;transition:transform .16s var(--ease-out),box-shadow .2s var(--ease-out)}
.pill:active{transform:scale(.98);box-shadow:var(--sh-sink);background:var(--tile)}
.pill:disabled{opacity:.6;cursor:default}
.pill.wide{display:flex;width:100%}
.pill.glass{background:rgba(255,255,255,.92);color:#121418;box-shadow:0 8px 20px -12px rgba(0,0,0,.5)}

/* ───────── on-air card ───────── */
.air{min-height:300px;padding:24px;display:flex;flex-direction:column;gap:6px}
.air-top .chip+.chip{margin-left:-2px}
.air-top{display:flex;align-items:flex-start;gap:10px}
.airtime{font-size:clamp(56px,11vw,100px);margin:4px 0 16px}
.air-row{display:flex;align-items:center;flex-wrap:wrap;gap:10px}
.mutebtn{display:flex;align-items:center;gap:14px;min-height:56px;padding:8px 8px 8px 18px;border:0;border-radius:999px;cursor:pointer;text-align:left;color:#fff;
  background:rgba(255,255,255,.2);box-shadow:inset 0 1px 0 rgba(255,255,255,.25);
  -webkit-tap-highlight-color:transparent;transition:transform .16s var(--ease-out)}
.mutebtn:active{transform:scale(.98)}
.mute-txt{display:flex;flex-direction:column;line-height:1.2}
.mute-title{font-size:16px;font-weight:500}
.mute-sub{font-size:12.5px;color:rgba(255,255,255,.82)}
.switch{position:relative;width:62px;height:36px;border-radius:999px;background:rgba(255,255,255,.28);flex:none;transition:background .2s var(--ease-out)}
.switch::after{content:'';position:absolute;top:4px;left:4px;width:28px;height:28px;border-radius:50%;background:#fff;box-shadow:0 2px 6px rgba(0,0,0,.3);transition:transform .26s var(--ease-soft)}
.mutebtn[aria-pressed="true"] .switch{background:#121418}
.mutebtn[aria-pressed="true"] .switch::after{transform:translateX(26px)}
.target{position:relative;width:120px;height:120px;margin:-8px -4px 0 0;display:grid;place-items:center;flex:none}
.target .ring{position:absolute;inset:0;border-radius:50%;border:1.5px solid rgba(255,255,255,.4);opacity:0;transform:scale(.55)}
.target .ring.still{opacity:1;transform:none;inset:24px;border-color:rgba(255,255,255,.3)}
.lamp{width:28px;height:28px;border-radius:50%;background:rgba(255,255,255,.35);transform:scale(calc(1 + var(--lvl,0) * .25));transition:transform .6s var(--ease-out),background .3s,box-shadow .3s}
#send.is-live:not(.is-muted) .lamp{background:radial-gradient(circle at 35% 30%,#fff 0 22%,#ffe1dc 60%);box-shadow:0 0 0 6px rgba(255,255,255,.16),0 0 28px 6px var(--bloom-2)}
/* On air (sound going out, not muted): the on-air card turns red, like a tally light. Off air or muted: blue. */
#send.is-live:not(.is-muted) #console{--aura-a:#d93a3a;--aura-b:#a3202c;--aura-hl:rgba(255,196,190,.75);--aura-glow:rgba(217,58,58,.6);--bloom-1:rgba(255,240,236,.6);--bloom-2:rgba(255,190,182,.55);--bloom-3:rgba(255,120,110,.6)}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]) #send.is-live:not(.is-muted) #console{--aura-a:#6e1620;--aura-b:#26070b;--aura-hl:rgba(230,90,90,.3);--aura-glow:rgba(0,0,0,.6);--bloom-1:rgba(255,140,130,.3);--bloom-2:rgba(220,80,80,.26);--bloom-3:rgba(200,60,60,.32)}}
:root[data-theme="dark"] #send.is-live:not(.is-muted) #console{--aura-a:#6e1620;--aura-b:#26070b;--aura-hl:rgba(230,90,90,.3);--aura-glow:rgba(0,0,0,.6);--bloom-1:rgba(255,140,130,.3);--bloom-2:rgba(220,80,80,.26);--bloom-3:rgba(200,60,60,.32)}
#send.is-live:not(.is-muted) .target .ring:not(.still),#lStage[data-state="live"] .target .ring:not(.still){animation:ring 2.8s var(--ease-soft) infinite}
.target .ring.r2{animation-delay:.9s!important}.target .ring.r3{animation-delay:1.8s!important}
@keyframes ring{0%{transform:scale(.55);opacity:.9}100%{transform:scale(1.1);opacity:0}}
.onaura-err:empty{display:none}

/* ───────── levels ───────── */
.lvl{display:flex;flex-direction:column;gap:12px;padding:16px 18px}
.lvlhead{display:flex;align-items:baseline;gap:10px}
.mlabel{flex:1;min-width:0;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.db{font-size:38px}
.meter{position:relative;height:8px;border-radius:4px;background:var(--tile-2);box-shadow:var(--sh-sink);overflow:hidden}
.meter i{position:absolute;inset:0;border-radius:4px;transform-origin:left center;transform:scaleX(0);will-change:transform;
  background:linear-gradient(90deg,var(--hue-2),var(--hue));box-shadow:0 0 10px color-mix(in srgb,var(--hue) 45%,transparent)}
.meter.clip i{background:var(--danger)}
.ticks{position:relative;height:14px;margin:0 18px}
.ticks b{position:absolute;top:0;transform:translateX(-50%);font-size:10.5px;font-weight:500;line-height:14px;color:var(--muted);font-variant-numeric:tabular-nums}
.ticks b:nth-child(1){left:0;transform:none}.ticks b:nth-child(2){left:25%}.ticks b:nth-child(3){left:50%}
.ticks b:nth-child(4){left:75%}.ticks b:nth-child(5){left:87.5%}.ticks b:nth-child(6){left:100%;transform:translateX(-100%)}

/* ───────── segmented: sunk track, lifted white thumb that slides ───────── */
.seg{position:relative;isolation:isolate;display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);padding:4px;border-radius:999px;background:var(--tile);box-shadow:var(--sh-sink)}
.seg::before{content:'';position:absolute;z-index:0;top:4px;bottom:4px;left:4px;width:calc((100% - 8px) / var(--n,3));border-radius:999px;
  transform:translateX(calc(var(--i,0) * 100%));background:var(--card-solid);box-shadow:var(--sh-lift-sm);transition:transform .28s var(--ease-soft)}
.seg.unset::before{opacity:0}
.seg button{position:relative;z-index:1;min-width:0;min-height:42px;padding:6px 8px;border:0;border-radius:999px;background:none;cursor:pointer;
  font-size:14.5px;font-weight:500;line-height:1.15;color:var(--muted);overflow-wrap:anywhere;-webkit-tap-highlight-color:transparent;touch-action:manipulation;transition:color .2s var(--ease-out)}
.seg button[aria-checked="true"],.seg button[aria-pressed="true"]{color:var(--ink)}
.seg button:focus-visible{outline-offset:-3px}
.seg-sm button{min-height:38px;font-size:13.5px}
.seg button[aria-selected="true"]{color:var(--ink)}

/* ───────── phone: sub-tabs, so a page never becomes a long scroll of cards ───────── */
.seg.tabs{display:none}
@media (max-width:899.98px){
  .seg.tabs{display:grid;position:sticky;top:max(10px,env(safe-area-inset-top));z-index:15;margin:0 0 16px;
    background:color-mix(in srgb,var(--card-strong) 94%,transparent);
    box-shadow:var(--sh-sink),0 10px 24px -16px rgba(16,22,34,.35)}
  .seg.tabs button{font-size:14px}
  #send[data-tab="air"] .grid [data-tab]:not([data-tab="air"]),
  #send[data-tab="video"] .grid [data-tab]:not([data-tab="video"]),
  #send[data-tab="people"] .grid [data-tab]:not([data-tab="people"]),
  #send[data-tab="input"] .grid [data-tab]:not([data-tab="input"]){display:none}
}

/* ───────── action bar: the main controls stick to the bottom and never move ───────── */
#send,#listen{padding-bottom:96px}
.actionbar{position:fixed;left:0;right:0;bottom:0;z-index:20;pointer-events:none;
  padding:0 max(12px,env(safe-area-inset-right)) max(12px,env(safe-area-inset-bottom)) max(12px,env(safe-area-inset-left))}
.actionbar>*{pointer-events:auto;max-width:560px;margin-left:auto;margin-right:auto}
.actionbar>.err{margin-bottom:8px;padding:10px 16px;border-radius:18px;background:color-mix(in srgb,var(--danger) 10%,var(--card-strong));
  border:1px solid color-mix(in srgb,var(--danger) 30%,transparent);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}
.actionrow{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:8px;padding:7px;border-radius:999px;
  background:var(--card-strong);border:1px solid var(--edge);box-shadow:var(--sh-card),inset 0 1px 0 var(--hi);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px)}
.actionrow.one{grid-template-columns:minmax(0,1fr)}
.actionrow .slot{display:grid;min-width:0}
.actionrow .slot>*{grid-area:1/1;width:100%;min-width:0}
.actionrow .btn{width:184px;height:58px}
.actionrow.one .btn{width:100%}
.btn .ic-stop,.btn.is-stop .ic-go{display:none}
.btn.is-stop .ic-stop{display:block}
.actionrow .btn.is-stop{height:58px;padding:0 7px 0 24px;--btn-bg:var(--card-solid);--btn-fg:var(--ink);--knob-bg:var(--ink);--knob-fg:var(--card-solid);
  border:1px solid var(--line);box-shadow:var(--sh-lift)}
.actionrow .btn.is-stop .knob{display:grid}
.slotnote{display:none;align-items:center;gap:8px;padding:0 18px;font-size:15px;font-weight:500;color:var(--muted)}
.slotnote .dot{background:var(--faint)}
#allowMic[hidden]~#onAir[hidden]~.slotnote{display:flex}
.actionrow .pill{min-height:58px;padding:6px 16px;white-space:normal;line-height:1.2;text-align:center;font-size:14.5px}
.actionrow .mutebtn{min-height:58px;padding:7px 7px 7px 20px;justify-content:space-between;color:var(--ink);background:var(--tile);box-shadow:var(--sh-sink);
  -webkit-backdrop-filter:none;backdrop-filter:none}
.actionrow .mute-sub{color:var(--muted)}
.actionrow .switch{background:var(--tile-2);box-shadow:var(--sh-sink)}
.actionrow .mutebtn[aria-pressed="true"] .switch{background:var(--hue)}
@media (max-width:520px){.actionrow .mute-sub{display:none}}

/* ───────── fields ───────── */
.field{display:flex;align-items:center;gap:10px;min-height:52px;padding:0 6px 0 16px;border-radius:999px;background:var(--tile);box-shadow:var(--sh-sink)}
.field:has(.ic){padding-left:7px}
.field .ic{width:38px;height:38px;border-radius:50%;display:grid;place-items:center;flex:none;background:var(--card-solid);color:var(--muted);box-shadow:var(--sh-lift-sm)}
.field input{flex:1;min-width:0;height:48px;border:0;background:none;outline:none;font-size:16px;color:var(--ink)}
.field input::placeholder{color:var(--faint)}
.field:focus-within{box-shadow:var(--sh-sink),0 0 0 3px var(--hue-soft)}
.field.bad{box-shadow:var(--sh-sink),0 0 0 2px var(--danger)}

/* ───────── sign-in card (cloud) ─────────
   Both ways share one grid cell: the card takes the taller one's height, so switching the way moves
   nothing (rule C1). The error line keeps two lines of room, and Sign in keeps its width while busy. */
.ways{display:grid}
.way{grid-area:1/1}
.way.off{visibility:hidden}
.err.keep{min-height:2.9em}
.err.keep:empty{display:block}
.signbtn{min-width:128px}
.selwrap{position:relative}
.selwrap select{-webkit-appearance:none;appearance:none;width:100%;min-height:52px;padding:0 44px 0 18px;border:0;border-radius:999px;cursor:pointer;
  font-size:16px;font-weight:500;text-overflow:ellipsis;background:var(--card-solid);color:var(--ink);box-shadow:var(--sh-lift)}
.selwrap select option{background:var(--card-solid);color:var(--ink)}
.selwrap::after{content:'';position:absolute;right:20px;top:50%;width:8px;height:8px;margin-top:-6px;pointer-events:none;border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);transform:rotate(45deg)}

input.range{-webkit-appearance:none;appearance:none;display:block;width:100%;height:36px;margin:0;background:transparent;cursor:pointer;--p:100%}
input.range::-webkit-slider-runnable-track{height:10px;border-radius:5px;box-shadow:var(--sh-sink);background:linear-gradient(90deg,var(--hue) 0 var(--p),transparent var(--p)),var(--tile-2)}
input.range::-webkit-slider-thumb{-webkit-appearance:none;width:28px;height:28px;margin-top:-9px;border-radius:50%;border:0;background:var(--card-solid);box-shadow:var(--sh-lift)}
input.range::-moz-range-track{height:10px;border-radius:5px;background:var(--tile-2);box-shadow:var(--sh-sink)}
input.range::-moz-range-progress{height:10px;border-radius:5px;background:var(--hue)}
input.range::-moz-range-thumb{width:28px;height:28px;border:0;border-radius:50%;background:var(--card-solid);box-shadow:var(--sh-lift)}
input.range:focus-visible{outline:none}
input.range:focus-visible::-webkit-slider-thumb{box-shadow:var(--sh-lift),0 0 0 3px var(--hue-soft),0 0 0 5px var(--hue)}

/* ───────── links, QR, video, listeners ───────── */
.link{padding:13px 16px;border-radius:18px;font:14px/1.45 var(--mono);word-break:break-all;-webkit-user-select:all;user-select:all;background:var(--tile);box-shadow:var(--sh-sink)}
.link+.link{margin-top:8px}
.qr{width:fit-content;margin:4px auto 0;padding:14px;border-radius:22px;background:#fff;box-shadow:var(--sh-lift)}
.qr canvas{display:block;width:216px;height:216px;image-rendering:pixelated}
.vidwrap{border-radius:22px;overflow:hidden;background:#000;display:grid;place-items:center;max-height:340px;box-shadow:var(--sh-sink)}
.vidwrap video{display:block;max-width:100%;max-height:340px}
.countrow{display:flex;align-items:baseline;gap:12px}
.count{font-size:56px}
.countlabel{font-weight:500}
ul.people{list-style:none;margin:0;padding:6px 16px;border-radius:var(--r-tile);background:var(--tile)}
ul.people li{display:flex;align-items:center;gap:12px;min-height:50px;padding:6px 0;border-top:1px solid var(--line);font-size:15px}
ul.people li:first-child{border-top:0}
ul.people li[data-i]::before{content:attr(data-i);flex:none;width:32px;height:32px;border-radius:50%;display:grid;place-items:center;font-size:13px;font-weight:600;color:var(--hue-ink);background:var(--hue-soft)}
ul.people li span:first-child{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:500}
ul.people li span+span{flex:none;font-size:13px;color:var(--muted);font-variant-numeric:tabular-nums}
ul.people li.empty{justify-content:center;color:var(--muted);font-size:14px}

/* ───────── listener: page 1 (join) and page 2 (listening) ───────── */
#listen[data-page="join"] #lLive,#listen[data-page="live"] #lJoin{display:none}
.lpage{display:flex;flex-direction:column;gap:14px}
.listen-hero{min-height:250px}
.pagehead{display:flex;align-items:center;gap:12px;margin:0 2px}
.pagetitle{display:flex;flex-direction:column;min-width:0}
.pagetitle .label{margin:0}
.pagetitle .h2{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.listen-air{min-height:250px}
.target.big{width:128px;height:128px}
.disc{width:56px;height:56px;border-radius:50%;display:grid;place-items:center;background:rgba(255,255,255,.3);color:#fff;
  transform:scale(calc(1 + var(--lvl,0) * .12));transition:transform .6s var(--ease-out),background .3s}
.disc svg.i{width:26px;height:26px}
#lStage[data-state="live"] .disc{background:#fff;color:var(--aura-a);box-shadow:0 0 30px 6px var(--bloom-2)}
#lStage[data-state="wait"] .disc{animation:breathe 1.6s var(--ease-io) infinite alternate}
@keyframes breathe{from{opacity:1}to{opacity:.55}}
.delayread{font-size:64px;margin:4px 0 8px}
.dot.live{background:#fff;box-shadow:0 0 0 4px rgba(255,255,255,.25)}
.foot{text-align:center;margin:4px 6px 0}

/* ───────── watch (local video) ───────── */
body.watching{padding:0;background:#000}
body.watching::before,body.watching::after,body.watching .top{display:none}
body.watching main{max-width:none}
.watch .stage{position:fixed;inset:0;background:#000;display:grid;place-items:center;container-type:size}
/* Turn the picture (Ethan, 2026-11-12): in 90-degree steps, in the page and in full screen (the stage is what goes full
   screen, so the same rules apply there). At 90 and 270 degrees the video box takes the stage's height as its width
   and the width as its height (cqh, cqw), then turns about its centre: a 9:16 window then fills a 16:9 screen.
   Only transform changes: no layout work while the video plays. */
.watch .stage[data-turn="90"] video,.watch .stage[data-turn="270"] video{inset:auto;left:50%;top:50%;width:100cqh;height:100cqw}
.watch .stage[data-turn="90"] video{transform:translate(-50%,-50%) rotate(90deg)}
.watch .stage[data-turn="180"] video{transform:rotate(180deg)}
.watch .stage[data-turn="270"] video{transform:translate(-50%,-50%) rotate(270deg)}
/* The video fills the stage itself, not a grid row sized to its content: in a row, height:100% resolved to nothing and a
   9:16 window grew to its own height, so a projector or a phone on its side showed only a strip of it. */
.watch video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;background:#000}
.wwait{position:absolute;left:50%;top:50%;width:min(420px,calc(100% - 32px));transform:translate(-50%,-50%);padding:24px;display:flex;flex-direction:column;gap:14px}
.wbar{position:absolute;left:0;right:0;top:0;display:flex;align-items:center;gap:10px;padding:max(12px,env(safe-area-inset-top)) max(12px,env(safe-area-inset-right)) 12px max(12px,env(safe-area-inset-left));
  transition:opacity .3s var(--ease-out)}
.wbar.hide{opacity:0;pointer-events:none}
/* No backdrop blur over the video: it would be redone for every video frame. */
.glassy{background:rgba(20,22,28,.62);color:#fff;box-shadow:none}
.chip.glassy{color:#fff}
.small.glassy{padding:6px 12px;border-radius:999px;font:12px/1.4 var(--mono);color:rgba(255,255,255,.85)}
.small.glassy:empty{display:none}
/* The stats pill is out of the row, right under the buttons: its text grows ("sound +N ms") and wraps on a phone, and
   in the row that moved Sound, Turn and Full screen down by up to 17 px (rule 4; Arcadia's WebKit check, 2026-11-12). */
#wStats{position:absolute;top:100%;right:max(12px,env(safe-area-inset-right));margin-top:-4px;max-width:calc(100% - 24px)}
#wChip .dot{background:#6f9bff;box-shadow:0 0 0 4px rgba(111,155,255,.3)}
/* Sound: off at first (a crossed speaker); on, the button fills with the screen's hue. It never moves (rule 4). */
#wSound .s-on,#wSound[aria-pressed="true"] .s-off{display:none}
#wSound[aria-pressed="true"] .s-on{display:block}
#wSound[aria-pressed="true"]{background:var(--hue);color:#fff}

/* ───────── motion: never linear. Ease-out (--ease-soft) to enter, ease-in-out (--ease-io) to change on screen ───────── */
/* The aura's colors are registered, so blue to red (on air) and the theme switch crossfade instead of jumping. */
@property --aura-a{syntax:'<color>';inherits:true;initial-value:#2f6ae0}
@property --aura-b{syntax:'<color>';inherits:true;initial-value:#1f4fb8}
@property --aura-hl{syntax:'<color>';inherits:true;initial-value:rgba(196,215,255,.8)}
@property --aura-glow{syntax:'<color>';inherits:true;initial-value:rgba(47,106,224,.7)}
@property --bloom-1{syntax:'<color>';inherits:true;initial-value:rgba(255,255,255,.6)}
@property --bloom-2{syntax:'<color>';inherits:true;initial-value:rgba(196,215,255,.55)}
@property --bloom-3{syntax:'<color>';inherits:true;initial-value:rgba(111,155,255,.65)}
/* Things that appear (a tab's cards, the second listen page, QR codes, the video preview, messages) fade and
   rise 8 px into place; controls in the action bar only fade, so they never move. @starting-style needs
   Chrome 117 or Safari 17.5; older browsers show them at once. */
.card,.lpage,.qr,.vidwrap,#watchBox,.actionbar>.err,.err.banner{transition:opacity .22s var(--ease-soft),translate .22s var(--ease-soft)}
.lpage{transition-duration:.26s}
.aura{transition:opacity .22s var(--ease-soft),translate .22s var(--ease-soft),
  --aura-a .28s var(--ease-io),--aura-b .28s var(--ease-io),--aura-hl .28s var(--ease-io),--aura-glow .28s var(--ease-io),
  --bloom-1 .28s var(--ease-io),--bloom-2 .28s var(--ease-io),--bloom-3 .28s var(--ease-io)}
.actionrow .slot>.pill{transition:opacity .2s var(--ease-soft),transform .16s var(--ease-out),box-shadow .2s var(--ease-out)}
.actionrow .mutebtn{transition:opacity .2s var(--ease-soft),transform .16s var(--ease-out)}
.slotnote{transition:opacity .2s var(--ease-soft)}
.btn .knob svg{transition:opacity .16s var(--ease-soft),scale .16s var(--ease-soft)}
#levelsCard,#peopleCard{transition-delay:40ms}
@starting-style{
  .card,.aura,.lpage,.qr,.vidwrap,#watchBox,.actionbar>.err,.err.banner{opacity:0;translate:0 8px}
  #listen.fwd #lLive{translate:24px 0}
  #listen.back #lJoin{translate:-24px 0}
  .actionrow .slot>*{opacity:0}
  .btn .knob svg{opacity:0;scale:.6}
}

/* ───────── comfort and access ───────── */
/* Reduced motion: fewer and gentler. Keep fades and color crossfades, drop movement. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important}
  .card,.aura,.lpage,.qr,.vidwrap,#watchBox,.actionbar>.err,.err.banner,.btn .knob svg{translate:none!important;scale:none!important}
  .seg::before{transition:none}
  .bloom{scale:1!important}
  .lamp,.disc{transform:none!important}
}
@media (prefers-contrast:more){
  :root{--card:var(--card-strong);--line:var(--muted)}
  .card{-webkit-backdrop-filter:none;backdrop-filter:none}
}
@media (forced-colors:active){
  .btn,.pill,.iconbtn,.seg button,.field,.selwrap select,.mutebtn{border:1px solid ButtonText}
  .seg button[aria-checked="true"],.seg button[aria-pressed="true"]{outline:2px solid Highlight}
  .meter i{background:Highlight}
}
