/* ============================================================================
   Granite Demos — shared base
   Design tokens (Carbon / IBM, from Figma) + global resets shared by every
   demo. Import this FIRST from a demo's stylesheet, then layer demo-specific
   styles on top so individual demos can drift without forking the tokens.
   ========================================================================== */

:root {
  /* --- Carbon / IBM design tokens (from Figma get_variable_defs) --- */
  --white: #ffffff;
  --neutral-white: #ffffff;
  --black: #000000;
  --cool-gray-10: #f2f4f8;
  --cool-gray-20: #dde1e6;
  --cool-gray-50: #878d96;
  --cool-gray-70: #4d5358;
  --cool-gray-80: #343a3f;
  --cool-gray-100: #121619;

  --text-primary: #161616;
  --text-on-color: #ffffff;
  --text-helper: #6f6f6f;
  --text-placeholder: #a8a8a8;
  --text-disabled: rgba(22, 22, 22, 0.25);
  --text-on-color-disabled: #8d8d8d;
  --content-regular: #252525;
  --content-inverse: #ffffff;

  --icon-primary: #161616;
  --icon-secondary: #525252;
  --icon-on-color: #ffffff;
  --icon-disabled: rgba(22, 22, 22, 0.25);

  --border-subtle: #c6c6c6;
  --border-subtle-01: #c6c6c6;
  --layer-selected-01: #e0e0e0;

  --blue-10: #edf5ff;
  --blue-20: #d0e2ff;
  --blue-30: #a6c8ff;
  --blue-40: #78a9ff;
  --blue-50: #4589ff;
  --blue-60: #0f62fe;

  --cool-gray-30: #c1c7cd;
  --cool-gray-60: #697077;
  --cool-gray-90: #21272a;
  --progress-track: #e5e7eb;
  --text-secondary: #525252;
  --support-success: #24a148;
  --green-10: #defbe6;
  --green-20: #a7f0ba;
  --green-30: #42be65;

  --tag-color: #121619;
  --tag-background: #dde1e6;
  /* Carbon green tag (green-20 fill / green-70 text) */
  --tag-color-green: #0e6027;
  --tag-background-green: #a7f0ba;
  /* Carbon orange operational tag (Figma 1083:80862) */
  --tag-color-orange: #8a3800;
  --tag-background-orange: #ffd9be;
  --tag-border-orange: #ff832b;

  /* Carbon categorical chart colors — used by the logo mark */
  --chart-01: #6929c4;
  --chart-04: #9f1853;
  --chart-05: #fa4d56;
  --chart-12: #012749;
  --chart-14: #a56eff;

  --spacing-06: 24px;
  --spacing-08: 40px;

  /* --- Hugging Face chrome (dark header) palette --- */
  --hf-bar-top: #101828;
  --hf-bar-bottom: #0b0f19;
  --hf-border: #141c2e;
  --hf-surface: #0b0f19;
  --hf-surface-2: #101828;
  --hf-text: #e5e7eb;
  --hf-text-muted: #99a1af;
  --hf-text-soft: #d1d5dc;
  --hf-divider: #4a5565;
  --hf-blue: #2b7fff;
  --hf-green: #00bc7d;
  --hf-avatar-dot: #f59e0b;

  /* Page shell */
  --shell-bg: #131313;

  /* Typography */
  --font-sans: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Sticky-note highlighter (HL) palette */
  --hl-yellow: #f8f059;
  --hl-orange: #ff5900;
  --hl-vermillion: #fe3021;
  --hl-green: #6cff8f;
  --hl-blue: #39efff;
}

* { box-sizing: border-box; }

/* Thin, borderless scrollbar across all demos. */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; border: none; }
::-webkit-scrollbar-thumb { background: var(--cool-gray-30, #c1c7cd); border-radius: 100px; }
::-webkit-scrollbar-thumb:hover { background: var(--cool-gray-50, #878d96); }
* { scrollbar-width: thin; scrollbar-color: var(--cool-gray-30, #c1c7cd) transparent; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: hidden;
}

body {
  font-family: var(--font-sans);
  background: var(--shell-bg);
  color: var(--text-primary);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { display: block; }
button { font-family: inherit; cursor: pointer; }

/* ============================================================================
   Grid overlay (shared across demos)
   Press "g" to toggle a Carbon 16-column grid overlay across the viewport.
   The overlay element is injected by shared/shell.js and driven by the
   .grid-on class on <body>. (No button — keyboard-only.)
   ========================================================================== */
/* Carbon grid overlay — grid tokens ported verbatim from the IBM Research
   Website Design repo (src/styles/globals.scss + GridOverlay.module.scss).
   columns 4 → 8 → 16; padding 1rem → 2rem → 2rem → 2.5rem; container caps at
   99rem (1584px) and centers only at ≥99rem. Blue-60 tint with 2px accent
   bars. Hidden until <body> has .grid-on. */
:root {
  --grid-columns: 4;
  --grid-gap: 2rem;
  --grid-padding: 1rem;
}
@media (min-width: 42rem) {
  :root { --grid-columns: 8; --grid-padding: 2rem; }
}
@media (min-width: 66rem) {
  :root { --grid-columns: 16; }
}
@media (min-width: 99rem) {
  :root { --grid-padding: 2.5rem; }
}

.grid-overlay {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: none;
  pointer-events: none;
  overflow: hidden;
}
body.grid-on .grid-overlay { display: block; }
.grid-overlay__inner {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), minmax(0, 1fr));
  column-gap: var(--grid-gap);
  max-width: 99rem;
  height: 100%;
  margin: 0 auto;
  padding: 0 var(--grid-padding);
}
.grid-overlay__col { height: 100%; position: relative; }
.grid-overlay__col-inner {
  height: 100%;
  position: relative;
  background: rgba(15, 98, 254, 0.1);
  border-left: 1px solid rgba(15, 98, 254, 0.3);
  border-right: 1px solid rgba(15, 98, 254, 0.3);
}
.grid-overlay__col-inner::before,
.grid-overlay__col-inner::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 2px;
  background: rgba(15, 98, 254, 0.5);
}
.grid-overlay__col-inner::before { top: 0; }
.grid-overlay__col-inner::after { bottom: 0; }

/* Hide columns beyond the active count (reference GridOverlay.module.scss). */
@media (max-width: 41.99rem) {
  .grid-overlay__col:nth-child(n + 5) { display: none; }
}
@media (min-width: 42rem) and (max-width: 65.99rem) {
  .grid-overlay__col:nth-child(n + 9) { display: none; }
}

/* ============================================================================
   Sticky-note comments (shared across demos)
   Press "s" to drop a draggable sticky note. Frosted-white, square (1:1),
   dragged by the whole card. Each note has a type pill (Design/Dev/Copy), a
   done checkmark, delete, author + date, and persists per-demo in
   localStorage. Markup is built by shared/shell.js.
   ========================================================================== */

/* Layer holding all notes: full-viewport, click-through except on the notes. */
.sticky-layer {
  position: fixed;
  inset: 0;
  z-index: 40;
  pointer-events: none;
}
/* Hidden state: "s" toggles all notes out of view (kept in the DOM/storage). */
body.notes-hidden .sticky-layer { display: none; }
/* Placement mode: the whole page shows the pin cursor; the next click
   drops a note there. */
body.notes-placing,
body.notes-placing * { cursor: url("assets/pin-cursor.svg") 2 30, crosshair !important; }

/* A single note: small 1:1 square, grabbable anywhere. Plain lavender frosted
   glass. */
.sticky {
  position: absolute;
  width: 148px;
  aspect-ratio: 1 / 1;
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px;
  border-radius: 16px;
  border: 1px solid rgba(18, 22, 25, 0.12);
  background: #ded7fb;
  box-shadow: 0 1px 1px rgba(0,0,0,0.04), 0 2px 5px rgba(0,0,0,0.06), 0 6px 14px rgba(0,0,0,0.05);
  color: var(--cool-gray-100);
  font-size: 12px;
  cursor: grab;
  transform: rotate(1.5deg);
  transition: transform 250ms ease, box-shadow 250ms ease;
}
.sticky:hover {
  transform: translateY(-3px) rotate(-2.5deg);
  box-shadow: 0 2px 2px rgba(0,0,0,0.05), 0 4px 10px rgba(0,0,0,0.08), 0 12px 22px rgba(0,0,0,0.07);
}
.sticky.is-dragging { cursor: grabbing; transform: rotate(-2.5deg); }
.sticky.is-done { opacity: 0.55; }
@media (prefers-reduced-motion: reduce) {
  .sticky { transition: none; }
  .sticky:hover { transform: rotate(1.5deg); box-shadow: 0 1px 1px rgba(0,0,0,0.04), 0 2px 5px rgba(0,0,0,0.06), 0 6px 14px rgba(0,0,0,0.05); }
}

/* Header row: type pills on the left, actions on the right. */
.sticky__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.sticky__actions { display: flex; gap: 2px; flex-shrink: 0; margin-left: auto; }
.sticky__btn {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 0;
  border-radius: 5px;
  background: rgba(18, 22, 25, 0.08);
  color: var(--cool-gray-100);
  cursor: pointer;
}
.sticky__btn:hover { background: rgba(18, 22, 25, 0.16); }
.sticky__btn svg { width: 12px; height: 12px; display: block; }
.sticky__btn.is-active { background: var(--cool-gray-100); color: var(--white); }

/* Type pills (Design=paint-brush, Dev=code, Copy=text) — single-select.
   Hidden at rest so the small note stays uncluttered; revealed on hover. */
.sticky__pills { display: none; gap: 2px; }
.sticky:hover .sticky__pills { display: flex; }
.sticky__pill {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  padding: 0;
  border: 1px solid rgba(18, 22, 25, 0.35);
  border-radius: 5px;
  background: transparent;
  color: var(--cool-gray-100);
  cursor: pointer;
}
.sticky__pill svg { width: 12px; height: 12px; display: block; }
.sticky__pill.is-selected {
  background: var(--cool-gray-100);
  color: var(--white);
  border-color: var(--cool-gray-100);
}

/* Editable body text — fills the square. */
.sticky__text {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto; /* scroll long comments within the small note */
  border: 0;
  background: transparent;
  resize: none;
  font-family: inherit;
  font-size: 12px;
  line-height: 1.35;
  color: var(--cool-gray-100);
  outline: none;
}
.sticky.is-done .sticky__text { text-decoration: line-through; }
.sticky__text::placeholder { color: rgba(18, 22, 25, 0.45); }

/* Footer: author + date. */
.sticky__foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  font-size: 11px;
  color: rgba(18, 22, 25, 0.7);
  white-space: nowrap;
}
/* Author matches the date (no bold, same muted color as .sticky__foot). */

/* ============================================================================
   Shared component styles — used identically by every demo.
   Each demo's stylesheet imports this file first, then layers its own
   demo-specific overrides on top.

   TOOLTIP NOTE: The caret mask uses a relative asset path. Each demo must
   declare --tooltip-caret-url in its own :root, e.g.:
     --tooltip-caret-url: url("assets/tooltip-caret.svg");
   ========================================================================== */

/* Full-height flex column so the footer sits at the bottom of the viewport. */
.app {
  height: 100vh;
  min-height: 420px;
  display: flex;
  flex-direction: column;
  background: var(--shell-bg);
  overflow: hidden;
}

/* ============================================================================
   Hugging Face header bar
   ========================================================================== */
.hf-bar {
  height: 47px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  background: linear-gradient(180deg, var(--hf-bar-top), var(--hf-bar-bottom));
  border-bottom: 1px solid var(--hf-border);
}

.hf-bar__left {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  overflow: hidden;
}

.hf-breadcrumb {
  display: flex;
  align-items: center;
  gap: 4px;
}
.hf-breadcrumb__spaces {
  display: flex;
  align-items: center;
  gap: 4px;
  font-weight: 600;
  font-size: 18px;
  line-height: 22.5px;
  color: var(--hf-text);
}
.hf-breadcrumb__spaces img { width: 20px; height: 18px; }

.hf-sep {
  width: 1px;
  height: 18px;
  background: var(--hf-divider);
  margin: 0 4px;
}

.hf-org {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 18px;
}
.hf-org__badge {
  width: 14px;
  height: 14px;
  border-radius: 4px;
  background: #374151;
  display: grid;
  place-items: center;
  overflow: hidden;
}
.hf-org__badge img { width: 12px; height: 12px; }
.hf-org__name { color: var(--hf-text-muted); }
.hf-org__slash { color: var(--hf-text-soft); padding: 0 2px; }

.hf-repo {
  display: flex;
  align-items: center;
  gap: 4px;
}
.hf-repo__name {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 17px;
  line-height: 21px;
  color: var(--hf-text);
  white-space: nowrap;
}
.hf-repo__ext { width: 12px; height: 12px; opacity: 0.8; }

/* Like counter (split button) */
.hf-like {
  display: flex;
  align-items: center;
  height: 26px;
  margin: 0 8px;
  background: var(--hf-surface);
  border: 1px solid var(--hf-border);
  border-radius: 8px;
  overflow: hidden;
}
.hf-like__btn {
  display: flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: 0;
  padding: 2px 8px;
  color: var(--hf-text-muted);
  font-size: 14px;
}
.hf-like__btn img { width: 14px; height: 14px; }
.hf-like__count {
  border-left: 1px solid var(--hf-border);
  padding: 2px 8px;
  color: var(--hf-text-muted);
  font-size: 14px;
}

.hf-pill {
  display: flex;
  align-items: center;
  gap: 4px;
  background: var(--hf-surface-2);
  border: 1px solid var(--hf-border);
  border-radius: 8px;
  padding: 3px 9px;
  font-size: 14px;
  white-space: nowrap;
}
.hf-pill img { width: 14px; height: 14px; }
.hf-pill--agents { color: var(--hf-blue); }

.hf-status {
  display: flex;
  align-items: center;
  height: 22px;
  margin: 0 4px;
  padding: 4px 8px;
  background: var(--hf-surface-2);
  border: 1px solid var(--hf-border);
  border-radius: 8px;
  gap: 4px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--hf-green);
  white-space: nowrap;
}
.hf-status__zero {
  font-weight: 700;
  font-style: italic;
  text-transform: uppercase;
  transform: skewX(-6deg);
}

.hf-pro {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 3px 9px;
  border: 1px solid var(--hf-border);
  border-radius: 8px;
  background: linear-gradient(90deg, rgba(246, 51, 154, 0.2), rgba(0, 188, 125, 0.2));
  color: rgba(209, 213, 220, 0.8);
  font-size: 13px;
  white-space: nowrap;
}

.hf-bar__right {
  display: flex;
  align-items: center;
  gap: 8px;
}
.hf-tabs { display: flex; align-items: center; height: 47px; }
.hf-tab {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 47px;
  padding: 0 14px 2px;
  border-bottom: 2px solid transparent;
  color: var(--hf-text-muted);
  font-size: 16px;
  text-decoration: none;
}
.hf-tab img { width: 16px; height: 16px; }
.hf-tab--active {
  border-bottom-color: var(--hf-text-muted);
  color: var(--hf-text-soft);
  font-weight: 600;
}

.hf-avatar {
  position: relative;
  width: 26px;
  height: 27px;
  display: grid;
  place-items: center;
  border: 1px solid var(--hf-border);
  border-radius: 8px;
  background: linear-gradient(180deg, #1e2939, #0b0f19);
}
.hf-avatar img { width: 16px; height: 16px; }
.hf-avatar__dot {
  position: absolute;
  top: 3px;
  left: 15px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--hf-avatar-dot);
}

/* ============================================================================
   Main stage — holds the app card and the floating info panel
   ========================================================================== */
.stage {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 16px 16px 2px;
  position: relative;
  min-height: 0;
}

/* The white application card — fills the full stage height and width. */
.app-card {
  --header-height: 44px;
  position: relative;
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  width: 100%;
  background: var(--cool-gray-10);
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
}

/* Card header: logo + title + action buttons */
.app-header {
  display: flex;
  align-items: center;
  gap: 20px;
  margin: 0;
  height: var(--header-height);
  padding: 0 8px 0 16px;
  background: transparent;
  border-radius: 8px;
  flex-shrink: 0;
}
.app-header__brand {
  display: flex;
  align-items: center;
  gap: 16px;
  flex: 1 0 0;
  min-width: 0;
}
.app-header__logo {
  width: 31px;
  height: auto;
  flex-shrink: 0;
  color: var(--text-primary);
}
.app-header__divider {
  width: 1px;
  height: 24px;
  flex-shrink: 0;
  background: var(--cool-gray-30);
}
.app-header__title {
  font-size: 16px;
  line-height: 20px;
  color: var(--content-regular);
  white-space: nowrap;
}
.app-header__title strong { font-weight: 700; }
.app-header__actions {
  display: flex;
  align-items: center;
  gap: 6px;
}

/* ============================================================================
   Carbon-style pill buttons
   ========================================================================== */
.btn-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 40px;
  padding: 0 12px;
  border: 0;
  border-radius: 20px;
  font-size: 14px;
  line-height: 16px;
}
/* Header action buttons: compact 28px, 8px corners. */
.app-header__actions .btn-pill { height: 28px; border-radius: 20px; }
.app-header__actions #open-upload { border-radius: 20px; }
.btn-pill__icon { width: 16px; height: 16px; }
.btn-pill--secondary {
  background: var(--cool-gray-80);
  color: var(--text-on-color);
}
.btn-pill--secondary:hover { background: var(--blue-60); }
.app-header__actions .btn-pill--primary {
  background: var(--cool-gray-100);
  color: var(--content-inverse);
}
.app-header__actions .btn-pill--primary:hover { background: var(--blue-60); }
.btn-pill--muted {
  background: var(--cool-gray-10);
  color: var(--text-disabled);
}
.btn-pill svg { width: 16px; height: 16px; }

/* ============================================================================
   Tooltips — dark pill + caret, shown below the trigger on hover/focus.
   Each demo must set: :root { --tooltip-caret-url: url("assets/tooltip-caret.svg"); }
   ========================================================================== */
[data-tooltip] { position: relative; --tt-bg: var(--cool-gray-80); }
[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  padding: 6px 10px;
  border-radius: 8px;
  background: var(--tt-bg);
  color: var(--text-on-color);
  font-size: 12px;
  line-height: 12px;
  white-space: nowrap;
  box-shadow: 0 0 20px rgba(0, 0, 0, 0.04);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.12s ease;
  z-index: 30;
}
[data-tooltip]::before {
  content: "";
  position: absolute;
  top: calc(100% + 1px);
  left: 50%;
  width: 13px;
  height: 11.5px;
  transform: translateX(-50%);
  background: var(--tt-bg);
  -webkit-mask: var(--tooltip-caret-url, url("assets/tooltip-caret.svg")) center / 100% 100% no-repeat;
          mask: var(--tooltip-caret-url, url("assets/tooltip-caret.svg")) center / 100% 100% no-repeat;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.12s ease;
  z-index: 31;
}
[data-tooltip]:hover::after,
[data-tooltip]:focus-visible::after,
[data-tooltip]:hover::before,
[data-tooltip]:focus-visible::before { opacity: 1; }

/* ============================================================================
   Workspace — shared structure, dim overlay.
   Demo files set grid-template-columns on .workspace themselves.
   ========================================================================== */
.workspace {
  position: relative;
  flex: 1 1 0;
  min-height: 0;
  overflow: hidden;
  border-radius: 0 0 8px 8px;
  background: var(--cool-gray-10);
  transition: opacity 0.2s ease;
}
.workspace.is-dimmed { pointer-events: none; }
/* Model still downloading — inert the record/upload controls (both entry
   points: the mic panel and the top-right upload button) until
   GraniteEngine reports ready, so users can't trigger a broken transcribe. */
body.is-model-loading #recorder,
body.is-model-loading #open-upload {
  pointer-events: none;
  opacity: 0.6;
}
.workspace.is-dimmed::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 5;
  background: rgba(255, 255, 255, 0.6);
  -webkit-backdrop-filter: blur(12px) saturate(1.2);
          backdrop-filter: blur(12px) saturate(1.2);
  border-radius: inherit;
}

.ws-col {
  display: flex;
  flex-direction: column;
  padding: 0 8px 8px;
  overflow: hidden;
}
.ws-col--left { padding-right: 8px; }

.panel {
  flex: 1 0 0;
  min-height: 0;
  background: var(--white);
  border: 1px solid var(--cool-gray-20);
  border-radius: 12px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.panel--pad { padding: 16px; }

/* ============================================================================
   Drop-stack — fanned file-type cards shown while dragging a file over a zone
   ========================================================================== */
.drop-stack { display: none; }
.drop-card {
  position: absolute;
  left: 50%;
  top: 50%;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--white);
  border: 1px solid var(--cool-gray-20);
}
.drop-card svg { width: 22px; height: 22px; color: var(--text-secondary); }
.drop-card--img {
  z-index: 1;
  transform: translate(-50%, -50%);
  animation: fan-img 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.drop-card--xls {
  transform: translate(-50%, -50%) translateX(-30px) rotate(-16deg);
  animation: fan-xls 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.12s both;
}
.drop-card--pdf {
  transform: translate(-50%, -50%) translateX(30px) rotate(16deg);
  animation: fan-pdf 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.12s both;
}
@keyframes fan-img {
  0%   { transform: translate(-50%, -50%) scale(0.8); opacity: 0; }
  60%  { opacity: 1; }
  100% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
}
@keyframes fan-xls {
  0%   { transform: translate(-50%, -50%) translateX(0) rotate(0deg); opacity: 0; }
  100% { transform: translate(-50%, -50%) translateX(-30px) rotate(-16deg); opacity: 1; }
}
@keyframes fan-pdf {
  0%   { transform: translate(-50%, -50%) translateX(0) rotate(0deg); opacity: 0; }
  100% { transform: translate(-50%, -50%) translateX(30px) rotate(16deg); opacity: 1; }
}
@keyframes sparkle-spin {
  0%   { opacity: 0; transform: scale(0.3) rotate(0deg); }
  15%  { opacity: 1; transform: scale(1) rotate(60deg); }
  100% { opacity: 1; transform: scale(1) rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .drop-card--img, .drop-card--xls, .drop-card--pdf, .drop-sparkle { animation: none; }
  .drop-sparkle { opacity: 0; }
}
/* .drop-sparkle intentionally omitted — uses url("assets/…") which must be
   declared in each demo's own stylesheet so the path resolves correctly. */

/* ============================================================================
   Info panel — dark floating panel (shared structure; graphic section is demo-specific)
   ========================================================================== */
.info-panel {
  position: absolute;
  z-index: 10;
  top: calc(var(--header-height) + 8px);
  right: 8px;
  bottom: 8px;
  left: auto;
  width: 272px;
  max-width: calc(100% - 64px);
  background: var(--black);
  border-radius: 12px;
  display: flex;
  flex-direction: row;
  overflow: hidden;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.4);
  color: var(--text-on-color);
}
.info-panel.is-expanded {
  left: auto;
  right: 8px;
  width: 60%;
  max-width: 60%;
  min-width: 0;
}
.info-panel__main {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.info-panel.is-expanded .info-panel__header,
.info-panel.is-expanded .info-panel__body,
.info-panel.is-expanded .info-panel__footer { padding-left: 20px; }
.info-panel.is-expanded .info-panel__header::after { left: 20px; }
.info-panel__graphic { display: none; }
.info-panel.is-expanded .info-panel__graphic {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  overflow: hidden;
  flex: 1 1 0;
  align-self: stretch;
  height: auto;
  aspect-ratio: unset;
  margin: 12px 0 12px 12px;
  border-radius: 12px;
  background-color: var(--blue-60);
}
.info-panel.is-expanded .info-panel__graphic::after {
  content: "";
  position: absolute;
  inset: -30% 0;
  pointer-events: none;
  transform: translateX(-150%) skewX(-20deg);
  background: linear-gradient(90deg,
    transparent 5%,
    rgba(69, 137, 255, 0.65) 50%,
    transparent 95%);
  animation: shimmer 3s infinite;
}
@keyframes shimmer { to { transform: translateX(150%) skewX(-20deg); } }
@media (prefers-reduced-motion: reduce) {
  .info-panel.is-expanded .info-panel__graphic::after { animation: none; display: none; }
}
.info-panel__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}
.info-panel__header {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding: 20px 20px 24px;
}
.info-panel__header::after {
  content: "";
  position: absolute;
  left: 20px;
  right: 20px;
  bottom: 0;
  height: 1px;
  background: var(--cool-gray-80);
}
.info-panel__title {
  margin: 0;
  font-weight: 400;
  font-size: 20px;
  line-height: 28px;
  color: var(--text-on-color);
}
.info-panel__subtitle {
  margin: 4px 0 0;
  font-size: 16px;
  line-height: 24px;
  color: var(--text-on-color-disabled);
}
.info-panel__icon-btn {
  width: 28px;
  height: 28px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--cool-gray-80);
  background: transparent;
  color: var(--text-on-color);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  cursor: pointer;
}
.info-panel__icon-btn:hover { background: var(--cool-gray-80); border-color: var(--cool-gray-80); }
.info-panel__icon-btn:focus-visible {
  outline: 2px solid var(--focus, #0f62fe);
  outline-offset: 1px;
}
.info-panel__icon-btn:focus:not(:focus-visible) { outline: none; }
.info-panel__icon-btn svg { width: 16px; height: 16px; display: block; }
.info-panel__body {
  flex: 1 0 0;
  min-height: 0;
  padding: 20px;
  overflow: auto;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: 0.16px;
  color: var(--text-on-color);
}
.info-panel__body p { margin: 0 0 20px; }
.info-panel__body p.info-panel__list-title { margin: 0 0 4px; }
.info-panel__body ul {
  margin: 0;
  padding-left: 21px;
  list-style: disc;
}
.info-panel__body li { margin: 0; }
.info-panel.is-expanded .info-panel__body > * { max-width: 504px; }
.info-panel__footer {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: flex-end;
  margin-top: auto;
  padding: 20px 20px 16px;
}

/* ============================================================================
   Carbon read-only tags
   ========================================================================== */
.tag {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 8px;
  border-radius: 12px;
  background: var(--tag-background-orange);
  border: 1px solid var(--tag-border-orange);
  color: var(--tag-color-orange);
  font-size: 14px;
  line-height: 18px;
  white-space: nowrap;
}

/* ============================================================================
   Upload confirmation modal
   ========================================================================== */
.upload-modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 20px;
  overflow-y: auto;
}
.upload-modal.is-open { display: flex; }
.upload-modal__dialog {
  width: 544px;
  max-width: 100%;
  background: var(--cool-gray-100);
  color: var(--text-on-color);
  border-radius: 12px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.4);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
}
.upload-modal__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  padding: 20px 20px 24px;
  border-bottom: 1px solid var(--cool-gray-80);
}
.upload-modal__title {
  margin: 0;
  font-weight: 400;
  font-size: 20px;
  line-height: 28px;
  color: var(--text-on-color);
}
.upload-modal__close {
  width: 24px;
  height: 24px;
  padding: 0;
  border-radius: 50%;
  border: 0.78px solid var(--cool-gray-80);
  background: transparent;
  color: var(--text-on-color);
  display: grid;
  place-items: center;
  flex-shrink: 0;
  cursor: pointer;
}
.upload-modal__close:hover { background: var(--cool-gray-80); }
.upload-modal__close svg { width: 14px; height: 14px; display: block; }
.upload-modal__body {
  padding: 20px;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: 0.16px;
  color: var(--text-on-color);
}
.upload-modal__body p { margin: 0; }
.upload-modal__footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  padding: 20px;
}
.upload-modal__cancel,
.upload-modal__confirm {
  padding: 10px 20px;
  border: 0;
  border-radius: 40px;
  font-size: 14px;
  line-height: 20px;
  color: var(--content-inverse);
  cursor: pointer;
}
.upload-modal__cancel { background: transparent; }
.upload-modal__cancel:hover { background: var(--cool-gray-80); }
.upload-modal__confirm { background: var(--blue-60); }
.upload-modal__confirm:hover { background: var(--blue-70, #0353e9); }

/* ============================================================================
   Responsive — Carbon breakpoints
   sm: 320px  md: 672px  lg: 1056px  xlg: 1312px  max: 1584px
   ========================================================================== */

/* xlg (1312px) — tighten stage padding so the card doesn't feel too wide */
@media (max-width: 1312px) {
  .stage { padding: 12px 12px 2px; }
}

/* lg (1056px) — collapse to single column, make header scrollable */
@media (max-width: 1056px) {
  .stage { padding: 8px 8px 2px; }
  .hf-bar__left { overflow-x: auto; }
  .hf-tabs { overflow-x: auto; }
  .upload-modal__dialog { width: 100%; border-radius: 8px; }
}

/* md (672px) — compact chrome, full-width modal, hide footer links */
@media (max-width: 672px) {
  [data-tooltip]::before,
  [data-tooltip]::after { display: none !important; }
  .hf-bar { padding: 0 12px; height: 44px; gap: 8px; }
  /* Left side scrolls horizontally so breadcrumb never wraps */
  .hf-bar__left { overflow: hidden; flex-shrink: 1; min-width: 0; gap: 4px; }
  .hf-bar__right { flex-shrink: 0; }
  .hf-breadcrumb { white-space: nowrap; flex-wrap: nowrap; }
  .hf-breadcrumb__spaces { font-size: 15px; white-space: nowrap; }
  .hf-org__name,
  .hf-org__slash,
  .hf-repo__name { white-space: nowrap; }
  .hf-repo__name { font-size: 14px; }
  /* Hide lower-priority items to save space */
  .hf-like,
  .hf-pro,
  .hf-pill--agents,
  .hf-status { display: none; }
  /* Tabs: scroll instead of wrap */
  .hf-tabs { overflow-x: auto; white-space: nowrap; }
  .stage { padding: 0; }
  .app-card { border-radius: 0; }
  .footer { display: none; }
  /* Type scale — step headings down one level on mobile */
  .app-header__title { font-size: 14px; }
  .app-header__btn { font-size: 13px; }
  .upload-modal { padding: 12px; }
  .upload-modal__dialog { border-radius: 6px; }
  .upload-modal__header { padding: 16px; }
  .upload-modal__body { padding: 16px; }
  .upload-modal__footer { padding: 12px 16px; }
  .footer { padding: 10px 12px; }
  .footer__links { gap: var(--spacing-06); font-size: 11px; }
}

/* sm (320px) — minimal padding, compact everything */
@media (max-width: 320px) {
  .hf-bar { padding: 0 8px; }
  .hf-status { display: none; }
  .stage { padding: 4px 4px 2px; }
  .footer__links a:not(:first-child):not(:nth-child(2)) { display: none; }
}

/* ============================================================================
   Footer
   ========================================================================== */
.footer {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  background: var(--shell-bg);
}
.footer__content {
  display: flex;
  align-items: center;
  gap: var(--spacing-08);
}
.footer__content > img { width: 16px; height: 16px; }
.footer__links {
  display: flex;
  align-items: center;
  gap: var(--spacing-06);
  font-size: 12px;
  line-height: 16px;
  letter-spacing: 0.32px;
  color: var(--text-on-color);
}
.footer__links a {
  color: inherit;
  text-decoration: none;
}
.footer__links a:hover { text-decoration: underline; }

/* ============================================================================
   Content switcher (footer theme toggle)
   ========================================================================== */
.content-switcher {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--border-subtle-01);
  border-radius: 8px;
  overflow: hidden;
}
.content-switcher__item {
  display: grid;
  place-items: center;
  padding: 6px 16px;
  background: none;
  border: 0;
  border-left: 1px solid var(--border-subtle-01);
  color: var(--white);
}
.content-switcher__item:first-child { border-left: 0; }
.content-switcher__item.is-selected {
  background: var(--layer-selected-01);
  color: var(--cool-gray-100);
}
.content-switcher__item svg { width: 16px; height: 16px; display: block; }
/* ============================================================================
   Granite Demos — Speech prototype
   Demo-specific styles only. Shared tokens, chrome, and components live in
   shared/base.css (imported above).
   ========================================================================== */

:root {
  /* Speech-specific tokens not covered by shared/base.css */
  --cool-gray-40: #a2a9b0;
  --progress-track: #e5e7eb;
  --support-error: #da1e28;

  /* Toggle track colors */
  --container-inverse: #131313;
  --toggle-off: #8d8d8d;

  /* Recording UI accent */
  --rec-accent: var(--blue-60);
  --rec-accent-hover: var(--blue-70, #0043ce);

  /* Asset paths relative to this demo's assets/ folder */
  --tooltip-caret-url: url("assets/tooltip-caret.svg");
}

/* Upload-layout switcher button — bordered icon button in the HF header.
@import url("../../shared/base.css");
/* ============================================================================
   Granite Demos — Speech prototype
   Demo-specific styles only. Shared tokens, chrome, and components live in
   shared/base.css (imported above).
   ========================================================================== */

:root {
  /* Speech-specific tokens not covered by shared/base.css */
  --cool-gray-40: #a2a9b0;
  --progress-track: #e5e7eb;
  --support-error: #da1e28;

  /* Toggle track colors */
  --container-inverse: #131313;
  --toggle-off: #8d8d8d;

  /* Recording UI accent */
  --rec-accent: var(--blue-60);
  --rec-accent-hover: var(--blue-70, #0043ce);

  /* Asset paths relative to this demo's assets/ folder */
  --tooltip-caret-url: url("assets/tooltip-caret.svg");
}

/* Upload-layout switcher button — bordered icon button in the HF header.
   Speech-only: doc-intelligence does not have this button. */
@import url("../../shared/base.css");
/* ============================================================================
   Granite Demos — Speech prototype
   Demo-specific styles only. Shared tokens, chrome, and components live in
   shared/base.css (imported above).
   ========================================================================== */

:root {
  /* Speech-specific tokens not covered by shared/base.css */
  --cool-gray-40: #a2a9b0;
  --progress-track: #e5e7eb;
  --support-error: #da1e28;

  /* Toggle track colors */
  --container-inverse: #131313;
  --toggle-off: #8d8d8d;

  /* Recording UI accent */
  --rec-accent: var(--blue-60);
  --rec-accent-hover: var(--blue-70, #0043ce);

  /* Asset paths relative to this demo's assets/ folder */
  --tooltip-caret-url: url("assets/tooltip-caret.svg");
}

/* Upload-layout switcher button — bordered icon button in the HF header.
   Speech-only: doc-intelligence does not have this button. */
.hf-iconbtn {
  display: grid;
  place-items: center;
  width: 28px;
  height: 27px;
  padding: 0;
  border: 1px solid var(--hf-border);
  border-radius: 8px;
  background: transparent;
  color: var(--hf-text-muted);
  cursor: pointer;
  transition: color 0.12s ease, border-color 0.12s ease, background 0.12s ease;
}
.hf-iconbtn svg { width: 16px; height: 16px; }
.hf-iconbtn:hover { color: var(--hf-text-soft); border-color: var(--hf-text-muted); }
.hf-iconbtn[aria-pressed="true"] {
  color: var(--hf-text-soft);
  border-color: var(--hf-text-soft);
  background: rgba(255, 255, 255, 0.06);
}

/* Icon-only pill button — speech uses cool-gray-30 border */
.btn-pill--icon {
  width: 28px;
  padding: 0;
  background: var(--white);
  border: 1px solid var(--cool-gray-30);
  color: var(--icon-secondary);
}
.btn-pill--icon:hover,
.btn-pill--icon[aria-pressed="true"] { color: var(--icon-primary); }

/* Suppress all focus outlines */
*:focus,
*:focus-visible { outline: none; }


/* Community tab badge: dark pill */
.hf-tab__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 4px;
  background: #1e2939;
  color: #ffffff;
  font-size: 12px;
  font-weight: 600;
  line-height: 1;
  margin-left: 4px;
}
/* Vertical separator in right side */
.hf-sep--v {
  display: block;
  width: 1px;
  height: 18px;
  background: #e5e7eb;
  margin: 0 4px;
  flex-shrink: 0;
}
/* Circular avatar */
.hf-avatar--circle {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: none;
  background: none;
  overflow: hidden;
  padding: 0;
}
.hf-avatar--circle img { width: 22px; height: 22px; border-radius: 50%; }

/* Two-column grid layout for this demo */
.workspace { display: grid; grid-template-columns: 1fr 1fr; }
.ws-col--right { padding-left: 0; }

/* Upload modal: match info panel background */
.upload-modal__dialog { background: var(--black); }

/* Shell: white, card floats inside with stage padding */
.app { background: #000000; }
.app-card { box-shadow: none; border: 1px solid var(--cool-gray-20); }
/* Hide footer (terms/privacy/theme switcher) on speech */
.footer { display: none; }
.stage { padding: 8px; }

.upload-view {
  flex: 1 0 0;
  min-height: 0;
  display: none;
  flex-direction: column;
}
.upload-view--record { display: flex; }

/* Layout 2 — voice recorder. Flow: landing (record-audio entry) →
   recording → review. The dark "screen" (status + waveform + timer) over a
   control row is shown once recording begins; states are driven by
   #recorder[data-rec]. */
.recorder {
  flex: 1 0 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Landing panel — the idle/dropzone state is LIGHT (Figma 1047:54124):
   cool-gray-10 fill with an inset dashed border. It flips to black only once
   recording starts (.is-listening). */
.record-panel {
  position: relative; /* corner-pinned Start over / Transcribe while recording */
  flex: 1 0 0;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 24px;
  background: var(--blue-10);
  border: 1.5px dashed var(--blue-40);
  border-radius: 12px;
  text-align: center;
  overflow: hidden;
  transition: background 0.3s ease, border-color 0.3s ease;
}
/* Drag-over: the dashed border turns blue + a blue-10 wash fills the panel
   (matches doc-intelligence's dropzone dragging state). */
.record-panel.is-dragging {
  border-color: var(--blue-60);
  background: var(--blue-10);
}
/* While dragging, swap the normal content (cluster/mic/text) for the fanned
   drop-cards + sparkles + "Drop audio file" prompt (mirrors doc-intelligence). */
.record-panel.is-dragging .record-visual,
.record-panel.is-dragging .record-panel__text { display: none; }

.record-panel__droptext {
  display: none;
  margin-top: 16px;
  font-size: 16px;
  line-height: 1.2;
  color: var(--text-primary);
}
.record-panel.is-dragging .record-panel__droptext { display: block; }

/* Drop-stack container reveal for dragging over the record panel */
.record-panel.is-dragging .drop-stack {
  display: block;
  position: relative;
  width: 96px;
  height: 56px;
}
.drop-sparkle {
  position: absolute;
  width: 16px;
  height: 16px;
  fill: var(--cool-gray-100);
  opacity: 0;
  overflow: visible;
  animation: sparkle-spin 2s linear infinite;
}
.drop-sparkle--1 { top: -14px;   right: -10px; animation-delay: 0s; }
.drop-sparkle--2 { bottom: -14px; left: 50%; margin-left: -8px; animation-delay: 0.08s; }
.drop-sparkle--3 { top: -14px;   left: -10px;  animation-delay: 0.16s; }
.rec-file-input { display: none; }
/* Recording state: same cool-gray-10 fill, border fades out via border-color
   (keeps the 1.5px dashed structure so border-color transitions back smoothly). */
.record-panel.is-listening { background: var(--cool-gray-10); border-color: transparent; }
/* Left column wrapper keeps the default white card + border + 16px padding
   (base .panel + .panel--pad), so the dashed dropzone sits inside a white
   outer panel — matching doc-intelligence. */
/* Bubble-cluster wrapper — positioning context for the centered mic button. */
.record-visual {
  position: relative;
  display: grid;
  place-items: center;
  margin-bottom: 12px;
  padding: 8px;
}

/* Pulsing voice-bubble cluster (Figma 1037:44730) — a dense diamond of black
   dots. Each dot is radially positioned via inline --x/--y (offset from center),
   --s (diameter), --d (pulse delay). */
.voice-cluster {
  position: relative;
  width: 200px;
  height: 180px;
}
.vdot {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--s, 16px);
  height: var(--s, 16px);
  margin: calc(var(--s, 16px) / -2) 0 0 calc(var(--s, 16px) / -2);
  border-radius: 50%;
  background: var(--cool-gray-100);
  transform: translate(var(--x, 0), var(--y, 0));
  transform-origin: center;
  transition: background-color 0.3s ease;
}
/* Hover: pulse the cluster when hovering the mic button. */
.record-panel:not(.is-listening) .record-visual:has(.record-panel__mic:hover) .vdot {
  animation: vdot-pulse 1.6s ease-in-out infinite;
  animation-delay: var(--d, 0s);
}
/* Recording: dots go dark (cool-gray-100) on the light panel (Figma). */
.record-panel.is-listening .vdot { background: var(--cool-gray-100); }
/* Static by default; only pulses once the mic button is clicked
   (.is-listening added to .record-panel). --d staggers the pulse center-out. */
.record-panel.is-listening .vdot,
.record-panel.is-converting .vdot {
  animation: vdot-pulse 1.6s ease-in-out infinite;
  animation-delay: var(--d, 0s);
}
/* Voice-reactive mode (mic active or synthesized fallback): replace the fixed
   breathe with a live scale driven by --vscale (set per frame by app.js from
   the input level, inherited from .voice-cluster). Louder → the cluster swells. */
.record-panel.is-voice .vdot {
  animation: none;
  transform: translate(var(--x, 0), var(--y, 0)) scale(var(--vscale, 1));
  /* Ease the color into the recording palette (was snapping because this rule
     dropped the base background transition); keep the scale responsive. */
  transition: background-color 0.35s ease, transform 0.08s linear;
}
/* Center-fill dots — hidden normally (the mic covers this space). */
.vdot--center { display: none; }
/* Converting: hide the mic, dot cluster, idle text; show the fanned drop-stack instead. */
.record-panel.is-converting .record-panel__mic { display: none; }
.record-panel.is-converting .voice-cluster { display: none; }
.record-panel.is-converting .record-visual { display: none; }
.record-panel.is-converting .record-panel__text { display: none; }
/* Show the fanned drop-stack during converting (reuse drag-over animation). */
.record-panel.is-converting .drop-stack {
  display: block;
  position: relative;
  width: 96px;
  height: 56px;
  margin-bottom: 32px;
}
.record-panel.is-converting .drop-card--img {
  z-index: 1;
  transform: translate(-50%, -50%);
  animation: fan-img 0.45s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.record-panel.is-converting .drop-card--xls {
  transform: translate(-50%, -50%) translateX(-30px) rotate(-16deg);
  animation: fan-xls 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.12s both;
}
.record-panel.is-converting .drop-card--pdf {
  transform: translate(-50%, -50%) translateX(30px) rotate(16deg);
  animation: fan-pdf 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.12s both;
}
.record-panel.is-converting .drop-sparkle {
  opacity: 0;
  animation: sparkle-spin 2s linear infinite;
}
/* Single breathe per cycle — same shape as the original, punchier: bigger
   scale swing and a faster cycle. */
@keyframes vdot-pulse {
  0%, 100% { transform: translate(var(--x, 0), var(--y, 0)) scale(0.83); opacity: 0.72; }
  45%      { transform: translate(var(--x, 0), var(--y, 0)) scale(1.18); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .vdot { animation: none; }
}

.record-panel__title {
  font-size: 16px;
  font-weight: 500;
  line-height: 1.2;
  color: var(--text-primary);  /* idle: dark on the light panel */
}
.record-panel__hint {
  font-size: 13px;
  line-height: 18px;
  color: var(--text-placeholder);
}
/* Mic button (Figma 1037:44829) — a solid 56px cool-gray-10 circle centered
   over the cluster, masking the center dots. Clicking starts/stops the pulse. */
.record-panel__mic {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 1;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  padding: 0;
  border-radius: 50%;
  /* Idle: white circle, cool-gray-20 border, icon-secondary glyph — matches doc-intx dropzone tile. */
  background: var(--white);
  border: 1px solid var(--cool-gray-20);
  color: var(--icon-secondary);
  cursor: pointer;
  transition: color 0.3s ease, border-color 0.3s ease, transform 0.08s ease;
}
/* Hover: cool-gray-30 border + icon-primary glyph — matches doc-intx. */
.record-panel:not(.is-listening) .record-panel__mic:hover {
  border-color: var(--cool-gray-30);
  color: var(--icon-primary);
}
/* Recording: same as hover state — white bg, cool-gray-30 border, icon-primary glyph. */
.record-panel.is-listening .record-panel__mic {
  background: var(--white);
  border-color: var(--cool-gray-30);
  color: var(--icon-primary);
}
.record-panel__mic:active { transform: translate(-50%, -50%) scale(0.96); }
.record-panel__mic svg { width: 24px; height: 24px; display: block; }
/* Disable the mic while recording — the transport controls drive the state. */
/* Record-again state: mic button back to unselected look + hoverable + clickable. */
.record-panel.is-restarting .record-panel__mic {
  pointer-events: auto;
  background: var(--white);
  border-color: var(--cool-gray-20);
  color: var(--icon-secondary);
}
.record-panel.is-restarting .record-panel__mic:hover {
  border-color: var(--cool-gray-30);
  color: var(--icon-primary);
}
.record-panel.is-restarting .record-panel__mic::before { opacity: 0 !important; }
/* Recording ripple — JS drives --ripple-scale and --ripple-opacity each frame
   so the halo expands in sync with the live mic level. */
.record-panel__mic::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 56px;
  height: 56px;
  z-index: -1;
  border-radius: 50%;
  background: var(--cool-gray-100);
  transform: translate(-50%, -50%) scale(var(--ripple-scale, 1));
  opacity: var(--ripple-opacity, 0);
}
/* Paused: freeze the dot pulse in place. */
.record-panel.is-paused .vdot {
  animation-play-state: paused;
}
@media (prefers-reduced-motion: reduce) {
  .record-panel__mic::before { opacity: 0 !important; }
}
/* Inline "select a file" pill (Figma 1042:47361) — on the dark panel: a
   transparent ghost button with a cool-gray-70 border and on-color text. */
/* "select a file" — blue underlined text link on the light idle panel
   (Figma 1047:54173), matching doc-intelligence's dropzone link. */
.record-panel__select {
  appearance: none;
  vertical-align: baseline;
  height: auto;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--blue-60);
  text-decoration: underline;
  text-underline-offset: 3px;
  white-space: nowrap;
  cursor: pointer;
}
.record-panel__select:hover { color: var(--blue-70, #0043ce); }
.record-panel__select .btn-pill__icon { display: none; }
/* Supported audio formats — mirrors doc-intelligence's .dropzone__formats. */
.record-panel__formats {
  /* 16px to match doc-intelligence's effective title→formats gap (its title +
     formats are direct flex children with gap:12px + the formats' 4px
     margin-top; speech wraps them in .record-panel__text, so set it here). */
  margin-top: 16px;
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 16px;
  letter-spacing: 0.32px;
  color: var(--text-placeholder);
}

/* ---- Recording state (below the dot cluster, Figma 1042:48666) -----------
   The idle text is swapped for recorded time + a bar waveform; Start over /
   Transcribe pin to the panel corners. Toggled by .is-listening. */
/* gap matches the dots→time spacing above (.record-panel gap 12 +
   .record-visual margin-bottom 12 = 24px). */
.record-panel__recording { display: none; flex-direction: column; align-items: center; gap: 24px; width: 100%; overflow: visible; }
.record-panel.is-listening .record-panel__text { display: none; }
.record-panel.is-listening .record-panel__recording { display: flex; }

/* Uploaded-file state (Figma 1369:28430): black panel, Back to upload top-left,
   compact bar waveform centred. No dot cluster, no full rec-wave, no timer. */
.record-panel.is-uploaded {
  background: #000000;
  border-color: transparent;
}
.record-panel.is-uploaded .record-visual { display: none; }
.record-panel.is-uploaded .record-panel__rectime { display: none; }
.record-panel.is-uploaded .record-panel__text { display: none; }
/* Uploaded: hide JS wave, show static SVG waveform full-width. */
.record-panel.is-uploaded .rec-wave { display: none; }
.rec-static-wave-wrap { display: none; }
.record-panel.is-uploaded .rec-static-wave-wrap {
  display: block;
  position: relative;
  width: calc(100% - 48px);
  height: 78px;
  cursor: pointer;
  touch-action: none;
}
.rec-static-wave {
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
/* Dims the not-yet-played portion of the clip; shrinks from the right as
   playback (or a drag/click seek) advances the playhead. */
.rec-static-wave__overlay {
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: 100%;
  background: rgba(0, 0, 0, 0.55);
  pointer-events: none;
}
.rec-static-wave__playhead {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 2px;
  background: var(--white);
  transform: translateX(-1px);
  pointer-events: none;
}
.record-panel.is-uploaded .rec-times { display: none !important; }
.record-panel.is-uploaded .recorder__back {
  display: inline-flex !important;
  background: transparent;
  border: 1px solid var(--cool-gray-80);
  color: var(--white);
}
.record-panel.is-uploaded .recorder__back:hover { background: var(--cool-gray-80); border-color: var(--cool-gray-80); }
/* Stretch recording row to fill panel so waveform ends up vertically centred. */
.record-panel.is-uploaded .record-panel__recording { flex: 1 0 0; justify-content: center; align-items: center; width: 100%; }
.record-panel__filetag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 8px;
  border-radius: 8px;
  background: var(--blue-10);
  color: var(--content-regular, #282828);
  font-size: 12px;
  line-height: 16px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 260px;
}
.record-panel__filetag[hidden] { display: none; }

/* Converting step — a filling progress bar + status, shown while
   .is-converting (used on file upload AND on transcribe). Hides the waveform,
   transport, timer, tag, corner buttons, and back button so only the progress reads.
   The panel flips to white with no border during this state. */
.rec-convert { display: none; flex-direction: column; align-items: stretch; gap: 10px; width: 100%; }
.record-panel.is-converting .rec-convert { display: flex; }
.record-panel.is-converting .record-panel__filetag,
.record-panel.is-converting .record-panel__rectime,
.record-panel.is-converting .rec-wave,
.record-panel.is-converting .rec-transport,
.record-panel.is-converting .record-panel__restart { display: none !important; }
/* White panel, no dashed outline during converting. Keep border-width/style
   intact so removing is-converting doesn't flash the border back. */
.record-panel.is-converting {
  background: var(--white);
  border-color: transparent;
}
/* Hide "Back to upload" during converting. */
.record-panel.is-converting .recorder__back { display: none !important; }
.rec-convert__head {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
/* Spinning sparkle loader — dark on the white panel. */
.rec-convert__spinner {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  fill: var(--cool-gray-100);
  overflow: visible;
}
.record-panel.is-converting .rec-convert__spinner {
  animation: star-loader-spin 1s linear infinite;
}
@keyframes star-loader-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .record-panel.is-converting .rec-convert__spinner { animation: none; }
}
.rec-convert__name {
  font-size: 16px;
  font-weight: 500;
  line-height: 22px;
  color: var(--text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rec-convert__status {
  margin: 0;
  font-size: 14px;
  line-height: 20px;
  color: var(--text-secondary);
}
/* Progress bar — cool-gray-10 track, cool-gray-100 fill. */
.progress__track {
  position: relative;
  height: 8px;
  width: 100%;
  background: var(--cool-gray-10);
  border-radius: 100px;
  overflow: hidden;
}
.progress__bar {
  position: absolute;
  top: 0; left: 0; bottom: 0;
  width: 5%;
  border-radius: 100px;
  background: var(--cool-gray-100);
  overflow: hidden;
}
.progress__bar::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg,
    transparent 0%, transparent 35%,
    rgba(255, 255, 255, 0.75) 50%,
    transparent 65%, transparent 100%);
  background-size: 220% 100%;
  background-repeat: no-repeat;
}
.record-panel.is-converting .progress__bar {
  animation: rec-convert-fill var(--convert-dur, 5s) ease-out forwards;
}
.record-panel.is-converting .progress__bar::after {
  animation: rec-bar-glimmer 2s linear infinite;
}
@keyframes rec-convert-fill { from { width: 5%; } to { width: 100%; } }
@keyframes rec-bar-glimmer { from { background-position: 150% 0; } to { background-position: -50% 0; } }
@media (prefers-reduced-motion: reduce) {
  .record-panel.is-converting .progress__bar { animation: none; width: 100%; }
  .record-panel.is-converting .progress__bar::after { animation: none; }
}

/* Recorded time — 18px on-color, above the waveform. */
.record-panel__rectime {
  font-family: var(--font-mono);
  font-size: 18px;
  line-height: 1.2;
  color: var(--text-primary);  /* dark on the light panel */
  font-variant-numeric: tabular-nums;
}

/* Dotted waveform — a row of columns, each a vertical stack of dots that light
   center-out to the column's level (LED VU meter). Blue playhead near the end. */
.rec-wave {
  position: relative;
  display: flex;
  align-items: center;
  width: calc(100% - 32px); /* match .rec-bar inset: left/right 16px each */
  margin: 0 auto;
  height: 80px;
  overflow: visible; /* allow star to poke above on mobile */
}
.rec-wave__bars {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  height: 100%;
  overflow: hidden; /* clip dots to the bar height */
}
.rec-wave__col {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  height: 100%;
  flex-shrink: 0;
}
.rec-wave__dot {
  width: 4px;
  height: 4px;
  min-width: 4px;
  min-height: 4px;
  aspect-ratio: 1;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--cool-gray-100);  /* dark dots on the light panel */
  opacity: 0;                        /* unlit dots hidden */
  transition: opacity 0.09s ease;
}
.rec-wave__dot.is-lit { opacity: 1; }
/* Columns past the playhead (future) render their lit dots in cool-gray-30. */
.rec-wave__col.is-future .rec-wave__dot.is-lit { background: var(--cool-gray-30); }
.rec-wave__playhead {
  position: absolute;
  top: -12px;               /* a little taller than the tallest wave column */
  bottom: -12px;
  left: 0;                 /* JS drives this via landProgress */
  width: 1px;
  background: var(--cool-gray-100);
}
/* Spinning star handle at the top of the ticker (dropzone sparkle shape).
   Inline SVG child .rec-wave__playhead-star — mask approach replaced so
   Figma capture renders the shape correctly. */
.rec-wave__playhead-star {
  position: absolute;
  top: -16px;
  left: 50%;
  margin-left: -8px;
  width: 16px;
  height: 16px;
  fill: var(--cool-gray-100);
  overflow: visible;
  animation: wave-star-spin 3s linear infinite;
}
@keyframes wave-star-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .rec-wave__playhead-star { animation: none; }
}

/* ---- Recording bottom bar (Figma 1083:79058) --------------------------
   Device tag (left) + restart/trim icons + Stop/Pause pills (right). Shown
   only while actively recording; the uploaded state keeps the transport row. */
.rec-bar { display: none; }
/* Flush to the bottom edge of the panel (Figma): device tag pinned bottom-left,
   controls bottom-right, while the cluster/timer/wave stay centered above.
   Inset 16px from the panel edges. */
.record-panel.is-listening:not(.is-uploaded):not(.is-converting) .rec-bar {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  position: absolute;
  left: 16px;
  right: 16px;
  bottom: 16px;
}
/* Recording state hides the transport row (that's for uploaded playback) and
   the corner Start over. */
.record-panel.is-listening:not(.is-uploaded) .rec-transport { display: none; }
.record-panel.is-listening:not(.is-uploaded) .record-panel__restart { display: none; }
/* Live recording: hide the playhead line (belongs to review state only). */
.record-panel.is-listening:not(.is-uploaded):not(.is-converting) .rec-wave__playhead { display: none; }
/* Uploaded state hides the recording bar. */
.record-panel.is-uploaded .rec-bar { display: none; }

.rec-bar__device {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 8px;
  border: 1px solid var(--cool-gray-20);
  border-radius: 8px;
  font-size: 12px;
  line-height: 16px;
  letter-spacing: -0.12px;
  color: var(--text-secondary);
  white-space: nowrap;
}
.rec-bar__actions { display: flex; align-items: center; gap: 8px; }
/* The 40px icon boxes carry ~10px of dead space on each side of their glyph, so
   icon↔icon glyph spacing runs a full padding wider than icon↔pill. Pull the
   second icon back so restart↔scissor matches the scissor→Stop rhythm. */
.rec-bar__icon + .rec-bar__icon { margin-left: -8px; }
.rec-bar__icon {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--icon-secondary);
  cursor: pointer;
  transition: color 0.12s ease, background 0.12s ease;
}
.rec-bar__icon svg { width: 20px; height: 20px; display: block; }
.rec-bar__icon:hover { color: var(--icon-primary); background: var(--cool-gray-20); }
/* Stop + Pause — dark cool-gray-100 pills with white text/glyph. */
.rec-bar__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 40px;
  padding: 0 12px;
  border: 0;
  border-radius: 20px;
  background: #000000;
  color: var(--text-on-color);
  font-size: 14px;
  line-height: 16px;
  cursor: pointer;
  transition: background 0.12s ease;
}
.rec-bar__btn:hover { background: var(--blue-60); }
.rec-bar__btn svg { width: 16px; height: 16px; display: block; }
/* Pause/play glyph toggle on the live pause button: show pause by default,
   play once paused. Selectors are scoped to .rec-bar__btn so they beat the
   generic `.rec-bar__btn svg` display rule above. */
.rec-bar__btn .rec-bar__play-icon { display: none; }
.rec-bar__btn.is-paused .rec-bar__pause-icon { display: none; }
.rec-bar__btn.is-paused .rec-bar__play-icon { display: block; }

/* Transport controls (below the waveform): skip-back · pause/play · skip-fwd.
   Skip icons are on-color BPMN glyphs; the center toggle is a white circle
   with a dark pause/play glyph. */
/* ---- Review transport (Figma 1083:77569) --------------------------------
   Light-theme playback controls, shown only in the uploaded/review state:
   volume + speed (left) · rewind / play / forward (center) · restart + trim
   (right). Spans the full panel width; the equal-flex sides center the group. */
.rec-transport {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: calc(100% - 32px); /* match .rec-wave width */
  max-width: 100%;
  margin-top: 4px;
}
.rec-transport__side { display: flex; align-items: center; gap: 12px; }
.rec-transport__side--right {
  position: absolute;
  right: -10px;
}
.rec-transport__center { flex: 0 0 auto; display: flex; align-items: center; gap: 24px; }

/* Round icon buttons (restart, trim) — dark glyph on light. */
.rec-transport__ctrl {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--icon-primary);
  cursor: pointer;
  transition: color 0.12s ease, background 0.12s ease;
}
.rec-transport__ctrl:hover { color: var(--icon-primary); background: var(--cool-gray-20); }
.rec-transport__ctrl svg { width: 20px; height: 20px; display: block; }
/* Muted volume button reads as dimmed. */
.rec-transport__ctrl.is-muted { color: var(--icon-disabled); }

/* Skip back/forward — same treatment as the play/pause toggle (dark round
   fill, white glyph), just smaller and with the skip icon. */
.rec-transport__skip {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--cool-gray-100);
  color: var(--white);
  cursor: pointer;
  transition: background 0.12s ease;
}
.rec-transport__skip:hover { background: var(--cool-gray-90); }
.rec-transport__skip svg { width: 18px; height: 12px; display: block; }

/* Playback-speed text toggle. */
.rec-transport__speed {
  height: 32px;
  padding: 0 8px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--icon-primary);
  font-family: var(--font-mono);
  font-size: 14px;
  cursor: pointer;
  transition: background 0.12s ease;
}
.rec-transport__speed:hover { background: var(--cool-gray-20); }

/* Big round play/pause — cool-gray-100 fill, white glyph (Figma). */
.rec-transport__toggle {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--cool-gray-100);
  color: var(--white);
  cursor: pointer;
  transition: background 0.12s ease, transform 0.08s ease;
}
.rec-transport__toggle:hover { background: var(--cool-gray-90); }
.rec-transport__toggle:active { transform: scale(0.94); }
.rec-transport__toggle svg { width: 20px; height: 20px; display: block; }
/* Show pause while playing, play while paused (one glyph at a time). */
.rec-transport__toggle .rec-transport__pause-icon { display: block; }
.rec-transport__toggle .rec-transport__play-icon { display: none; }
.rec-transport__toggle.is-paused .rec-transport__pause-icon { display: none; }
.rec-transport__toggle.is-paused .rec-transport__play-icon { display: block; }

/* Dual timers below the wave (current position | total duration). */
.rec-times {
  display: none;
  align-items: center;
  justify-content: space-between;
  width: calc(100% - 32px); /* match .rec-wave width */
  max-width: 100%;
  font-family: var(--font-mono);
  font-size: 18px;
  color: var(--text-primary);
}
/* Uploaded state overrides the line 429 !important for rec-times (not shown). */
/* Review has no file tag (Figma). */
.record-panel.is-uploaded .record-panel__filetag { display: none; }

/* Static dotted waveform — only visible in the uploaded state. */
.rec-static-wave-wrap { display: none; }
.record-panel.is-uploaded .rec-static-wave-wrap { display: block; }

/* Transcribe recording button removed — transcription is now live/automatic. */
.record-panel__restart { display: none !important; } /* replaced by the restart icon */

/* Landing shows only the record-panel; ready/recording/review show the dark screen. */
.recorder[data-rec="landing"] .recorder__screen,
.recorder[data-rec="landing"] .recorder__controls { display: none; }
.recorder:not([data-rec="landing"]) .record-panel { display: none; }

/* Back to upload — hidden by default (idle dropzone); shown once the panel is
   recording or playing back an uploaded file (.record-panel.is-listening). */
.recorder__back { display: none; }
.record-panel.is-listening .recorder__back { display: inline-flex; }

/* Back to upload button — pinned top-left inside the panel, at the same 16px
   inset as the bottom bar (display is gated above by the recording state). */
.recorder__back {
  position: absolute;
  top: 16px;
  left: 16px;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border: 1px solid var(--cool-gray-30);
  border-radius: 8px;
  background: var(--white);
  color: var(--text-secondary);
  font: inherit;
  font-size: 12px;
  line-height: 16px;
  letter-spacing: 0.32px;
  cursor: pointer;
  flex-shrink: 0;
  transition: color 0.12s ease;
}
.recorder__back:hover { color: var(--text-primary); }
.recorder__back svg { width: 16px; height: 16px; display: block; flex-shrink: 0; }

/* Dark recorder screen — sits inside the white panel. */
.recorder__screen {
  flex: 1 0 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 20px;
  background: var(--cool-gray-100);
  border-radius: 12px;
  color: var(--white);
  overflow: hidden;
}

/* Waveform region: bars fill center, blue playhead marks the "now" line. */
.recorder__wave {
  flex: 1 0 0;
  min-height: 0;
  position: relative;
  display: flex;
  align-items: center;
  overflow: hidden;
}
.recorder__bars {
  display: flex;
  align-items: center;
  gap: 3px;
  height: 88px;
  width: 100%;
}
.recorder__bars span {
  flex: 1 0 0;
  min-width: 2px;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.85);
  height: 6%;
}
/* Bars past the playhead read as "not yet recorded". */
.recorder__bars span.is-future { background: rgba(255, 255, 255, 0.18); height: 6% !important; }
.recorder__playhead {
  position: absolute;
  top: 8%;
  bottom: 8%;
  left: 58%;
  width: 2px;
  background: var(--rec-accent);
  display: none;
}
.recorder__playhead::before {
  content: "";
  position: absolute;
  top: -5px; left: -3px;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--rec-accent);
}

/* Bottom row: timer left, buttons right */
.recorder__bottom {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  margin-top: 12px;
  flex-shrink: 0;
}
.recorder__btns {
  display: flex;
  gap: 8px;
  align-items: center;
}
.recorder__time {
  font-family: var(--font-sans);
  font-size: 64px;
  line-height: 1;
  font-weight: 300;
  letter-spacing: 1px;
  font-variant-numeric: tabular-nums;
  color: var(--white);
}

/* Circular buttons in the recorder bottom row */
.rec-mic-btn {
  display: grid;
  place-items: center;
  width: 64px; height: 64px;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.12s ease, transform 0.08s ease;
}
.rec-mic-btn:active { transform: scale(0.96); }
.rec-mic-btn svg { width: 28px; height: 28px; }

/* Mic (blue) — ready state only */
.rec-mic-btn--mic { background: var(--rec-accent); color: var(--cool-gray-100); }
.rec-mic-btn--mic:hover { background: var(--blue-30, #a6c8ff); color: var(--cool-gray-100); }

/* Stop (blue) — recording state only */
.rec-mic-btn--stop { background: var(--rec-accent); color: var(--cool-gray-100); }
.rec-mic-btn--stop:hover { background: var(--blue-30, #a6c8ff); color: var(--cool-gray-100); }

/* Pause (cool-gray) — recording state only */
.rec-mic-btn--pause { background: var(--cool-gray-30); color: var(--cool-gray-100); }
.rec-mic-btn--pause:hover { background: var(--cool-gray-20); }
.rec-mic-btn--pause.is-paused { background: var(--cool-gray-20); }

/* State visibility */
.recorder[data-rec="ready"] .rec-mic-btn--stop { display: none; }
.recorder[data-rec="ready"] .rec-mic-btn--pause { display: none; }
.recorder[data-rec="recording"] .rec-mic-btn--mic { display: none; }
.recorder[data-rec="review"] .rec-mic-btn { display: none; }
.recorder[data-rec="review"] .recorder__bottom { display: none; }

/* Playhead shown during recording and playback */
.recorder[data-rec="recording"] .recorder__playhead { display: block; }
.recorder.is-playing .recorder__playhead { display: block; }
@keyframes rec-blink { 50% { opacity: 0.25; } }

/* Review state time labels — shown inside dark screen, below waveform */
.recorder__review-times {
  display: none;
  justify-content: space-between;
  padding: 0 2px;
  margin-top: 8px;
  flex-shrink: 0;
}
.recorder__review-time-start,
.recorder__review-time-end {
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 20px;
  color: var(--white);
}
.recorder[data-rec="review"] .recorder__review-times { display: flex; }

/* Review transport controls row — inside the dark screen */
.recorder__review-controls {
  display: none;
  align-items: center;
  justify-content: space-between;
  padding-top: 12px;
  flex-shrink: 0;
}
.recorder[data-rec="review"] .recorder__review-controls { display: flex; }

/* "New recording" + "Transcribe" pill buttons */
.rec-review-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 48px;
  padding: 0 24px;
  border-radius: 40px;
  font-family: var(--font-sans);
  font-size: 16px;
  font-weight: 400;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.12s ease, border-color 0.12s ease, transform 0.08s ease;
}
.rec-review-btn:active { transform: scale(0.97); }

/* "New recording" — outline white border */
.rec-review-btn--new {
  background: transparent;
  border: 1px solid var(--white);
  color: var(--white);
}
.rec-review-btn--new:hover { background: rgba(255,255,255,0.1); }

/* "Transcribe" — solid blue-40 */
.rec-review-btn--transcribe {
  background: var(--rec-accent);
  border: 1px solid var(--rec-accent);
  color: var(--cool-gray-100);
}
.rec-review-btn--transcribe:hover { background: var(--blue-30, #a6c8ff); border-color: var(--blue-30, #a6c8ff); }

/* Center cluster: skip-back + stop + skip-forward */
.rec-review-center {
  display: flex;
  align-items: center;
  gap: 8px;
}
.rec-review-icon-btn {
  display: grid;
  place-items: center;
  width: 64px; height: 64px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--white);
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.12s ease, transform 0.08s ease;
}
.rec-review-icon-btn:hover { background: rgba(255,255,255,0.1); }
.rec-review-icon-btn:active { transform: scale(0.96); }
.rec-review-icon-btn svg { width: 28px; height: 28px; }

/* Stop button in center cluster — blue-40 fill */
.rec-review-icon-btn--stop {
  background: var(--rec-accent);
  color: var(--cool-gray-100);
}
.rec-review-icon-btn--stop:hover { background: var(--blue-30, #a6c8ff); }


/* ============================================================================
   Left column — Upload Audio dropzone (Speech)
   The dropzone is the whole left panel; clicking it kicks off a stubbed
   transcription (see app.js). No swappable sub-views in the Speech demo.
   ========================================================================== */

/* --- Right column: transcription canvas ------------------------------------
   Canvas frame holds the "Transcription" toolbar, the transcription output
   field, and the Prompt card (language select + processing toggles). */

/* Disable the right panel until recording/upload has started — except the
   punctuation toggle, which stays live so it can be set in advance. */
.workspace:not(.is-active) .canvas-body {
  pointer-events: none;
}
.workspace:not(.is-active) .canvas-body .toggle-row {
  pointer-events: auto;
}
.workspace:not(.is-active) .canvas-body .transcription,
.workspace:not(.is-active) .canvas-body .transcription[data-placeholder="true"],
.workspace:not(.is-active) .canvas-body .prompt-card__label,
.workspace:not(.is-active) .canvas-body .select-field__value,
.workspace:not(.is-active) .canvas-body .select-field__chevron,
.workspace:not(.is-active) .canvas-toolbar__title { color: var(--text-disabled); }
.workspace:not(.is-active) .canvas-body .transcription,
.workspace:not(.is-active) .canvas-body .select-field {
  background: var(--cool-gray-10);
}

.canvas-body {
  flex: 1 0 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
  /* Reduced top padding so the field sits closer to the toolbar title and
     fills the space above it. */
  padding: 8px 16px 16px;
}

/* Transcription output — fills remaining height. Placeholder-gray until a
   transcript is produced; shimmered while transcribing. */
.transcription {
  flex: 1 0 0;
  min-height: 0;
  padding: 16px;
  background: var(--color-field, var(--cool-gray-10));
  border-radius: 12px;
  overflow: auto;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: 0.16px;
  color: var(--text-primary);
  white-space: pre-wrap;
  text-align: left;
  position: relative;
}
.transcription__text {
  position: relative;
  z-index: 1;
  display: inline-block;
}
/* Placeholder state: gray, non-selectable helper copy. */
.transcription[data-placeholder="true"] { color: var(--text-placeholder); }

/* Silent recording shimmer — sweep across the placeholder text only. */
@keyframes text-shimmer {
  0% { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}
.transcription.is-silent {
  color: var(--text-primary);
}
.transcription.is-silent .transcription__text {
  color: transparent;
  background-image: linear-gradient(
    110deg,
    var(--text-primary) 0%,
    var(--text-primary) 46.5%,
    rgba(255, 255, 255, 0.8) 50%,
    var(--text-primary) 53.5%,
    var(--text-primary) 100%
  );
  background-size: 200% 140%;
  background-repeat: no-repeat;
  background-position: 100% 50%;
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: text-shimmer 1.8s linear infinite;
}

/* Shared upload skeleton shimmer — matches the Granite Speech loading sweep. */
@keyframes upload-skeleton-shimmer {
  to { transform: translateX(150%) skewX(-20deg); }
}
.workspace.is-uploading .transcription,
.workspace.is-uploading .toggle-row {
  position: relative;
  overflow: hidden;
  background: var(--cool-gray-10);
  border-width: 0;
  pointer-events: none;
}
.workspace.is-uploading .transcription {
  color: transparent;
}
.workspace.is-uploading .transcription .transcript-ts {
  background: transparent;
  color: transparent;
}
.workspace.is-uploading .transcription__text,
.workspace.is-uploading .toggle {
  visibility: hidden;
}
.workspace.is-uploading .toggle-row__label {
  color: transparent;
}
.workspace.is-uploading .transcription::after,
.workspace.is-uploading .toggle-row::after {
  content: "";
  position: absolute;
  inset: -30% 0;
  transform: translateX(-150%) skewX(-20deg);
  background: linear-gradient(
    90deg,
    transparent 5%,
    rgba(255, 255, 255, 0.98) 50%,
    transparent 95%
  );
  animation: upload-skeleton-shimmer 1.2s infinite;
  pointer-events: none;
}
/* Timestamp tokens — [0:00] — muted monospace pill. */
.transcript-ts {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  font-weight: 300;
  letter-spacing: 0.32px;
  color: var(--text-helper, var(--cool-gray-50));
  background: var(--cool-gray-20, #dde1e6);
  border-radius: 4px;
  padding: 1px 5px;
  margin-right: 4px;
  vertical-align: 1px;
  user-select: none;
}

/* Prompt card — pinned below the transcription output. */
.prompt-card {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: 0;
}
.prompt-card__header { display: none; }
.prompt-card__label {
  font-size: 14px;
  line-height: 20px;
  color: var(--text-primary);
}
.prompt-card__tag {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 8px;
  border-radius: 8px;
  background: var(--blue-10);
  color: var(--content-regular, #282828);
  font-size: 12px;
  line-height: 16px;
  white-space: nowrap;
}
.workspace:not(.is-active) .canvas-body .prompt-card__tag,
.workspace:not(.is-active) .canvas-toolbar .prompt-card__tag {
  background: var(--cool-gray-10);
  color: var(--text-disabled);
}

/* Language "select" — display-only dropdown trigger (Carbon field look). */
.select-field {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  height: 48px;
  padding: 0 16px;
  background: var(--cool-gray-10);
  border: none;
  outline: none;
  border-radius: 12px;
  text-align: left;
  cursor: pointer;
}
.select-field__value {
  flex: 1 0 0;
  min-width: 0;
  font-size: 14px;
  line-height: 16px;
  color: var(--text-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.select-field__chevron {
  width: 16px; height: 16px; color: var(--text-secondary); flex-shrink: 0;
  transition: transform 0.15s ease;
}
/* Placeholder state — no language chosen yet */
.select-field[data-placeholder="true"] .select-field__value { color: var(--text-placeholder); }
.select-field[data-placeholder="true"] .select-field__chevron { color: var(--text-placeholder); }
/* Once transcription is active, the placeholder + chevron read as active
   text-primary (matches main's parsing dropdown). */
.workspace.is-active .select-field[data-placeholder="true"] .select-field__value,
.workspace.is-active .select-field[data-placeholder="true"] .select-field__chevron { color: var(--text-primary); }
/* Interactive hover only once transcription is active — no background change
   (matches main's parsing dropdown). */
.workspace.is-active .select-field:hover .select-field__value { color: var(--text-primary); }
/* Open state: dark border + flip the chevron. */
.select[data-open="true"] .select-field { border: 1.5px solid var(--cool-gray-100); }
.select[data-open="true"] .select-field__chevron { transform: rotate(180deg); }

/* --- Dropdown menu (listbox) ------------------------------------------- */
.select { position: relative; }
.select-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 20;
  margin: 0;
  padding: 4px;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 116px;
  overflow-y: auto;
  background: var(--white, #fff);
  border: 1px solid var(--cool-gray-20);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.16);
}
.select-menu[hidden] { display: none; }
.select-option {
  display: flex;
  align-items: center;
  padding: 8px 12px;
  border-radius: 8px;
  font-size: 14px;
  line-height: 18px;
  color: var(--text-primary);
  cursor: pointer;
}
.select-option:hover,
.select-option.is-active { background: var(--cool-gray-10); }
.select-option[aria-selected="true"] {
  background: var(--cool-gray-10);
  font-weight: 500;
}
.select-option[aria-selected="true"]::after {
  content: "";
  margin-left: auto;
  width: 16px; height: 16px;
  flex-shrink: 0;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6.4 11.6 3 8.2l.9-.9 2.5 2.5L12.1 4l.9.9z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6.4 11.6 3 8.2l.9-.9 2.5 2.5L12.1 4l.9.9z'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Toggle rows — label + Carbon-style switch on a field background. */
.toggle-row {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 48px;
  padding: 0 16px;
  background: var(--color-field, var(--cool-gray-10));
  border-radius: 12px;
  cursor: pointer;
}
.toggle-row__label {
  flex: 1 0 0;
  min-width: 0;
  font-size: 14px;
  line-height: 20px;
  color: var(--text-primary);
}
/* Carbon-style toggle switch built from a checkbox. */
.toggle {
  position: relative;
  flex-shrink: 0;
  width: 44px;
  height: 24px;
}
.toggle__input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
/* Off (active state): dark track, white knob on the left, gray status dot on
   the right to indicate off. On: dark track, knob slides right, green dot on
   the left. Both share the dark track — only the knob position + dot differ. */
.toggle__track {
  position: relative;
  display: block;
  width: 44px;
  height: 24px;
  border-radius: 12px;
  background: var(--container-inverse, #131313);
  transition: background 0.15s ease;
}
/* Off status dot — gray, mirrored to the right (opposite the left-sitting knob). */
.toggle__input:not(:checked) ~ .toggle__track::before {
  content: "";
  position: absolute;
  top: 10px;
  right: 10px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--cool-gray-50);
}
.toggle__knob {
  position: absolute;
  top: 4px;
  left: 4px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--white);
  transition: transform 0.15s ease;
  z-index: 1;
}
/* On: dark track, white knob on the right, green status dot on the left. */
.toggle__input:checked ~ .toggle__track { background: var(--container-inverse, #131313); }
.toggle__input:checked ~ .toggle__track .toggle__knob { transform: translateX(20px); }
.toggle__input:checked ~ .toggle__track::before {
  content: "";
  position: absolute;
  top: 10px;
  left: 10px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--support-success);
}

/* Toggle: proxy focus ring onto the visible track since input is hidden */
.toggle__input:focus-visible ~ .toggle__track {
  outline: 2px solid var(--blue-60);
  outline-offset: 2px;
}

/* Canvas frame (right) — Transcription */
.canvas-frame {
  width: 100%;
  height: 100%;
  background: var(--white);
  border: 1px solid var(--cool-gray-20);
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.canvas-toolbar {
  position: relative;
  padding: 16px 16px 8px;
  display: flex;
  align-items: center;
  gap: 8px;
}
.canvas-toolbar__actions {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
}
/* Toolbar icon buttons — same as doc-intelligence logo-chip */
.logo-chip {
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--text-disabled);
  display: grid;
  place-items: center;
  cursor: pointer;
}
.logo-chip svg { width: 14px; height: 14px; display: block; }
.workspace:not(.is-active) .logo-chip { pointer-events: none; cursor: default; }
.workspace.is-active .logo-chip { color: var(--cool-gray-100); }
.workspace.is-active .logo-chip:hover { background: var(--cool-gray-10); }
/* Tooltips for toolbar action buttons: appear to the left, vertically centred */
.canvas-toolbar__actions [data-tooltip]::after {
  top: 50%;
  left: auto;
  right: calc(100% + 8px);
  transform: translateY(-50%);
}
.canvas-toolbar__actions [data-tooltip]::before {
  top: 50%;
  left: auto;
  right: calc(100% - 1px);
  transform: translateY(-50%) rotate(90deg);
}

/* Transcription wrapper — positions the telemetry pills inside the field */
.transcription-wrap {
  position: relative;
  flex: 1 0 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.transcription-wrap .transcription {
  flex: 1 0 0;
  min-height: 0;
}

/* Telemetry pills — hidden until workspace is active, pinned bottom-right */
.telemetry-pills {
  display: none;
  position: absolute;
  bottom: 10px;
  right: 10px;
  align-items: center;
  gap: 6px;
  pointer-events: none;
}
.workspace.is-active .telemetry-pills { display: flex; }
.workspace.is-uploading .telemetry-pills,
.workspace.is-transcribing .telemetry-pills { display: none !important; }
.telemetry-pill {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 8px;
  border-radius: 8px;
  background: var(--cool-gray-20);
  color: var(--text-secondary);
  font-size: 12px;
  line-height: 16px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.canvas-toolbar__title {
  font-weight: 500;
  font-size: 16px;
  line-height: 20px;
  color: var(--text-primary);
}

/* Left column heading — same 16px-medium treatment as .canvas-toolbar__title,
   and the 16px panel padding aligns it with the right column's "Transcription"
   title. The 8px bottom gap mirrors the canvas toolbar (16px 16px 8px).
   Hidden in the idle dropzone; shown only once recording / reviewing.
   16px bottom gap = the right column's 8px toolbar + 8px body top padding, so
   the gray panel top-aligns with the transcription field. */
.recorder-toolbar { display: none; padding-bottom: 16px; flex-shrink: 0; align-items: center; gap: 8px; }
.upload-view--record:has(.record-panel.is-listening) .recorder-toolbar { display: flex; }
.upload-view--record:has(.record-panel.is-converting) .recorder-toolbar { display: none; }
/* Otherwise-hidden in the idle landing state — but while the model is still
   downloading, that's exactly when a visible "Loading model… X%" message
   matters most (the dimmed panel alone reads as broken, not loading). */
body.is-model-loading .recorder-toolbar { display: flex; }
.recorder-toolbar__title {
  font-weight: 500;
  font-size: 16px;
  line-height: 20px;
  color: var(--text-primary);
}
.recorder-toolbar__filetag {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 8px;
  border-radius: 8px;
  background: var(--blue-10);
  color: var(--content-regular, #282828);
  font-size: 12px;
  line-height: 16px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 220px;
}

/* ============================================================================
   Live interim text shimmer — glisten effect on in-progress speech
   Applied to .transcript-interim spans while dictation is active.
   ========================================================================== */
@keyframes shimmer {
  to { transform: translateX(150%) skewX(-20deg); }
}
@keyframes text-glisten {
  0%   { background-position: -200% center; }
  100% { background-position:  200% center; }
}

/* Interim words: each word staggers in with a glisten sweep + fade from dim */
/* Stop dictation / Start dictation toggle icons */
.rec-btn__mic-icon { display: none; }
.rec-btn__stop-icon { display: block; }

/* Each finalized pause-segment on its own line */
.transcript-line {
  display: block;
  margin-bottom: 4px;
}
.transcript-line:last-child { margin-bottom: 0; }

/* Interim words: stagger in at full text color */
.transcript-word {
  display: inline;
  color: var(--text-primary);
}

/* ============================================================================
   Info panel — speech-specific graphic content (mic glyph)
   Everything else (layout, header, body, footer) is in shared/base.css.
   ========================================================================== */
.info-panel__glyph {
  position: relative;
  z-index: 1; /* keep the mic above the shimmer sweep */
  width: 96px;
  height: 96px;
  color: var(--icon-on-color);
  display: block;
}
/* ============================================================================
   Responsive: let the fixed-width card shrink gracefully on narrow viewports.
   The frame is designed at 1584px; below that we scale the card container.
   ========================================================================== */
/* Below the 1584px design viewport (1544px card + 40px gutters), the fixed
   Figma column widths no longer fit — fall back to fluid fractions. At/above
   1584px the base grid renders the design pixel-exact. */
/* max (1584px) → xlg (1312px): fluid equal columns */
@media (max-width: 1583px) {
  .workspace { grid-template-columns: 1fr 1fr; }
}

/* xlg (1312px): slightly reduce left col padding */
@media (max-width: 1312px) {
  .ws-col--left { padding-right: 6px; }
  .ws-col--right { padding-left: 6px; }
}

/* lg (1056px): stack to single column — aligned to Carbon lg breakpoint */
@media (max-width: 1056px) {
  html, body { overflow-y: auto; }
  .app { height: 100vh; min-height: 700px; overflow: hidden; background: var(--cool-gray-10); }
  .stage { flex: 1 1 0; min-height: 0; padding: 0; }
  .app-card { flex: 1 1 0; min-height: 0; overflow: hidden; border-radius: 0; box-shadow: none; }
  /* Upload modal — bottom sheet on mobile */
  .upload-modal { align-items: flex-end; padding: 0; overflow-y: visible; }
  .upload-modal__dialog {
    width: 100%;
    max-width: 100%;
    border-radius: 16px 16px 0 0;
    transform: translateY(0);
    transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
  }
  .upload-modal__dialog.is-hiding {
    transform: translateY(100%);
  }
  .upload-modal__header { padding: 24px 20px 16px; flex-shrink: 0; }
  .upload-modal__title { font-size: 18px; line-height: 26px; }
  .upload-modal__body { padding: 16px 20px 20px; }
  .upload-modal__footer { padding: 16px 20px 32px; flex-shrink: 0; }
  .workspace { display: flex; flex-direction: column; flex: 1 1 0; min-height: 0; height: auto; overflow: hidden; }
  .ws-col { overflow: hidden; flex: 1 1 0; min-height: 0; }
  .canvas-frame { height: 100%; min-height: 0; }
  .canvas-body { flex: 1 1 0; min-height: 0; overflow: auto; }
  .transcription { flex: 1 1 0; min-height: 0; overflow: auto; }
  .ws-col--left { padding-right: 8px; }
  .ws-col--right { padding-left: 8px; padding-bottom: 8px; }
  .ws-col--left .panel { min-height: 0; }
  .info-panel,
  .info-panel.is-expanded {
    position: absolute;
    top: auto;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    max-width: none;
    min-width: 0;
    height: 50vh;
    border-radius: 16px 16px 0 0;
    transform: translateY(0);
    transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
  }
  .info-panel.is-hiding {
    transform: translateY(100%);
  }
  .info-panel.is-expanded .info-panel__graphic { display: none; }
  .info-panel__main { overflow: hidden; }
  .info-panel__body { overflow-y: auto; flex: 1 1 0; min-height: 0; }
  .info-panel__header { padding: 14px 16px 16px; }
  .info-panel__body { padding: 14px 16px; }
  .info-panel__footer { padding: 12px 16px 14px; }
}

/* Info panel drag handle */
.info-panel__handle {
  display: none;
  width: 36px;
  height: 4px;
  border-radius: 2px;
  background: var(--cool-gray-60);
  margin: 12px auto 4px;
  flex-shrink: 0;
}
@media (max-width: 1056px) {
  .info-panel__handle { display: block; }
  .info-panel__close { display: none; }
}

/* Bottom sheet drag handle — shown on mobile, hidden on desktop */
.upload-modal__handle {
  display: none;
  width: 36px;
  height: 4px;
  border-radius: 2px;
  background: var(--cool-gray-60);
  margin: 12px auto 0;
  flex-shrink: 0;
}
@media (max-width: 1056px) {
  .upload-modal__handle { display: block; }
  .upload-modal__close { display: none; }
}

/* Tablet gap (673–1056px): the workspace already stacks to a single column
   at 1056px (squeezing the record panel's height), but the voice cluster
   didn't scale down until the 672px mobile breakpoint — so at tablet widths
   it kept its full 200px size and overflowed the now-shorter panel instead
   of staying centered. Give it a lighter version of the mobile scale-down. */
@media (max-width: 1056px) and (min-width: 673px) {
  .voice-cluster { transform: scale(0.85); transform-origin: center; margin: -10px 0; }
  .record-visual { margin-bottom: 0; }
}

/* Short window (wide layout, height-constrained): a wide-but-short browser
   never reaches the 1056px width breakpoint, so .record-panel's own
   overflow:hidden + justify-content:center just clips the voice cluster's
   top and hides the timer below it once the centered mic/wave/timer stack
   is taller than the panel. Scale it down the same way the width
   breakpoints do, but keyed off height instead. Scoped to widths above the
   stacking breakpoint so it doesn't double up with the width-based rules. */
@media (min-width: 1057px) and (max-height: 700px) {
  .voice-cluster { transform: scale(0.85); transform-origin: center; margin: -10px 0; }
  .record-visual { margin-bottom: 0; }
}
@media (min-width: 1057px) and (max-height: 560px) {
  .voice-cluster { transform: scale(0.7); transform-origin: center; margin: -22px 0; }
  .record-panel__recording { gap: 12px; }
  .rec-wave { height: 40px; }
  .rec-wave__dot { width: 3px; height: 3px; min-width: 3px; min-height: 3px; }
}

/* md (672px): compact spacing, tighter controls */
@media (max-width: 672px) {
  .workspace { gap: 0; }
  .panel--pad { padding: 12px; }
  .record-panel { padding: 12px; border-radius: 8px; gap: 4px; justify-content: center; }
  .rec-bar__btn-label { display: none; }
  .voice-cluster { transform: scale(0.78); transform-origin: center; margin: -16px 0; }
  .record-visual { margin-bottom: 0; }
  .record-panel__mic { width: 46px; height: 46px; }
  .record-panel__mic svg { width: 20px; height: 20px; }
  .rec-wave { width: 100%; height: 40px; }
  .rec-wave__col { gap: 1px; }
  .rec-wave__dot { width: 3px; height: 3px; min-width: 3px; min-height: 3px; }
  .rec-transport { width: 100%; gap: 8px; }
  .rec-times { width: 100%; }
  .rec-transport__center { gap: 12px; }
  .canvas-toolbar { padding: 12px 12px 0; }
  .canvas-body { padding: 12px; gap: 12px; }
  .prompt-card__label { display: none; }
  .prompt-card { border: none; padding: 0; gap: 12px; }
  .record-panel__recording { gap: 24px; }
  /* Type scale */
  .record-panel__title { font-size: 15px; }
  .record-panel__rectime { font-size: 15px; }
  .rec-times { font-size: 15px; }
  .canvas-toolbar__title { font-size: 15px; }
  .recorder-toolbar__title { font-size: 15px; }
  .rec-bar__device { font-size: 12px; }
  /* Match panel's 12px padding — override the desktop 16px insets */
  .record-panel.is-listening:not(.is-uploaded):not(.is-converting) .rec-bar {
    left: 12px;
    right: 12px;
    bottom: 12px;
  }
  .recorder__back {
    top: 12px;
    left: 12px;
  }
}

/* sm (320px): minimal chrome */
@media (max-width: 320px) {
  .record-panel { padding: 12px; gap: 8px; }
  .rec-transport__speed { display: none; }
  .canvas-body { padding: 8px; }
}
