/* Ambient Mixer — "atmosphere lab" identity: quiet glass chrome over a
   full-bleed reactive background, mono utility labels, tabular readouts.
   Dark is the home theme; a light "paper" variant swaps the variables below
   via html[data-theme="light"] (set pre-paint by the inline script in
   index.html, then kept live by js/theme.js + main.js — "system" is resolved
   to a concrete value there, so this file only knows dark and light). */
:root {
  color-scheme: dark;
  --ink:        #070a0f;
  --panel:      rgba(16, 22, 30, 0.62);
  --panel-solid: rgba(16, 22, 30, 0.55);
  --panel-line: rgba(255, 255, 255, 0.10);
  --text:       #e9eff6;
  --muted:      #8a97a8;
  --faint:      #56616f;
  --accent:     #5fd3c4;
  --accent-rgb: 95, 211, 196;  /* keep in step with --accent */
  --danger:     var(--danger);
  --danger-rgb: 255, 143, 136; /* keep in step with --danger */
  --btn-bg:       var(--btn-bg);
  --btn-bg-hover: var(--btn-bg-hover);
  --track:      rgba(255, 255, 255, 0.12);
  --tile-active-bg: rgba(22, 30, 40, 0.7);
  --title-shadow: 0 2px 24px rgba(0, 0, 0, 0.5);
  --radius:     14px;
  --bar-h:      66px; /* console fallback height (single line; the stack
                         breakpoint raises it); JS refines it via --console-h. */

  --mono: ui-monospace, "SF Mono", "SFMono-Regular", Menlo, Consolas, monospace;
  --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

/* Light "paper" theme. The accent and danger hues shift darker so filled
   pills (accent bg + --ink text) and armed-delete tints keep their contrast
   on a bright page; --ink doubles as the text-on-accent colour either way. */
html[data-theme="light"] {
  color-scheme: light;
  --ink:        #eef1f5;
  --panel:      rgba(244, 247, 250, 0.66);
  --panel-solid: rgba(244, 247, 250, 0.6);
  --panel-line: rgba(15, 30, 45, 0.14);
  --text:       #17222e;
  --muted:      #52616e;
  --faint:      #7e8a97;
  --accent:     #0e8d7d;
  --accent-rgb: 14, 141, 125;
  --danger:     #c2453c;
  --danger-rgb: 194, 69, 60;
  --btn-bg:       rgba(15, 30, 45, 0.05);
  --btn-bg-hover: rgba(15, 30, 45, 0.10);
  --track:      rgba(15, 30, 45, 0.18);
  --tile-active-bg: rgba(255, 255, 255, 0.72);
  --title-shadow: 0 2px 24px rgba(255, 255, 255, 0.65);
}

* { box-sizing: border-box; }

/* overflow-x on html makes IT the page's scroll container (body's overflow
   stops propagating to the viewport) — so the drawer's page-scroll lock below
   must target html, not body. */
html { overflow-x: hidden; }
/* While an open console drawer's panel has something to scroll (classes set
   in main.js) the page behind it locks, so there's a single scrollable area;
   when the panel fits its content, the page keeps scrolling normally. The
   body freezes in place (main.js offsets it by the scroll position and
   restores on close/release), and when a classic page scrollbar was showing,
   html keeps the empty scrollbar track so the layout width doesn't jump while
   locked. (scrollbar-gutter can't do this: Chrome ignores it on the root.) */
html.drawer-open body { position: fixed; left: 0; right: 0; }
html.drawer-open.keep-scrollbar { overflow-y: scroll; }
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--ink);
  color: var(--text);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden; /* full-bleed bg layers must never induce sideways scroll */
}

/* --- Reactive background layers (behind everything, never interactive) --- */
#bg-gl, #bg-fx {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
  pointer-events: none;
}
#bg-gl { display: none; }
#bg-flash {
  position: fixed;
  inset: -10%;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: screen;
  background: radial-gradient(circle at 50% 42%, rgba(160,190,255,0.9), transparent 68%);
  transition: opacity 90ms linear;
}
/* On paper, screen-blending a bright flash does nothing (white stays white);
   multiply lets the same pulse read as a brief tint instead. */
html[data-theme="light"] #bg-flash { mix-blend-mode: multiply; }

/* Content sits above the background layers */
.app-header, main, .console { position: relative; z-index: 2; }

/* --- Masthead --- */
.app-header { text-align: center; padding: 2.4rem 1rem 0.75rem; }
.eyebrow {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 0.6rem;
}
.app-header h1 {
  margin: 0;
  font-size: clamp(1.5rem, 3.2vw, 2rem);
  font-weight: 620;
  letter-spacing: -0.015em;
  text-shadow: var(--title-shadow);
}
.tagline {
  color: var(--muted);
  margin: 0.5rem 0 0;
  font-size: 0.9rem;
}
/* Poetic "now playing" line. Always occupies its one line (min-height) so the
   grid doesn't shift when it fades in; hidden = faded out, not display:none. */
.now-playing {
  color: var(--faint);
  font-style: italic;
  font-size: 0.82rem;
  margin: 0.4rem 0 0;
  min-height: 1.2em;
  opacity: 0;
  transition: opacity 0.6s ease;
}
.now-playing.visible { opacity: 1; }

/* Only the grid scrolls; leave room so the last tiles clear the fixed console.
   --console-h is the console row's real measured height (see main.js): the
   controls wrap to extra rows on narrow viewports, so a fixed --bar-h guess
   would let the bar overlap the last card. env() is already baked into the
   measured value; --bar-h is only the pre-JS fallback. */
main {
  flex: 1;
  max-width: 880px;
  width: 100%;
  margin: 0 auto;
  padding: 1.5rem 1rem calc(var(--console-h, calc(var(--bar-h) + env(safe-area-inset-bottom, 0px))) + 1.25rem);
}

/* Shared small caps label (group titles, section labels) */
.section-label, .group-title {
  font-family: var(--mono);
  font-size: 0.66rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--faint);
}

/* --- Sound grid --- */
.sound-grid { display: flex; flex-direction: column; gap: 1.7rem; }

/* Group label doubles as a category mute toggle */
.group-title {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.8rem;
  padding: 0.15rem 0;
  color: var(--muted);
  background: none;
  border: 0;
  cursor: pointer;
  transition: color 0.18s;
}
.group-title:hover { color: var(--text); }
.group-title:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
/* Always laid out (reserves its space) so muting only fades it in — no reflow */
.gt-mute { width: 13px; height: 13px; flex: none; opacity: 0; transition: opacity 0.18s; }
.group-title.muted .gt-label { text-decoration: line-through; text-decoration-thickness: 1px; }
.group-title.muted .gt-mute { opacity: 1; }
/* Muted category: dim the tiles' foreground and drop their active glow, but
   DON'T change their opacity — lowering opacity would reveal more of the bright
   reactive background through the glass and read as a flash before it dims. */
.sound-group.muted .tile {
  color: var(--faint);
  border-color: var(--panel-line);
  box-shadow: none;
}
.sound-group.muted .tile .tile-icon svg { color: var(--faint); }
.sound-group.muted .tile-slider { filter: grayscale(1); opacity: 0.6; }
.sound-group.muted .tile-pan { filter: grayscale(1); }
.group-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
  gap: 0.8rem;
}

.tile {
  --group: 138, 151, 168;
  background: var(--panel-solid);
  border: 1px solid var(--panel-line);
  border-radius: var(--radius);
  padding: 1.15rem 1rem 1rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.65rem;
  color: var(--muted);
  transition: color 0.25s, background 0.25s, border-color 0.25s, box-shadow 0.25s;
}
.tile.active {
  color: var(--text);
  background: var(--tile-active-bg);
  border-color: rgba(var(--group), 0.7);
  box-shadow: 0 0 26px -8px rgba(var(--group), 0.85), inset 0 1px 0 rgba(255, 255, 255, 0.05);
}
/* The icon is a per-sound play/pause button; keep it visually identical to the
   old plain glyph and let the hover nudge + cursor carry the affordance. */
.tile-icon {
  background: none;
  border: none;
  padding: 0;
  color: inherit;
  cursor: pointer;
  transition: transform 0.15s;
}
.tile-icon:hover { transform: scale(1.08); }
.tile-icon:active { transform: scale(0.96); }
.tile-icon:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }
.tile-icon svg { width: 34px; height: 34px; display: block; transition: color 0.25s; }
.tile.active .tile-icon svg { color: rgb(var(--group)); }
.tile-name { font-size: 0.88rem; letter-spacing: 0.01em; }

/* --- Support link (Ko-fi) ---
   A labelled pill on wide screens; the narrow breakpoint collapses it (and the
   copy button) to an icon-only button to keep the transport line on one row. */
.kofi-link {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 40px; /* match the reset + copy buttons in the transport row */
  font-size: 0.84rem;
  color: var(--muted);
  text-decoration: none;
  border: 1px solid var(--panel-line);
  border-radius: 999px;
  padding: 0.45rem 1rem;
  background: var(--btn-bg);
  white-space: nowrap;
  transition: color 0.2s, background 0.2s, border-color 0.2s;
}
.kofi-link svg { width: 18px; height: 18px; flex: none; }
.kofi-link:hover, .kofi-link:focus-visible {
  color: var(--text);
  background: var(--btn-bg-hover);
  border-color: rgba(var(--accent-rgb),0.5);
}
.kofi-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* --- Sliders --- */
input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 4px;
  border-radius: 3px;
  background: var(--track);
  outline: none;
  cursor: pointer;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 15px; height: 15px; border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}
input[type="range"]::-moz-range-thumb {
  width: 15px; height: 15px; border: none; border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.5);
}
.tile-slider { accent-color: rgb(var(--group)); }
/* Labeled control rows: a muted speaker glyph marks volume, L/R endcaps mark
   pan. Both rows share the same 3-column grid so the tracks align, and each
   row is tall enough to contain its own thumb, so the knobs can't collide.
   The pan row is always laid out — just faded + disabled while the sound is
   silent — so every card looks the same and never reflows on activation. */
.tile-controls { width: 100%; display: flex; flex-direction: column; gap: 0.45rem; }
.ctl-row { display: grid; grid-template-columns: 13px 1fr 13px; gap: 5px; align-items: center; min-height: 15px; }
.ctl-cap {
  font-family: var(--mono);
  font-size: 0.55rem;
  line-height: 1;
  color: var(--faint);
  text-align: center;
  user-select: none;
  -webkit-user-select: none;
}
.ctl-vol svg { width: 12px; height: 12px; display: block; margin: 0 auto; }
.tile-pan {
  height: 2px;
  accent-color: rgb(var(--group));
}
.tile-pan::-webkit-slider-thumb { width: 10px; height: 10px; }
.tile-pan::-moz-range-thumb { width: 10px; height: 10px; }
.tile-pan:disabled { cursor: default; }
.pan-row { opacity: 0.35; transition: opacity 0.25s; }
.tile.active .pan-row { opacity: 0.9; }
input[type="range"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* --- Backdrop controls (inside the Backdrop popover) --- */
.backdrop-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem 1rem;
  align-items: center;
}
.bd-tabs { display: flex; gap: 0.3rem; flex-wrap: wrap; }
.bd-tab {
  font-family: var(--mono);
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  color: var(--muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 9px;
  padding: 0.42rem 0.85rem;
  cursor: pointer;
  transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.bd-tab:hover { color: var(--text); }
.bd-tab[aria-pressed="true"] {
  color: var(--ink);
  background: var(--accent);
  border-color: var(--accent);
  font-weight: 600;
}

.bd-toggles { display: flex; gap: 0.4rem; }
.bd-toggle[hidden] { display: none; } /* hidden must beat the flex display */
.bd-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--panel-line);
  border-radius: 9px;
  padding: 0.4rem 0.7rem;
  cursor: pointer;
  user-select: none;
  transition: color 0.15s, border-color 0.15s;
}
.bd-toggle input { position: absolute; opacity: 0; pointer-events: none; }
.bd-toggle .dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--faint);
  transition: background 0.15s, box-shadow 0.15s;
}
.bd-toggle[data-on="true"] { color: var(--text); border-color: rgba(var(--accent-rgb),0.5); }
.bd-toggle[data-on="true"] .dot { background: var(--accent); box-shadow: 0 0 10px 1px rgba(var(--accent-rgb),0.7); }

.preset-row, .timer-row {
  display: flex; flex-wrap: wrap; gap: 0.5rem;
}

/* Pill buttons (presets, timer, copy) */
.preset-btn, .timer-btn, .copy-link {
  font-family: var(--sans);
  background: var(--btn-bg);
  color: var(--muted);
  border: 1px solid var(--panel-line);
  border-radius: 999px;
  padding: 0.45rem 1rem;
  cursor: pointer;
  font-size: 0.84rem;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}
.preset-btn:hover, .timer-btn:hover, .copy-link:hover {
  color: var(--text);
  background: var(--btn-bg-hover);
}
.timer-btn.active {
  background: var(--accent);
  color: var(--ink);
  border-color: var(--accent);
  font-weight: 600;
}
/* "Surprise me" chip — an action, not a scene: accent-tinted at rest, and
   filled like an active timer pill on hover. */
.preset-btn.surprise {
  color: var(--accent);
  border-color: rgba(var(--accent-rgb),0.45);
  background: rgba(var(--accent-rgb),0.08);
}
.preset-btn.surprise:hover {
  color: var(--ink);
  background: var(--accent);
  border-color: var(--accent);
}
/* Built-in presets: a grid of two-line cards (name + one-line description)
   below the Surprise/saved-scenes row. The drawer panel's own max-height and
   overflow-y (see .drawer-panel) provide the scrolling when it outgrows. */
.preset-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.45rem;
}
/* Each grid cell holds the card button plus its favorite star overlaid on the
   corner (a button can't nest a button). */
.preset-cell { position: relative; display: grid; }
.preset-btn.preset-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
  text-align: left;
  border-radius: 12px;
  padding: 0.4rem 2rem 0.4rem 0.7rem; /* right side clears the star */
  /* Long-press (un)favorites a card, so its text must not select or raise
     the iOS callout while the finger holds. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
.preset-card .preset-desc {
  font-size: 0.7rem;
  color: var(--faint);
  transition: color 0.2s;
}
.preset-card:hover .preset-desc { color: var(--muted); }
/* Favorite star: quiet in the card's corner until hovered or set. The card
   itself is the big touch target (long-press), so the star can stay small
   while still clearing ~28px of hit area. */
.preset-fav {
  position: absolute;
  top: 0.1rem;
  right: 0.1rem;
  width: 1.75rem;
  height: 1.75rem;
  display: grid;
  place-items: center;
  background: none;
  border: none;
  border-radius: 50%;
  color: var(--faint);
  font-size: 0.95rem;
  line-height: 1;
  cursor: pointer;
  transition: color 0.2s;
}
.preset-fav:hover { color: var(--text); }
.preset-fav.faved { color: var(--accent); }
.preset-btn:focus-visible, .timer-btn:focus-visible, .copy-link:focus-visible,
.bd-tab:focus-visible, .play-toggle:focus-visible, .scene-del:focus-visible,
.scene-save-confirm:focus-visible, .preset-fav:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.bd-toggle:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }

/* User-saved scenes: the same pill split into an apply half and a small ×
   delete half. Dashed borders keep them subtly distinct from built-ins. */
.user-scenes { display: contents; }
.user-scene { display: inline-flex; }
.user-scene .preset-btn, .scene-save-btn, .scene-save input { border-style: dashed; }
.user-scene .preset-btn {
  border-radius: 999px 0 0 999px;
  border-right: none;
}
.scene-del {
  font-family: var(--sans);
  background: var(--btn-bg);
  color: var(--muted);
  border: 1px dashed var(--panel-line);
  border-radius: 0 999px 999px 0;
  padding: 0.45rem 0.75rem 0.45rem 0.55rem;
  cursor: pointer;
  font-size: 0.84rem;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}
.scene-del:hover { color: var(--text); background: var(--btn-bg-hover); }
/* Armed state: first click tints the ×; only the second click deletes. */
.scene-del.confirm {
  color: var(--danger);
  border-color: rgba(var(--danger-rgb),0.55);
  background: rgba(var(--danger-rgb),0.12);
}

/* "+ Save scene" chip and the inline name form it swaps to */
.scene-save-btn:disabled { opacity: 0.45; cursor: default; }
.scene-save-btn:disabled:hover { color: var(--muted); background: var(--btn-bg); }
.scene-save { display: inline-flex; }
.scene-save[hidden] { display: none; } /* display beats the UA [hidden] rule otherwise */
.scene-save input {
  font-family: var(--sans);
  font-size: 0.84rem;
  background: var(--btn-bg);
  color: var(--text);
  border: 1px dashed var(--panel-line);
  border-right: none;
  border-radius: 999px 0 0 999px;
  padding: 0.45rem 0.8rem;
  width: 8.5rem;
}
.scene-save input:focus { outline: none; border-color: rgba(var(--accent-rgb),0.5); }
.scene-save input::placeholder { color: var(--faint); }
.scene-save-confirm {
  font-family: var(--sans);
  background: rgba(var(--accent-rgb),0.14);
  color: var(--accent);
  border: 1px solid rgba(var(--accent-rgb),0.4);
  border-radius: 0 999px 999px 0;
  padding: 0.45rem 0.9rem;
  cursor: pointer;
  font-size: 0.84rem;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}
.scene-save-confirm:hover { background: rgba(var(--accent-rgb),0.24); }

/* --- Console: the only always-visible chrome (fixed glass bar) ---
   A control row that folds a drawer open above it. The drawer is part of the
   same surface, so opening it just makes the bar taller — no floating card. */
.console {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border-top: 1px solid var(--panel-line);
  backdrop-filter: blur(20px) saturate(1.3);
  -webkit-backdrop-filter: blur(20px) saturate(1.3);
}
/* One flat row: a single line while everything fits (transport left, drawer
   triggers centered, links right); the stack breakpoint below moves the
   triggers onto their own top line. --console-h (set in main.js) keeps the
   grid's bottom padding matched to the row's real height either way. */
.console-row {
  display: flex;
  align-items: center;
  gap: 0.5rem 0.9rem;
  min-height: var(--bar-h);
  padding: 0.55rem clamp(0.6rem, 3vw, 1.5rem);
  padding-bottom: calc(0.55rem + env(safe-area-inset-bottom, 0px));
}
/* Fold-out drawer: animates height 0 -> content via the grid-rows trick */
.console-drawer {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.28s ease;
}
.console.open .console-drawer { grid-template-rows: 1fr; }
.drawer-inner { overflow: hidden; min-height: 0; }
.drawer-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.55rem;
  min-height: 98px;          /* all three open to the same bar height */
  padding: 0.7rem clamp(0.6rem, 3vw, 1.5rem) 0.8rem;
  max-height: 52vh;
  overflow-y: auto;
  overscroll-behavior: contain; /* panel scroll must not chain into the page */
}
.drawer-panel[hidden] { display: none; }
/* The Scenes panel is the one panel that can outgrow its max-height, and a
   centered flex container clips overflowing content at the top where no
   scrollbar can reach it. Anchor it to the top instead; the short panels
   (Backdrop / Timer / Mix) keep the centered look. */
.drawer-panel[data-panel="scenes"] { justify-content: flex-start; }

.play-toggle {
  flex: none;
  width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center; padding: 0;
  font-size: 1rem;
  background: var(--accent);
  color: var(--ink);
  border: none;
  cursor: pointer;
  box-shadow: 0 4px 18px -6px rgba(var(--accent-rgb),0.8);
  transition: transform 0.15s;
}
.play-toggle:hover { transform: scale(1.05); }

.master { display: flex; align-items: center; gap: 0.55rem; flex: none; }
.master input[type="range"] { width: 104px; }

/* Reset: a compact circular icon button, sits next to the volume control */
.reset-btn {
  flex: none;
  width: 40px; height: 40px;
  display: grid; place-items: center; padding: 0;
  color: var(--muted);
  background: var(--btn-bg);
  border: 1px solid var(--panel-line);
  border-radius: 50%;
  cursor: pointer;
  transition: background 0.18s, border-color 0.18s, color 0.18s, opacity 0.18s;
}
.reset-btn svg { width: 18px; height: 18px; }
.reset-btn:not([disabled]):hover { color: var(--text); background: var(--btn-bg-hover); }
.reset-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.reset-btn[disabled] { opacity: 0.35; cursor: default; }

/* Scenes / Backdrop / Timer drawer triggers: centered, and on the single-line
   layout they absorb the free width between the transport and the links. */
.console-actions {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 0.4rem;
  flex: 1 1 auto; min-width: 0;
}
.console-btn {
  display: inline-flex; align-items: center; gap: 0.35rem;
  font-family: var(--sans); font-size: 0.84rem;
  color: var(--text);
  background: var(--btn-bg);
  border: 1px solid var(--panel-line);
  border-radius: 999px;
  padding: 0.5rem 0.95rem;
  cursor: pointer; white-space: nowrap;
  transition: background 0.18s, border-color 0.18s, color 0.18s;
}
.console-btn:hover { background: var(--btn-bg-hover); }
.console-btn[aria-expanded="true"] {
  border-color: rgba(var(--accent-rgb),0.6);
  background: rgba(var(--accent-rgb),0.12);
}
/* Crisp px-sized triangle (the ▴ glyph renders tiny at any font-size) */
.console-btn .caret {
  width: 0; height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-bottom: 6px solid var(--muted); /* points up when closed */
  transition: transform 0.18s;
}
.console-btn[aria-expanded="true"] .caret { transform: rotate(180deg); }
.console-btn.running {
  border-color: rgba(var(--accent-rgb),0.6);
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.copy-link {
  flex: none; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 0.45rem;
  height: 40px; /* match the reset button (and Ko-fi link) in the transport row */
  color: var(--muted);
}
.copy-link svg { width: 18px; height: 18px; flex: none; }
/* Success flash: tint the button so the feedback also reads when it's an
   icon-only button on narrow screens (where the label text is hidden). */
.copy-link.copied {
  color: var(--accent);
  border-color: rgba(var(--accent-rgb),0.6);
  background: rgba(var(--accent-rgb),0.12);
}

.drawer-panel .section-label { display: block; }
/* Fade picker (fade out / fade in): small-caps label + pill row on one line */
.timer-fade { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem 0.7rem; }
/* Pomodoro rows (Focus / Break / long-break toggle) stack like the panel;
   flex-start keeps the toggle from stretching. hidden must beat the flex
   display (same trick as .bd-toggle[hidden]) — the duration row and the
   pomodoro rows swap on the mode tabs. */
.pomodoro-rows { display: flex; flex-direction: column; align-items: flex-start; gap: 0.7rem; }
.pomodoro-rows[hidden], .timer-row[hidden] { display: none; }
/* Mix panel rows (Liveliness / Space / Warmth): same label + pills shape as
   the fade picker; a fixed label width lines the three rows up. */
.mix-row { display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem 0.7rem; }
.mix-row > .section-label { min-width: 84px; }
/* Warmth: a small tone slider with tiny end labels, like the pan L/R caps.
   (input[type="range"] sets width:100%; the doubled class outranks it.) */
input[type="range"].warmth-slider { width: 132px; height: 3px; accent-color: var(--accent); }
.warmth-slider::-webkit-slider-thumb { width: 12px; height: 12px; }
.warmth-slider::-moz-range-thumb { width: 12px; height: 12px; }
/* Tones: tiny listening hint under the band/mode rows */
.mix-note { color: var(--muted); font-size: 0.72rem; margin: -0.1rem 0 0; }
.timer-remaining {
  color: var(--accent);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.85rem;
}

/* Stats panel: all-time listening totals (see js/stats.js), rendered as
   label + value rows in the mix-row shape. */
.stats-body { display: flex; flex-direction: column; gap: 0.45rem; }
.stats-row { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.3rem 0.7rem; }
.stats-row > .section-label { min-width: 84px; }
.stats-value {
  font-size: 0.88rem;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
/* Reset chip; the armed .confirm state matches the scene-delete tint. */
.stats-reset {
  align-self: flex-start;
  font-family: var(--sans);
  font-size: 0.8rem;
  color: var(--muted);
  background: var(--btn-bg);
  border: 1px solid var(--panel-line);
  border-radius: 999px;
  padding: 0.4rem 0.85rem;
  cursor: pointer;
  transition: background 0.2s, border-color 0.2s, color 0.2s, opacity 0.2s;
}
.stats-reset:not([disabled]):hover { color: var(--text); background: var(--btn-bg-hover); }
.stats-reset:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.stats-reset[disabled] { opacity: 0.45; cursor: default; }
.stats-reset.confirm {
  color: var(--danger);
  border-color: rgba(var(--danger-rgb),0.55);
  background: rgba(var(--danger-rgb),0.12);
}

/* Stack breakpoint: the single line no longer fits, so the drawer triggers
   move onto their own top line (right under the panel they fold open) and the
   transport controls line up centered beneath them. (Raised from 950px when
   the Mix tab became the fourth trigger, and again for Stats as the fifth.) */
@media (max-width: 1120px) {
  :root { --bar-h: 112px; }
  .console-row { flex-wrap: wrap; justify-content: center; gap: 0.5rem 0.7rem; }
  .console-actions { order: -1; flex-basis: 100%; }
}

/* Sheet treatment: on a narrow screen an open drawer behaves like a bottom
   sheet — the panel may take the full height above the console row (the page
   behind locks whenever the panel overflows, which on a sheet it usually
   does). max-height (not height) keeps the short panels content-sized. */
@media (max-width: 640px) {
  .drawer-panel {
    max-height: calc(100vh - var(--console-h, var(--bar-h)));
    max-height: calc(100dvh - var(--console-h, var(--bar-h)));
  }
}

/* Narrow viewports: collapse the copy + coffee links to icon-only buttons and
   drop the volume label so the transport controls stay on a single line. */
@media (max-width: 620px) {
  .master .section-label { display: none; }
  .master input[type="range"] { width: 84px; }
  .copy-text, .kofi-text { display: none; }
  /* Square them off so border-radius:999px renders a true circle, matching the
     reset button (they're 40px tall from the base rule). */
  .copy-link, .kofi-link { gap: 0; width: 40px; padding: 0; justify-content: center; }
  .console-btn { padding: 0.5rem 0.8rem; font-size: 0.82rem; }
  /* Phone width: the five drawer triggers no longer fit on one line. Instead
     of wrapping into a crowded two-row block, keep them on a single line that
     scrolls sideways — a half-visible pill at the edge is the affordance. The
     auto margins on the ends center the row while it still fits and collapse
     to zero once it overflows (justify-content: center would clip the first
     pill unreachably past the left edge of a scroll container). */
  .console-actions {
    flex-wrap: nowrap;
    justify-content: flex-start;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    padding: 3px 0; /* keep focus outlines inside the scroll clip */
  }
  .console-actions::-webkit-scrollbar { display: none; }
  .console-btn:first-child { margin-left: auto; }
  .console-btn:last-child { margin-right: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .tile, .bd-tab, .preset-btn, .timer-btn, .copy-link, .play-toggle,
  .console-btn, .caret, .group-title, .gt-mute, .sound-group .group-grid,
  .console-drawer, #bg-flash, .kofi-link, .kofi-text, .pan-row, .scene-del,
  .scene-save-confirm, .preset-fav { transition: none; }
}
