/* Vibe Check — the shared SEND BOX. One component on the homepage (anon, locked) and the studio
   (signed-in, unlocked). 3 states: rest / uploading / ready. Values from SENDBOX-SPEC.md.
   Tokens from tokens.css. WeTransfer layout: compact near-opaque card top-left over a full-bleed
   bg + scrim. */

/* base: Inter everywhere. The homepage loads only tokens.css + this file, so without a body
   font-family it falls back to the browser serif (the studio escapes that via studio.css).
   Inter + Roboto Mono come from the Google Fonts <link> in the page head. */
*{ box-sizing:border-box; }   /* the homepage loads no other reset; without this the full-width card's padding+border overflow */
/* single-viewport lock (ch): the page itself never scrolls on any surface. Matches player.css/studio.css,
   which already lock html,body — here it covers the homepage. Overflow (e.g. the taller uploading state on a
   short phone) is absorbed as INTERNAL scroll by .sb-home below, which the (ch) rule explicitly allows. */
html,body{ margin:0; height:100%; overflow:hidden; overscroll-behavior:none; }
body{ font-family:var(--ui); color:var(--text); background:var(--base); -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility; overflow-x:hidden; }
/* form controls don't inherit text-transform by default — without this, buttons/inputs (Get your link,
   Save changes, the expiry pill, etc.) escape the cards' lowercase. The id/class exemptions below still
   win by specificity, so user-typed values + avatar initials stay as-is. Loaded by all four surfaces. */
button, input, select, textarea{ text-transform:inherit; }

/* portrait lock: the card layouts are portrait-first, so phones in landscape get a "rotate to portrait"
   cover instead of a broken layout. (A true OS orientation lock isn't possible on iOS Safari from the web,
   so this prompts rotation.) Only the surfaces that include the .vc-rotate element — studio + homepage. */
.vc-rotate{ display:none; }
@media (orientation:landscape) and (max-height:540px) and (pointer:coarse){
  .vc-rotate{ display:flex; position:fixed; inset:0; z-index:9000; align-items:center; justify-content:center;
    background:#0C0C0E; padding:24px; text-align:center; }
  .vc-rotate__in{ display:flex; flex-direction:column; align-items:center; gap:12px; font:600 15px var(--ui); color:rgba(255,255,255,.92); }
  .vc-rotate svg{ color:var(--blue); }
}

/* ---- stage: full-bleed bg + scrim, box top-left ------------------------------------------- */
.sb-wall{ position:fixed; inset:0; z-index:0; background:
  radial-gradient(120% 80% at 72% 18%, #283450 0%, rgba(40,52,80,0) 55%),
  radial-gradient(110% 90% at 18% 92%, #3a2436 0%, rgba(58,36,54,0) 52%),
  linear-gradient(158deg, #0f1117 0%, #08080b 60%, #050507 100%); background-size:cover; background-position:center; }
.sb-wall img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
.sb-scrim{ position:fixed; inset:0; z-index:1; background:linear-gradient(180deg,rgba(8,6,6,.38),rgba(8,6,6,.22) 45%,rgba(8,6,6,.52)); }
/* Brand scrim/vignette behind the FLOATING CARD — ONE source, shared by the homepage hero + the studio (NOT
   the centred recipient players, which keep plain .sb-scrim). A soft vignette: darker at the edges/corners
   where the box + hero text sit (box bottom-left, text right, studio card top-left), fading to a clear centre
   so the wallpaper still reads. The 90deg layer adds a touch more on the right for white hero type over the
   bright Studer photo. Subtle: enough to separate the card + carry the type, not enough to kill the photo. */
.sb-scrim-lift{ background:
  radial-gradient(135% 115% at 50% 40%, rgba(6,5,8,0) 30%, rgba(6,5,8,.32) 66%, rgba(6,5,8,.60) 100%),
  linear-gradient(90deg, rgba(6,5,8,0) 58%, rgba(6,5,8,.24) 100%); }
/* ---- THE CARD'S TOP OFFSET, ONE DECLARED TOKEN (Sid, 2026-08-02) ----
   The player sat lower from the viewport top than the studio — 20 against 7 at an ordinary
   1440x800, measured at 100% zoom on the same window. Two ladders for one thing. This is the
   STUDIO's, which is the tighter one, and every surface reads it: studio, both Listen Later skins,
   the live player. It is a token and not a copied number for the reason the well and the auto-play
   switch both taught — a hand-kept second copy drifts, and verify-shared-controls asserts these
   agree across surfaces now.
   The homepage is deliberately outside it: its card is CENTRED in the stage, so its top is a
   consequence of the viewport rather than an offset. */
:root{ --card-top:48px; }
@media (max-height:800px){ :root{ --card-top:7px; } }
@media (max-width:480px){ :root{ --card-top:14px; } }
.sb-stage{ position:relative; z-index:2; min-height:100vh; min-height:100dvh; padding:var(--card-top) 56px;
  padding-top:max(var(--card-top), env(safe-area-inset-top)); padding-bottom:max(40px, env(safe-area-inset-bottom)); }
/* homepage stage owns the scroll (single-viewport lock (ch)): the page is fixed to the viewport and any
   overflow scrolls WITHIN here, so the browser page never scrolls. Homepage-only — the players/studio use
   their own stage classes. Applies at every breakpoint; the media-query .sb-home rules only add layout. */
.sb-home{ height:100%; overflow-y:auto; overscroll-behavior:contain; }

/* ---- card: the shared .st-card (promoted below) — the old .sb shell is gone ------------------ */

/* all homepage box copy is lowercase (matches the lowercase hero); wordmark is an image so unaffected */
#box{ text-transform:lowercase; }
/* but never flatten what the user typed: the track-name + message inputs keep their value as-typed, and
   the generated link URL keeps its real case. (Placeholders are lowercased in the markup.) */
#trackName, #box #message, #resultUrl{ text-transform:none; }

/* ---- chrome: wordmark / tagline / avatar / section label / footer ------------------------- */
.sb-brand{ position:relative; display:flex; align-items:center; }   /* layout via shared .vc-head (centered wordmark; the image is .st-wordmark) */
/* homepage chrome: a quiet "Sign in" link, top-right of the header, vertically centred on the
   wordmark. Absolutely positioned so it never shifts the centred wordmark; present in all 3
   homepage states. (Signed-in visitors are redirected to /studio, which shows the avatar instead.) */
.sb-signin{ position:absolute; right:0; top:50%; transform:translateY(-50%); font:500 12.5px var(--ui);
  color:rgba(255,255,255,.7); background:none; border:none; text-decoration:none; cursor:pointer; padding:0; }
.sb-signin:hover{ color:#fff; }

/* ---- shared HEADER component: [optional left] · centered wordmark · [optional right] ---------- */
/* One header for homepage + studio + edit so they all match. The wordmark is optically centered on the
   card; side controls are pulled OUT of flow (absolute) so they flank it without shifting it off-centre.
   homepage = sign-in right · studio = avatar right · edit = back left + avatar right. (Players keep their
   own already-centred header.) */
.vc-head{ position:relative; display:flex; justify-content:center; align-items:center; min-height:30px; }
.vc-head .st-back{ position:absolute; left:0; top:50%; transform:translateY(-50%); margin:0; }
.vc-head .sb-signin, .vc-head .st-avatar{ position:absolute; right:0; top:50%; transform:translateY(-50%); margin:0; }
/* PAGE chrome: the shared top-bar component (wordmark + tertiary link + optional sign-in) moved to
   topbar.css — ONE component for the homepage and /about so the corner brand never jumps. */
/* account menu (anchored under the avatar) — header + divider + action rows */
/* Account menu: a distinct ~280px panel floating clearly on top, anchored under the top-right avatar (position
   + top/right are set in JS as position:FIXED so the card's overflow:hidden can't clip/fuse it). Surface #1C1C1E
   with a crisp 0.5px hairline + a soft shadow so it separates from the same-colour card behind it. (§10) */
.sb-acctpop{ position:fixed; z-index:60; width:280px; max-width:calc(100vw - 36px);
  background:var(--surface-1); border:0.5px solid rgba(255,255,255,.2); border-radius:14px; box-shadow:0 16px 44px rgba(0,0,0,.6); padding:8px; }   /* popover surface, NOT the card ground — same value by coincidence until the card moved */
.sb-acctpop .achead{ display:flex; align-items:center; gap:12px; padding:10px 9px 12px; }
.sb-acctpop .achead .ava{ width:40px; height:40px; border-radius:50%; flex:0 0 auto; background:var(--blue) center/cover no-repeat;
  color:#fff; display:flex; align-items:center; justify-content:center; font-size:16px; font-weight:600; }
.sb-acctpop .achead .meta{ min-width:0; }
.sb-acctpop .achead .nm{ font-size:14px; font-weight:600; color:#fff; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sb-acctpop .achead .em{ font-size:12.5px; color:rgba(255,255,255,.55); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; margin-top:1px; }
.sb-acctpop .acdiv{ height:1px; background:rgba(255,255,255,.10); margin:2px 4px 6px; }
.sb-acctpop .acrow{ display:flex; align-items:center; gap:11px; width:100%; text-align:left; background:none; border:none;
  color:#fff; font:500 13.5px var(--ui); padding:10px 9px; cursor:pointer; border-radius:9px; }
.sb-acctpop .acrow:hover{ background:rgba(255,255,255,.06); }
.sb-acctpop .acrow svg{ flex:0 0 auto; width:17px; height:17px; color:rgba(255,255,255,.55); }
.sb-tagline{ text-align:center; font-size:14px; color:var(--text-2); margin-top:8px; line-height:1.4; }
.sb-label{ font-family:var(--mono); font-size:11px; letter-spacing:1px; color:rgba(255,255,255,.5); margin-top:20px; }
.sb-foot{ text-align:center; margin-top:16px; padding-top:14px; border-top:1px solid rgba(255,255,255,.12); }
.sb-foot .vc-pfoot{ margin-top:0; }   /* the divider's own padding is the air here */
/* trust line spacing — still used by the STUDIO first-upload footer (its block keeps the trust pair) */
.sb-trust{ margin-top:8px; }
.sb-plays{ text-align:center; font-size:12px; color:rgba(255,255,255,.5); margin-top:16px; }

/* ---- state 1: drop zone ------------------------------------------------------------------- */
/* homepage well = the studio's frosted .st-win (clean transparent window onto the wallpaper, no dashed
   border) — this just centres the drop prompt inside it. */
.sb-drop{ display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center;
  min-height:150px; border-radius:13px; clip-path:inset(0 round 13px); padding:22px 20px; margin-top:18px; cursor:pointer; transition:box-shadow .15s; }
.sb-drop:hover, .sb-drop.drag{ box-shadow:inset 0 0 0 1.5px var(--blue); }
.sb-dropIcon{ width:46px; height:46px; border-radius:50%; background:rgba(255,255,255,.07); display:flex;
  align-items:center; justify-content:center; margin:0 auto; color:#7fa0e8; }
.sb-dropTitle{ font-weight:600; font-size:15.5px; margin-top:12px; color:#fff; }
.sb-dropHint{ font-size:12.5px; color:rgba(255,255,255,.5); margin-top:4px; }

/* ---- state 2: uploading — the studio uploader's waveform well + play (shared wave.js) -------- */
/* .sb-upwell is a CLEAN dark well (player-style, not the frosted glass): wave.js draws its
   decorative placeholder envelope in it during upload (the waveform fills L→R — it IS the progress
   bar) and resolves to the real peaks when the server responds. Centred "uploading %" readout. */
.sb-upwell{ position:relative; overflow:hidden; height:150px; border-radius:13px; margin-top:18px;
  background:rgba(0,0,0,.5); }
.sb-upwell canvas{ position:absolute; inset:0; width:100%; height:100%; display:block; }
.sb-upPct{ position:absolute; left:50%; top:50%; transform:translate(-50%,-50%);
  font:500 11.5px var(--mono); color:rgba(255,255,255,.92); letter-spacing:.02em;
  text-shadow:0 1px 5px rgba(0,0,0,.6); pointer-events:none; }
.sb-upPlayRow{ display:flex; justify-content:center; margin-top:14px; }
.sb-upPlayRow[hidden]{ display:none; }   /* the play button doesn't render until 'ready' — [hidden] must beat display:flex */
.sb-upPlay{ flex:none; width:72px; height:72px; border-radius:50%; border:none; background:var(--blue); cursor:pointer;
  box-shadow:0 14px 30px rgba(63,111,214,.5); display:flex; align-items:center; justify-content:center;
  transition:transform .12s ease, background .15s ease; }
.sb-upPlay:hover{ transform:scale(1.04); }
.sb-upPlay svg{ width:28px; height:28px; }
.sb-upPlay:disabled{ background:rgba(255,255,255,.08); box-shadow:none; cursor:default; transform:none; }

/* ---- shared SEND-BOX FIELDS — studio uploader + homepage box render from ONE source ---------- */
/* Moved here from studio.css so the field type/spacing can't drift between the two surfaces. Values
   are byte-identical to the studio's; the two studio-local vars (var(--f), var(--blue-soft)) are
   inlined to their literals so they also resolve on the homepage (which doesn't load studio.css). */
.st-fields{ flex:0 0 auto; margin-top:12px; }
.st-fields.locked{ opacity:.45; pointer-events:none; }   /* signed-out homepage: fields visible but locked */
.st-input{ width:100%; font-family:inherit; font-size:14px; padding:8px 13px; border:1px solid rgba(255,255,255,.18); border-radius:11px;
  outline:none; color:#fff; background:rgba(255,255,255,.07); }
.st-input::placeholder{ color:rgba(255,255,255,.4); }
.st-input:focus{ border-color:var(--blue); box-shadow:0 0 0 3px rgba(59,116,240,.18); }
.st-input + .st-input{ margin-top:7px; }
.st-detailRow{ display:flex; align-items:center; gap:9px; margin-top:9px; }
.st-flabel{ font-size:13.5px; color:rgba(255,255,255,.6); font-weight:500; flex:none; }
.st-pill{ flex:1; min-width:0; display:flex; align-items:center; justify-content:center; gap:7px; white-space:nowrap; font-weight:600; font-size:13.5px; font-family:inherit;
  border:1px solid rgba(255,255,255,.18); border-radius:10px; padding:6px 12px; background:rgba(255,255,255,.07); color:#fff; cursor:pointer; }
.st-pill svg{ transition:transform .15s; flex:none; }
.st-expWrap{ position:relative; display:flex; flex:1; min-width:0; }
.st-expWrap.open .st-pill{ border-color:var(--blue); background:rgba(59,116,240,.14); }
.st-expWrap.open .st-pill svg{ transform:rotate(180deg); }
.st-menu{ position:absolute; top:calc(100% + 6px); right:0; width:178px; background:var(--surface-1); border:.5px solid rgba(255,255,255,.2);
  border-radius:12px; box-shadow:0 18px 44px rgba(0,0,0,.6); padding:5px; z-index:40; }
.st-menu .mi{ display:flex; align-items:center; justify-content:space-between; padding:8px 10px; border-radius:8px; font-size:13px; color:#fff; cursor:pointer; }
.st-menu .mi:hover{ background:rgba(255,255,255,.06); }
.st-menu .mi.on{ background:rgba(59,116,240,.18); font-weight:600; }
.st-menu .mi svg{ opacity:0; }
.st-menu .mi.on svg{ opacity:1; }
.st-menu .div{ height:1px; background:rgba(255,255,255,.1); margin:5px 8px; }
.st-pin{ flex:1; min-width:0; font-family:var(--mono); font-size:13.5px; text-align:center; padding:6px 12px; border:1px solid rgba(255,255,255,.18);
  border-radius:10px; outline:none; color:#fff; background:rgba(255,255,255,.07); }
.st-pin::placeholder{ color:rgba(255,255,255,.4); }
.st-pin:focus{ border-color:var(--blue); box-shadow:0 0 0 3px rgba(59,116,240,.18); }
.st-go{ flex:0 0 auto; width:100%; display:flex; align-items:center; justify-content:center; gap:8px; padding:13px; border-radius:12px;
  border:none; background:var(--blue); color:#fff; cursor:pointer; font:600 15px var(--ui); margin-top:14px; box-shadow:0 8px 18px rgba(63,111,214,.30); }
.st-go[disabled]{ background:rgba(255,255,255,.07); color:rgba(255,255,255,.3); cursor:not-allowed; box-shadow:none; }
@media (max-width:480px){
  .st-detailRow{ gap:10px; }   /* clear space between "disappears in" and the dropdown */
  .st-detailRow .st-flabel{ font-size:13px; white-space:nowrap; }
  .st-pill, .st-pin{ font-size:13px; padding:5px 9px; }
  .st-pill{ gap:6px; }
}

/* homepage sign-in cue: a quiet question + a big "sign in" CTA (the conversion action). Centered:
   icon sits inline with the question, the "sign in" line centers under it. */
.sb-cue{ background:rgba(59,116,240,.10); border-radius:11px; text-align:center;
  padding:12px 13px; margin-top:13px; font-size:13.5px; color:rgba(255,255,255,.72); line-height:1.5; }
.sb-cueQ{ display:inline-flex; align-items:center; gap:7px; }
.sb-cue svg{ flex:0 0 auto; color:var(--blue); }
.sb-cueA{ margin-top:4px; font-size:12.5px; color:rgba(255,255,255,.5); }   /* "(it's 100% free)" aside */
.sb-cueA a{ font-size:15px; font-weight:700; color:var(--blue-text); cursor:pointer; text-decoration:underline; text-underline-offset:2px; margin-right:5px; }
.sb-cueA a:hover{ color:#5a8bf5; }
/* (the old mid-upload inert "waiting" state is gone: signing in mid-flight hands the File over) */

/* state 3 (success card) removed: the flow lands directly on the /{token} owner view */

/* ============================================================================
   SHARED studio components — single source of truth for the studio AND the homepage.
   The studio (studio.css) layers its fixed-height shell on .st-card; the homepage uses
   the chrome as-is (content-height). Promoted out of studio.css so both pages render the
   SAME card, the SAME frosted well, and the SAME wordmark — not two lookalikes.
   ============================================================================ */
:root{ --wall-img:url("/l/_assets/studio-bg.jpg"); }   /* homepage overrides this to its own wallpaper */
.st-card{ position:relative; width:412px; max-width:100%; background:var(--surface-card); border:1px solid #26282B; border-radius:24px;   /* edge + radius from Acetate_Collection.html, measured 2026-07-31 */   /* the ONE card ground: player moved to #1A1B1D first, studio + homepage follow (2026-07-30) */
  box-shadow:0 30px 80px rgba(0,0,0,.7); padding:22px 24px; }
/* The frosted "window": a blurred slice of the SAME wallpaper that sits behind the card, ALIGNED to
   each well's on-screen position so it reads as real see-through glass (not a centered sticker copy).
   We can't use backdrop-filter (the card is solid, so it would only blur the card) and
   background-attachment:fixed is flaky on iOS, so wall-sync.js sets --wall-size + --wall-pos per well
   to match the full-bleed background. The cover/center values below are the graceful no-JS fallback. */
/* overflow:CLIP, not hidden. The waveform canvas runs ~40px past the well on every surface, and a
   hidden box is still programmatically SCROLLABLE — WebKit scrolls the nearest such ancestor to
   chase a focused caret, which is the iOS bug the studio already had to fix on its own copy of this
   well. Both axes are hidden here, so clip does not degrade to hidden the way it does beside an
   auto axis. Painting is unchanged. Fixed once here, so the players inherit it. */
.st-win{ position:relative; overflow:clip; isolation:isolate; background:transparent;
  transform:translateZ(0); }   /* force Safari to clip the blurred ::before to the rounded corners (no white corner leaks) */
.st-win::before{ content:""; position:absolute; inset:-40px; z-index:-2;
  background-image:var(--wall-img); background-repeat:no-repeat;
  background-size:var(--wall-size, cover); background-position:var(--wall-pos, center); filter:blur(12px); }
.st-win::after{ content:""; position:absolute; inset:0; z-index:-1; background:rgba(0,0,0,.5); }
.st-wordmark{ font-weight:200; font-size:31px; line-height:22.5px; letter-spacing:.34em; padding-left:.34em; text-transform:uppercase; color:#fff; display:block; white-space:nowrap; }

/* homepage card (state 1): a left-aligned title block — prominent lowercase headline + Sign in on one
   row, a small tertiary sub-line beneath — then the drop zone, then the divider/footer. Even, calm
   rhythm; no wordmark inside (it lives in the page corner). */
#box .sb-cardtop{ display:flex; align-items:baseline; justify-content:space-between; gap:12px; }
#box .sb-cardh{ margin:0; font:500 21px/1.2 var(--ui); letter-spacing:-.01em; color:#fff; }
#box .sb-cardtop .sb-signin{ position:static; transform:none; flex:0 0 auto; }
#box .sb-sub{ margin-top:5px; font-size:12.5px; line-height:1.45; color:rgba(255,255,255,.5); }
#box #rest .sb-drop{ margin-top:18px; }
#box #rest .sb-foot{ margin-top:18px; }

/* homepage mobile layout (hero on top + bottom-sheet box) is consolidated at the END of this file
   so it cascades after the base .sb-hero/.sb-scrim-home rules. */

/* ============================================================================
   HOMEPAGE hero over the Studer photo (desktop only). Box stays top-left; the
   BIG headline + sub sit on the RIGHT, right-aligned and vertically centred
   (the approved reference). Photo stays bright — only a gentle right-side scrim;
   the white type carries on its weight + a soft shadow.
   ============================================================================ */
/* .sb-scrim-home retired — the scrim is unified in .sb-scrim-lift (single source, homepage + studio). */

.sb-hero{ display:none; }   /* hidden on mobile/tablet; shown on desktop below */

@media (min-width:721px){
  .sb-home{ display:flex; flex-direction:row; align-items:flex-start; gap:40px; }
  .sb-home > #box{ flex:0 0 auto; align-self:flex-end; }   /* box sits BOTTOM-left */
  /* fill the space to the RIGHT of the box; vertically centred, right-aligned */
  .sb-hero{ display:flex; flex-direction:column; justify-content:center; align-items:flex-end;
    flex:1 1 0; min-width:0; align-self:stretch; text-align:right; }
  .sb-heroH{ margin:0; font:800 clamp(56px, 7.2vw, 96px)/1.03 var(--ui); letter-spacing:-.03em; color:#fff;
    text-shadow:0 2px 24px rgba(0,0,0,.42); }
  .sb-heroP{ margin:24px 0 0; max-width:540px; font:400 clamp(18px, 1.9vw, 25px)/1.42 var(--ui); color:#fff;
    text-shadow:0 1px 14px rgba(0,0,0,.5); }
}

/* ============================================================================
   HOMEPAGE — MOBILE: hero on top (over a top scrim), box FLOATS near the bottom
   with wallpaper around it (margins all sides + a bottom gap, all corners curved).
   Placed last so it cascades after the base .sb-hero (display:none) + scrim rules.
   ============================================================================ */
@media (max-width:480px){
  /* reserve the bottom zone the fixed "need help?" pill lives in (pill ~33px tall, 14px from the edge),
     so the card is laid out clear of it; the card then centres in the space ABOVE this zone. */
  .sb-home{ display:flex; flex-direction:column; justify-content:flex-start; padding:0;
    padding-bottom:max(64px, calc(env(safe-area-inset-bottom) + 50px)); }

  /* hero text above the box. LEFT-aligned on mobile (reads cleaner than right-ragged at this width),
     and pushed WELL below the fixed corner brand row so the two layers don't cram — the corner row
     owns the top ~52px, the headline starts noticeably lower with clear breathing room. */
  .sb-home .sb-hero{ display:block; order:-1; max-width:none; text-align:left;
    padding:max(118px, calc(env(safe-area-inset-top) + 84px)) 20px 22px; }
  .sb-heroH{ margin:0; font:800 31px/1.08 var(--ui); letter-spacing:-.028em; color:#fff;
    text-shadow:0 2px 6px rgba(0,0,0,.5), 0 2px 20px rgba(0,0,0,.55); }
  .sb-heroP{ margin:16px 0 0; font:400 19px/1.5 var(--ui); color:#fff;
    text-shadow:0 1px 12px rgba(0,0,0,.55); }

  /* (cf/ch) mobile: the caption flows right under the hero sub-lines (nested in .sb-hero → inherits the
     right-align), at caption scale so it stays subordinate. Same soft shadow as the hero over the photo.
     Parent-scoped (.sb-home) so this beats the base `.sb-cap{display:none}`, which sits LATER in source. */
  .sb-home .sb-cap{ display:block; position:static; max-width:none; margin:20px 0 0; text-align:right;
    text-shadow:0 1px 12px rgba(0,0,0,.55); }
  .sb-capH{ margin:0 0 7px; font:600 13px/1.35 var(--ui); letter-spacing:.01em; color:rgba(255,255,255,.9); }
  .sb-capP{ margin:0 0 5px; font:400 12px/1.5 var(--ui); color:rgba(255,255,255,.66); }
  .sb-capP:last-child{ margin-bottom:0; color:rgba(255,255,255,.84); }

  /* box FLOATS with wallpaper around it (NOT a full-bleed sheet). Auto top+bottom margins CENTRE it in
     the free space below the hero, so the gap above and below feels balanced (no dead space) — and it
     stays clear of the reserved pill zone. On a very short viewport the auto margins collapse first
     (card tightens/shifts up) so the pill never covers the trust line. */
  #box.st-card{ width:auto; max-width:none; border-radius:24px;
    margin:auto 16px; padding:18px 20px; }
  #box .sb-sub{ margin-top:4px; }
  #box .sb-drop{ min-height:114px; padding:16px; margin-top:15px; }
  #box .sb-dropTitle{ margin-top:9px; }
  #box #rest .sb-foot{ margin-top:15px; padding-top:12px; }

  /* POST-DROP (busy): the pitch is done — the hero hides so the expanded card owns the viewport
     (it returns on reset; the corner brand row stays), and the card compacts (same discipline as
     the owner view) so uploading fits short phones without any page scroll. */
  .sb-home.busy .sb-hero{ display:none; }
  .sb-home.busy #box.st-card{ margin-top:auto; }
  #box .sb-upwell{ height:104px; margin-top:12px; }
  #box .st-fields{ margin-top:10px; }
  #box .st-input{ padding:7px 12px; }
  #box .sb-cue{ margin-top:10px; padding:10px 12px; }
  #box .st-go{ margin-top:12px; padding:12px; }

  /* top scrim so the white corner row + headline are legible on the light silver photo at this crop:
     add a top-down dark band over the shared vignette (consistent with the desktop scrim treatment). */
  .sb-scrim-lift{ background:
    linear-gradient(180deg, rgba(6,5,8,.60) 0%, rgba(6,5,8,.34) 26%, rgba(6,5,8,0) 48%),
    radial-gradient(135% 115% at 50% 40%, rgba(6,5,8,0) 30%, rgba(6,5,8,.32) 66%, rgba(6,5,8,.60) 100%),
    linear-gradient(90deg, rgba(6,5,8,0) 58%, rgba(6,5,8,.24) 100%); }
}

/* (cf) why acetate — retained markup, NOT rendered (the section carries `hidden`; these styles are kept
   so re-enabling is a one-attribute change). The copy now lives in .sb-cap below. */
.sb-why{ position:relative; z-index:2; background:var(--base); padding:110px 24px 130px; text-align:center; }
.sb-whyH{ margin:0 0 34px; font:600 17px/1.3 var(--ui); letter-spacing:.01em; color:#fff; }
.sb-whyP{ margin:0 auto 18px; max-width:520px; font:400 15.5px/1.65 var(--ui); color:rgba(255,255,255,.62); }
.sb-whyP:last-child{ margin-bottom:0; color:rgba(255,255,255,.86); }

/* (cf/ch) the digital acetate — quiet caption pinned to the bottom-right of the hero viewport. Absolutely
   placed against .sb-stage so it never disturbs the hero row or the box. Caption scale + soft shadow (it sits
   over the bright right side of the Studer photo, like .sb-heroP), clearly subordinate to the hero.
   DESKTOP ONLY, and only from 960px up: below that the bottom-left box reaches too far right to clear it (at
   880px the gutter is just ~16px), so per the single-viewport rule we omit it rather than shrink it. Hidden on
   mobile/tablet by the same gate. */
.sb-cap{ display:none; }
@media (min-width:960px){
  /* reserve the caption's bottom-right zone so the vertically-centred hero never grows down into it at short
     viewport heights (a 1366×768 laptop is ~680px of content — without this the sub-lines clip the caption). */
  .sb-hero{ padding-bottom:170px; }
  /* lifted clear of the "need help?" pill (fixed bottom-right ~62px tall) so the last caption line never sits under it */
  .sb-cap{ display:block; position:absolute; right:56px; bottom:max(84px, calc(env(safe-area-inset-bottom) + 44px));
    max-width:380px; text-align:right; text-shadow:0 1px 12px rgba(0,0,0,.5); pointer-events:none; }
  .sb-capH{ margin:0 0 9px; font:600 13.5px/1.35 var(--ui); letter-spacing:.01em; color:rgba(255,255,255,.9); }
  .sb-capP{ margin:0 0 6px; font:400 12.5px/1.5 var(--ui); color:rgba(255,255,255,.58); }
  .sb-capP:last-child{ margin-bottom:0; color:rgba(255,255,255,.8); }
}

/* ---- MOBILE fixes (phone screenshots round) --------------------------------------------------
   1 · card headers: at narrow widths the 31px wordmark collided with the back control and avatar.
       Scale it to clear both sides (back left · wordmark centred · avatar right, safe from 320px). */
@media (max-width:480px){
  .vc-head .st-wordmark, .vp-head .st-wordmark{ font-size:clamp(16px, 5.8vw, 22px); letter-spacing:.24em; padding-left:.24em; }
  /* 3 · frosted well on iOS: when the blur slice misaligns, the bright mic-room wood tints the
     whole well orange. A deeper, slightly blue-black in-well scrim keeps it near-neutral dark
     over ANY wallpaper (desktop's aligned dark slice is barely affected). */
  .st-win::after{ background:rgba(10,11,14,.66); }
  /* 4 · "no pin" placeholder was clipping to "no pir" */
  .st-pin{ min-width:64px; }
}


/* ============================================================================================
   SHARED CONTROLS — ONE COMPONENT, EVERY SURFACE (Sid's ruling, 2026-08-01)
   This file is the only stylesheet the studio, the Listen Later players and the live (/s/) player
   all load, so it is the only place a component can actually be shared. Both controls below used
   to exist as TWO copies — studio.css and player.css — each carrying a comment telling the next
   person to "keep them in step" by hand. They did not stay in step: measured live before this
   change, every single field of the auto-play control differed.

     field        studio (ruled)        player (was)
     pill         29x16                 20x12
     on-green     #2F8F4E               #30D158  (the status green, on a switch)
     knob         12x12                 9x9
     label        12/400 #8E9196        8/600 rgba(255,255,255,.78)
     axis         label ABSOLUTE, so    label in flow, so the pill+label stack was centred
                  only the pill is      and the pill sat 6.5px ABOVE the transport's centreline
                  centred (delta 0.0)   (delta -6.5)
     well         120px both widths     150px desktop / 104px at 390

   Note the well drifted in BOTH directions — bigger on desktop, smaller on a phone — which is what
   a hand-kept copy does over time and what a shared component cannot.
   The copies in studio.css and player.css are DELETED, not overridden: both files load after this
   one, so a surviving copy at equal specificity would silently win and the sharing would be
   decorative. If a value below needs to change, it changes here, once, for all three surfaces.
   ============================================================================================ */

/* ---- auto-play ---- */
.sv-auto, .st-pmAuto, .vp-auto{
  position:relative; align-self:center; flex:0 0 38px; width:38px;
  display:flex; flex-direction:column; align-items:center; gap:0;
  font:inherit; color:inherit; }
.sv-auto .sv-toggle, .st-pmAuto .sv-toggle, .vp-auto .sv-toggle{
  display:inline-flex; align-items:center; justify-content:flex-start;
  width:29px; height:16px; border-radius:999px; background:rgba(255,255,255,.2);
  padding:1.5px; border:none; cursor:pointer; position:static;
  transition:background .15s, justify-content 0s; }
.sv-auto .sv-toggle .knob, .st-pmAuto .sv-toggle .knob, .vp-auto .sv-toggle .knob{
  position:static; width:12px; height:12px; border-radius:50%; background:#fff;
  top:auto; left:auto; right:auto; transition:none; }
.sv-auto .sv-toggle[aria-checked="true"], .st-pmAuto .sv-toggle[aria-checked="true"],
.vp-auto .sv-toggle[aria-checked="true"]{ background:var(--green-on); justify-content:flex-end; }
.sv-auto .sv-toggle[aria-checked="true"] .knob, .st-pmAuto .sv-toggle[aria-checked="true"] .knob,
.vp-auto .sv-toggle[aria-checked="true"] .knob{ background:#fff; box-shadow:0 1px 2px rgba(0,0,0,.4); }
/* the label is ABSOLUTE on purpose: that is what makes ONLY THE PILL participate in the transport
   row's vertical centring, so the switch sits on the arrows' centreline instead of the stack's. */
.sv-auto > span, .st-pmAuto > span, .vp-auto > span{
  position:absolute; top:calc(100% + var(--sp-tight)); left:50%; transform:translateX(-50%);
  font-family:var(--ui); font-size:var(--t-control); font-weight:var(--t-w-reg);
  letter-spacing:var(--t-tracking); color:var(--txt-muted); white-space:nowrap; }
/* mirrors the control so PLAY stays dead-centre when auto is present */
.sv-transport.hasAuto::before, .st-playRow.hasAuto::before, .vp-playRow.hasAuto::before{
  content:''; flex:0 0 38px; }
/* PHONE: the 12px label is ~52px wide inside a 38px box, so centred it hangs ~7px past the box on
   each side. On the right that lands outside the card and makes an overflow-y:auto ancestor
   horizontally scrollable — which is what WebKit then scrolls to chase a caret (the iOS bug). The
   label anchors to the box's right edge instead; it reads as aligning to the row's right edge.
   Shared, so the players cannot inherit the bug the panel already had to fix. */
@media (max-width:480px){
  .sv-auto > span, .st-pmAuto > span, .vp-auto > span{ left:auto; right:0; transform:none; }
}

/* ---- the waveform well: ONE ruled height ----
   The height-constrained tiers in player.css stay: those compact the card on a SHORT viewport,
   which is a different axis from this ruling and the studio compacts the same way. */
.st-well, .ll-well, .live-well{ height:var(--well-h); }
/* ---- THE COMPACT STATE, on the shared component (Sid, 2026-08-02) ----
   `.has-list` is set on the CARD wherever a collection tracklist shares it — the collection player
   (app.js) and the studio's edit panel on a collection (studio.js). Sid's ruling: on a collection
   the tracklist is the most important element on the page and the layout protects it first, so the
   ceremony compacts and the list takes the room.
   min(), not a flat 84: the short-viewport tiers above already go BELOW 84 on a small phone (52 at
   390x620), and a "compact" state that made the well bigger there would be the opposite of the
   ruling. This takes whichever of the two is smaller, so the state can only ever compact.
   IT IS DECLARED ONCE, HERE, and the studio inherits it — that is the point of the well being a
   shared component rather than two copies with a comment asking the next person to keep them in
   step. The studio's collection EDIT PANEL is the surface that inherits it; the studio LIST view
   does not, deliberately: its well belongs to whichever track is loaded, not to a collection
   sharing the card, and expanding a row would otherwise resize the well under the finger. */
.st-card.has-list .st-well,
.st-card.has-list .ll-well,
.st-card.has-list .live-well{ height:min(var(--well-h), var(--well-h-tight)); }

/* ---- SHORT-VIEWPORT COMPACTION, shared ----
   Measured 2026-08-01: base height and WIDTH matched on every surface (120h, 366w desktop / 316w at
   390, identical 22px card padding) — the shared component was intact and width was never the
   difference. What differed was these tiers: the player compacted at four thresholds and the studio
   at none, so at an ordinary 1440x800 laptop window the player's well was 110 against the studio's
   120, and at 390x740 it was 96 against 120. That is the "reads smaller" Sid saw, and it appears at
   any window shorter than 820px.
   They now compact IDENTICALLY, from one place. Not flattened to 120 instead: measured, the player
   card is already capped by max-height with overflow:hidden and clips 79-116px of its own content at
   these window heights WITH the tiers in place. The tiers are a partial mitigation for that, so
   removing them would deepen an existing clip rather than fix anything. The clip itself is a
   separate, pre-existing fault — it needs the tracklist to become the flexible child the way the
   studio's list already is, and that is a layout change, not a token. */
@media (min-width:481px) and (max-height:820px){ :root{ --well-h:110px; } }
@media (min-width:481px) and (max-height:680px){ :root{ --well-h:84px; } }
@media (max-width:480px) and (max-height:760px){ :root{ --well-h:96px; } }
@media (max-width:480px) and (max-height:620px){ :root{ --well-h:52px; } }


/* ---- the signed-in account chip ----
   Sid's "one primary per card" flagged this: .vp-vava was a --blue FILL inside the same card as the
   blue play hero, so the recipient card had one blue fill and the owner card had two.
   It takes the INVERTED CHIP the product already uses for every other avatar — studio.css gives
   .st-avatar exactly this, and player.css gives the card's SENDER avatar (.vp-ava) exactly this.
   The viewer's chip was simply the one that never got it. Measured first: the studio's chip already
   computes white, so there was nothing to align there and a shared rule would have been inert on
   that surface — this is the one avatar that was still blue, and it now matches the other two.
   background-COLOR, not the shorthand: the base rule carries `center/cover no-repeat` for the photo
   case and the shorthand would throw it away. */
.vp-card .vp-vava{ background-color:#fff; color:var(--ink-invert); }
