/* ============================================================================
   audiotrove.css — the AudioTrove marketing site's OWN stylesheet. STANDALONE.

   This was forked ONE TIME from the app design system (trove-core.css) on
   2026-08-08 as a visual starting point, then decoupled. It is now the website's
   own file and evolves INDEPENDENTLY. It is NOT the design system and must NEVER
   be synced to/from the prototype. The website shares NOTHING with the prototype:
   its HTML, CSS, fonts, icons, and images all live under design/website/.

   Deltas already applied vs the original fork: (1) no external Fraunces @import
   (fonts are self-hosted in fonts/fonts.css); (2) native page scrollbar restored
   (the app mockups hid it to look phone-like; a real website shows it).
   ============================================================================ */

/* ============================================================================
   TROVE CORE:  interactable design system  (D30 exploration build)
   STANDALONE / NOT CANONICAL until the principal approves D30.
   2-tier tokens: REFERENCE → SEMANTIC. Components bind to SEMANTIC only, so the
   D6 colour overhaul is a re-point, not a rewrite. Colours here are NEUTRAL
   PLACEHOLDERS (D6 owns final hue). Locked: Soft buttons · Tighter radius ·
   Compact density · pills (no tabs) · custom transport shapes · ≥48 hit.
   Class names are by ROLE (never appearance) to prevent collisions (brief §5).
   ============================================================================ */

/* [deploy-strip] the canonical Fraunces @import was here; removed for the site — Fraunces is served first-party by vendor/fonts/fonts.css. This is the ONLY delta from canonical. */   /* cover-fallback DISPLAY serif (Fraunces): covers only; the body serif stays Lora */
*,*::before,*::after{box-sizing:border-box}   /* system reset: width includes padding/border (block buttons, scaffold, etc. assume this) */
[hidden]{display:none!important}   /* the hidden attribute ALWAYS wins. Beats any component/utility display: rule, so toggling el.hidden works EVERYWHERE (no per-element [hidden] guard needed; Bootstrap/normalize convention) */
/* WEB-RENDER ONLY: hide scrollbars so the mockups read like a phone (Android/iOS use auto-hiding overlay scrollbars; the app doesn't style scrollbars). Scrolling still works. */
*{scrollbar-width:none;-ms-overflow-style:none}
*::-webkit-scrollbar{width:0;height:0;display:none}

/* ===== TIER 1: REFERENCE (raw values; never used by components directly) ==== */
:root{
  /* palette: placeholder neutrals; D6 replaces these hues */
  --ref-bg:#14140f; --ref-surface:#211f1a; --ref-elevated:#2a2722; --ref-elevated-2:#423d34;   /* elevated-2 = top elevation (snackbar), clearly above the bg */
  --ref-line:#3a352c; --ref-line-2:#4a4438;
  --ref-ink:#ece8dd; --ref-ink-2:#b7b1a2; --ref-ink-3:#857f70;
  --ref-gold:#d9c77e; --ref-gold-ink:#1b1810; --ref-gold-soft:#34301f;
  --ref-sage:#8fb39a; --ref-clay:#d98a7e; --ref-leaf:#93ce8a;
  --ref-star:#f2c33b; --ref-download:#7ec873;   /* state-icon hues, PROPOSED, principal to tune: star-yellow (distinct from the pale gold action) · downloaded-green (variant of leaf/success) */
  /* radius scale: Tighter */
  --ref-r-xs:4px; --ref-r-sm:8px; --ref-r-md:10px; --ref-r-lg:12px; --ref-r-full:999px;
  /* size / density: Compact (drawn; hit ≥48 enforced separately) */
  --ref-h-sm:40px; --ref-h-md:44px; --ref-h-lg:56px;
  /* space: 4dp grid */
  --ref-s-1:4px; --ref-s-2:8px; --ref-s-3:12px; --ref-s-4:16px; --ref-s-5:20px; --ref-s-6:24px;
  /* type */
  --ref-serif:'Lora',Georgia,serif; --ref-sans:'Hanken Grotesk',system-ui,sans-serif; --ref-cover:'Fraunces','Lora',Georgia,serif;   /* cover-fallback DISPLAY serif (not the body serif) */   /* serif = Lora (principal 2026-06-20; Fraunces dropped, too thin on phone) */
  /* motion */
  --ref-dur-press:150ms; --ref-dur:200ms; --ref-dur-enter:300ms;   /* MOTION durations on the M3 50ms grid: feedback (press/toggle/select) 150 · base (fades/scrim/exits) 200 · overlay-enter (sheet/dialog/menu) 300. Continuous loops (buffering/skeleton/spin) are bespoke, not on this scale. */
  --ref-ease:cubic-bezier(.2,0,0,1); --ref-ease-enter:cubic-bezier(0,0,0,1); --ref-ease-exit:cubic-bezier(.3,0,1,1);   /* MOTION easing (Material 3 named): standard (default) · decelerate = ENTER (settles in) · accelerate = EXIT (snaps away) */
}

/* ===== TIER 2: SEMANTIC (the only layer components read) ==================== */
:root{
  /* ===== MIDNIGHT: the default theme. FULL EXPLICIT palette (no derivation). Every [data-theme] block sets its own
     full palette likewise. The 17 colour tokens (base ramp · action family · accent · content signals). ===== */
  --base:rgba(10, 13, 19, 1); --base-surface:rgba(23, 27, 33, 1); --base-elevated:rgba(33, 36, 42, 1); --base-outline:rgba(58, 61, 68, 1); --base-outline-strong:rgba(73, 77, 84, 1);
  --base-on-surface:rgba(224, 229, 238, 1); --base-on-surface-variant:rgba(173, 177, 186, 1); --base-on-surface-faint:rgba(128, 132, 140, 1);
  --snackbar-surface:rgba(58, 61, 68, 1); --dialog-surface:rgba(33, 36, 42, 1); --banner-surface:rgba(23, 27, 33, 1); --chip-border:rgba(53, 103, 147, 1); --bar-track:rgba(73, 77, 84, 1);   /* component surfaces/borders: own tokens (snackbar/dialog/banner bg · chip border · progress-bar track) */
  --action:rgba(49, 137, 208, 1); --action-soft:rgba(0, 38, 67, 1); --action-selected:rgba(0, 58, 99, 1); --action-outline:rgba(33, 85, 128, 1); --action-bright:rgba(49, 137, 208, 1);
  --accent:rgba(190, 165, 106, 1); --success:rgba(143, 206, 132, 1); --danger:rgba(234, 126, 111, 1); --bookshelf:rgba(243, 196, 60, 1); --warning:rgba(216, 148, 71, 1);

  /* radius BY ROLE (the cohesion lever) */
  --r-button:var(--ref-r-md);      /* Soft */
  --r-control:var(--ref-r-sm);     /* inputs · menus · segmented */
  --r-container:var(--ref-r-lg);   /* cards · sheets · dialogs · menus */
  --r-tag:var(--ref-r-xs);
  --r-pill:var(--ref-r-full);      /* chips · view-selector · avatar */
  /* control heights */
  --h-control:var(--ref-h-md); --h-prominent:var(--ref-h-lg); --h-compact:var(--ref-h-sm);
  /* type roles */
  --font-display:var(--ref-serif); --font-headline:var(--ref-serif); --font-title:var(--ref-serif);
  --font-body:var(--ref-sans); --font-label:var(--ref-sans);
  /* state */
  --press-op:.55; --disabled-op:.38; --row-highlight:rgba(255,255,255,.05); --space:var(--ref-s-4);
  /* scaffold (Layer 4): page & sheet structure */
  --page-gutter:20px; --overlay-gutter:12px;   /* --overlay-gutter = horizontal padding inside snackbar / banner (dialogs use 20px all round) */
  --section-gap:24px; --section-gap-tight:16px; --block-gap:12px;   /* VERTICAL RHYTHM, all on the 4/8/12/16/20/24 scale. Between SECTIONS: airy 24 (hero/content screens) · tight 16 (list/dense screens, add .tc-screen__body--tight). WITHIN a section: block 12 (header→content / sub-groups). Item/row gap 8 is component-owned (li-sp). */
  --appbar-h:56px; --content-max:640px;
  --inset-top:24px; --inset-bottom:24px;   /* CSS proxies: real values = WindowInsets at runtime */
  --sheet-radius:var(--r-container); --sheet-grabber:32px; --scrim:rgba(0,0,0,.55);
  --shadow-1:0 16px 34px -14px rgba(0,0,0,.6); --shadow-2:0 24px 50px -18px rgba(0,0,0,.7);   /* ELEVATION shadows for FLOATING things only: 1 = raised (menu / snackbar) - 2 = modal / hero (dialog - Now-Playing cover). The surface TINT ramp (base -> surface -> elevated) carries elevation for everything resting on the page. (Pure-black shadows; a future tweak could soften them on the light Papyrus theme.) */
}

/* ===== THEMES: each is a FULL EXPLICIT palette (no derivation); a [data-theme] block sets all its own colour tokens.
   Set data-theme on <html> to switch (Settings → Theme persists it). Default = Midnight (the :root palette above). ===== */
[data-theme="forest"]{   /* FULL explicit palette dialed in via the D6 generator: green-black ground · sage action · gilt · BLUE success (kept distinct from the green action) */
  --base:rgba(9, 15, 9, 1); --base-surface:rgba(22, 29, 22, 1); --base-elevated:rgba(31, 38, 31, 1); --base-outline:rgba(56, 63, 56, 1); --base-outline-strong:rgba(72, 80, 72, 1);
  --base-on-surface:rgba(222, 232, 222, 1); --base-on-surface-variant:rgba(171, 180, 171, 1); --base-on-surface-faint:rgba(127, 135, 126, 1);
  --snackbar-surface:rgba(56, 63, 56, 1); --dialog-surface:rgba(31, 38, 31, 1); --banner-surface:rgba(22, 29, 22, 1); --chip-border:rgba(77, 108, 78, 1); --bar-track:rgba(72, 80, 72, 1);
  --action:rgba(116, 155, 117, 1); --action-soft:rgba(14, 43, 16, 1); --action-selected:rgba(34, 64, 36, 1); --action-outline:rgba(55, 86, 57, 1); --action-bright:rgba(116, 155, 117, 1);
  --accent:rgba(192, 165, 90, 1); --success:rgba(102, 198, 254, 1); --danger:rgba(217, 137, 125, 1); --bookshelf:rgba(243, 196, 60, 1); --warning:rgba(216, 148, 71, 1);
}
[data-theme="rose"]{   /* FULL explicit palette dialed in via the D6 generator: wine ground · rose action · cyan accent · FLAT bg (prototype.js TROVE_THEMES.rose.flat) */
  --base:rgba(18, 11, 13, 1); --base-surface:rgba(32, 24, 26, 1); --base-elevated:rgba(42, 33, 36, 1); --base-outline:rgba(67, 58, 61, 1); --base-outline-strong:rgba(84, 74, 77, 1);
  --base-on-surface:rgba(237, 225, 228, 1); --base-on-surface-variant:rgba(185, 174, 177, 1); --base-on-surface-faint:rgba(139, 129, 132, 1);
  --snackbar-surface:rgba(67, 58, 61, 1); --dialog-surface:rgba(42, 33, 36, 1); --banner-surface:rgba(32, 24, 26, 1); --chip-border:rgba(145, 72, 97, 1); --bar-track:rgba(84, 74, 77, 1);
  --action:rgba(211, 90, 133, 1); --action-soft:rgba(78, 34, 49, 1); --action-selected:rgba(95, 27, 54, 1); --action-outline:rgba(126, 55, 80, 1); --action-bright:rgba(211, 90, 133, 1);
  --accent:rgba(31, 186, 220, 1); --success:rgba(143, 206, 132, 1); --danger:rgba(248, 113, 105, 1); --bookshelf:rgba(243, 196, 60, 1); --warning:rgba(216, 148, 71, 1);
}
[data-theme="papyrus"]{   /* LIGHT theme: cream parchment · deep-green action · sienna accent. prototype.js sets data-mode=light (drives the light-only rules). */
  --base:rgba(247, 242, 228, 1); --base-surface:rgba(233, 228, 215, 1); --base-elevated:rgba(220, 215, 202, 1); --base-outline:rgba(169, 164, 151, 1); --base-outline-strong:rgba(182, 177, 164, 1);
  --base-on-surface:rgba(25, 22, 12, 1); --base-on-surface-variant:rgba(76, 71, 60, 1); --base-on-surface-faint:rgba(105, 100, 89, 1);
  --snackbar-surface:rgba(251, 248, 241, 1); --dialog-surface:rgba(251, 248, 241, 1); --banner-surface:rgba(251, 248, 241, 1); --chip-border:rgba(87, 117, 82, 1); --bar-track:rgba(216, 213, 205, 1);
  --action:rgba(78, 109, 73, 1); --action-soft:rgba(202, 237, 196, 1); --action-selected:rgba(138, 171, 133, 1); --action-outline:rgba(78, 109, 73, 1); --action-bright:rgba(78, 109, 73, 1);
  --accent:rgba(149, 84, 53, 1); --success:rgba(30, 126, 8, 1); --danger:rgba(155, 78, 74, 1); --bookshelf:rgba(184, 104, 65, 1); --warning:rgba(183, 107, 0, 1);
}
[data-theme="obsidian"]{   /* neutral charcoal-black ground · soft periwinkle action · gold accent (ported from the canonical "obsidian") */
  --base:rgba(22, 22, 27, 1); --base-surface:rgba(32, 32, 39, 1); --base-elevated:rgba(42, 42, 51, 1); --base-outline:rgba(56, 56, 63, 1); --base-outline-strong:rgba(70, 70, 77, 1);
  --base-on-surface:rgba(238, 235, 229, 1); --base-on-surface-variant:rgba(169, 167, 175, 1); --base-on-surface-faint:rgba(143, 141, 149, 1);
  --snackbar-surface:rgba(56, 56, 63, 1); --dialog-surface:rgba(42, 42, 51, 1); --banner-surface:rgba(32, 32, 39, 1); --chip-border:rgba(88, 96, 140, 1); --bar-track:rgba(70, 70, 77, 1);
  --action:rgba(143, 157, 226, 1); --action-soft:rgba(36, 40, 64, 1); --action-selected:rgba(50, 56, 92, 1); --action-outline:rgba(72, 80, 124, 1); --action-bright:rgba(143, 157, 226, 1);
  --accent:rgba(217, 197, 140, 1); --success:rgba(135, 193, 143, 1); --danger:rgba(222, 135, 117, 1); --bookshelf:rgba(243, 196, 60, 1); --warning:rgba(216, 148, 71, 1);
}
[data-theme="trove"]{   /* BRAND theme from the Trove app-icon: deep teal-green ground, teal action (brighter --action-bright for play/CTA), brand gold accent. APPROVED principal 2026-06-28. */
  --base:rgba(5, 14, 17, 1); --base-surface:rgba(15, 26, 32, 1); --base-elevated:rgba(26, 49, 60, 1); --base-outline:rgba(55, 62, 64, 1); --base-outline-strong:rgba(70, 77, 79, 1);
  --base-on-surface:rgba(224, 231, 233, 1); --base-on-surface-variant:rgba(165, 177, 181, 1); --base-on-surface-faint:rgba(112, 132, 138, 1);
  --snackbar-surface:rgba(55, 62, 64, 1); --dialog-surface:rgba(33, 39, 42, 1); --banner-surface:rgba(25, 32, 34, 1); --chip-border:rgba(56, 107, 122, 1); --bar-track:rgba(70, 77, 79, 1);
  --action:rgba(19, 146, 158, 1); --action-soft:rgba(0, 35, 44, 1); --action-selected:rgba(7, 52, 63, 1); --action-outline:rgba(39, 83, 96, 1); --action-bright:rgba(65, 176, 188, 1);
  --accent:rgba(194, 159, 94, 1); --success:rgba(134, 208, 133, 1); --danger:rgba(214, 130, 118, 1); --bookshelf:rgba(228, 188, 96, 1); --warning:rgba(206, 150, 90, 1);
}

/* ===== SCAFFOLD (Layer 4): page & sheet structure ========================== */
.tc-screen{display:flex;flex-direction:column;min-height:0;height:100%;background:linear-gradient(to bottom,var(--base-surface),var(--base));color:var(--base-on-surface);padding-top:8px}
[data-flat] .tc-screen{background:var(--base)}   /* THEME FLAG: flat-background themes drop the page gradient (set data-flat on <html>) */
.tc-appbar{flex:0 0 auto;display:flex;align-items:center;gap:8px;min-height:var(--appbar-h);padding:0 var(--page-gutter)}
.tc-appbar__title{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}  /* single line; long titles ellipsize instead of sliding under the trailing buttons */
.tc-appbar__title:not(:first-child){padding-left:8px}  /* breathing room when a leading (back) button precedes the title; primary pages (title first) sit at the gutter */
.tc-iconbtn[hidden] + .tc-appbar__title{padding-left:0}  /* but a HIDDEN leading button (e.g. Library back at L1) shouldn't push the title. It's display:none yet still :first-child, so reset to flush-left */
.tc-appbar__center{flex:1;min-width:0;display:flex;align-items:center;justify-content:center}  /* centered slot (title or chip/tag) between equal-width end buttons */
/* OFFLINE INDICATOR: a quiet, app-wide connectivity marker that lives IN the app bar (fixed height, so it never reflows
   content) and appears ONLY while the device is offline. Icon + "Offline", calm amber, no dismiss. Global chrome, present
   on every app-bar screen (Now Playing is the exception: it carries its own connection tag). Driven by the app's global
   connectivity state; in the prototype, html[data-state="offline"] (injected into every app bar by prototype.js). Its
   point-of-action partner is the Download control, which queues on tap while offline and starts on reconnect. Approved
   principal 2026-07-09. */
.tc-offline{display:none;align-items:center;gap:5px;height:28px;padding:0 10px;border-radius:999px;background:color-mix(in srgb,var(--warning) 13%,transparent);color:var(--base-on-surface-variant);font-size:12px;font-weight:600;flex:0 0 auto;white-space:nowrap}
.tc-offline i{color:var(--warning);font-size:16px}
html[data-state="offline"] .tc-offline{display:inline-flex}
.tc-screen__body{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:var(--section-gap);padding-block:var(--block-gap);padding-inline:var(--page-gutter)}  /* scrollable body region. Name avoids .tc-body (type) + .tc-content (row text) collisions */
.tc-screen__body--center{max-width:var(--content-max);margin-inline:auto;width:100%}
.tc-screen__body--tight{gap:var(--section-gap-tight)}   /* DENSE screens (Settings, Downloads, list-heavy): tighter 16px section rhythm. The section headers carry the extra separation */
.tc-sheet{background:var(--base-elevated);border-top-left-radius:var(--sheet-radius);border-top-right-radius:var(--sheet-radius);padding-inline:var(--page-gutter);padding-bottom:calc(var(--inset-bottom) + 12px)}   /* clears the home indicator / bottom safe area */
.tc-sheet__grabber{width:var(--sheet-grabber);height:4px;border-radius:var(--r-pill);background:var(--base-outline-strong);margin:10px auto 6px}

/* ===== BASE / shared interaction model ====================================== */
.tc-root{background:#0a0a0a;color:var(--base-on-surface);font-family:var(--font-body)}   /* intentional fixed near-black ground (NOT a theme token), sits behind the themed surfaces */
[class^="tc-"]:focus-visible,[class*=" tc-"]:focus-visible{outline:2px solid var(--action);outline-offset:2px}
.tc-disabled,[disabled]{opacity:var(--disabled-op);pointer-events:none}
/* press feedback = iOS-dim, NO scale (decisions §13). EVERY control dims on press. Rows/menu-items HIGHLIGHT instead
   (in their blocks). Listed centrally so a new primitive can't silently miss the press state again. */
.tc-btn,.tc-iconbtn,.tc-link,.tc-chip,.tc-seg button,.tc-switch,.tc-stepper button,
.tc-transport .tc-play,.tc-seek,.tc-chapnav,.tc-tile,.tc-press{transition:opacity var(--ref-dur-press)}
.tc-btn:active,.tc-iconbtn:active,.tc-link:active,.tc-chip:active,.tc-seg button:active,
.tc-switch:active,.tc-stepper button:active,.tc-transport .tc-play:active,.tc-seek:active,.tc-chapnav:active,.tc-tile:active,
.tc-press:active{opacity:var(--press-op)}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* LOADING / BUFFERING: the calm pulsing three-dots (canonical .ld-dots). currentColor, adopts the host's ink.
   Global reduced-motion rule above disables the animation (dots rest legibly). */
.tc-dots{display:inline-flex;gap:5px;align-items:center}
.tc-dots i{width:6px;height:6px;border-radius:50%;background:currentColor;animation:tc-dotpulse 1s ease-in-out infinite}
.tc-dots i:nth-child(2){animation-delay:.15s}
.tc-dots i:nth-child(3){animation-delay:.3s}
@keyframes tc-dotpulse{0%,72%,100%{opacity:.3;transform:translateY(0)}36%{opacity:1;transform:translateY(-2px)}}

/* ===== BUTTON  →  TroveButton(variant, intent, size, iconLayout, fullWidth) === */
.tc-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;font-family:var(--font-label);
  font-size:15px;font-weight:600;line-height:1;border-radius:var(--r-button);min-height:var(--h-control);
  padding:0 20px;border:1px solid transparent;background:none;color:var(--base-on-surface);cursor:pointer;position:relative;transition:opacity var(--ref-dur-press)}
.tc-btn--primary{background:linear-gradient(90deg,var(--action-bright),var(--action));color:var(--base)}   /* horizontal action gradient (--action-bright → --action), system-wide; label/icon in --base (cutout, like the transport glyph) */
[data-mode="light"] .tc-btn--primary,[data-mode="light"] .tc-transport .tc-play{background:var(--action)}   /* THEME FLAG: LIGHT themes drop the button gradient → flat --action */
.tc-btn--secondary{background:var(--action-soft);color:var(--base-on-surface)}
.tc-btn--tertiary{background:none;color:var(--accent);padding:0 12px}
.tc-btn--destructive{background:var(--danger);color:var(--base);border-color:transparent}   /* destructive-dialog primary action: tc-btn--primary treatment with a --danger FILL · --base text · no border */
.tc-btn--outline{background:none;color:var(--action);border-color:var(--action-outline)}   /* dialog "Cancel" + conflict-picker choices: bordered (--action-outline) · no fill · --action text */
.tc-btn--sm{min-height:var(--h-compact);font-size:13.5px;padding:0 14px}
.tc-btn--lg{min-height:var(--h-prominent);font-size:16px;padding:0 26px}
.tc-btn--block{display:flex;width:100%}
.tc-btn .tc-ic{font-size:18px}
.tc-btn--lead{padding-left:14px}                 /* leading slot filled → tighter that side */
.tc-btn--trail{padding-right:14px}               /* trailing slot filled → tighter that side */
.tc-btn--stacked{flex-direction:column;justify-content:center;text-align:center;gap:4px;height:64px;min-width:96px;font-size:12.5px;padding:4px 12px}  /* FIXED height. A subtext squeezes in, never grows the button/row; contents vertically + horizontally centred (incl. wrapping labels) */
.tc-btn--stacked .tc-ic{font-size:20px;color:var(--base-on-surface-variant)}
.tc-btn--stacked.tc-on .tc-ic{color:inherit}   /* active stacked button colours the ICON too. It follows the button's set colour (Remove-from-Bookshelf, Finished, …) */
.tc-btn--stacked .tc-sub{font-size:10px;font-weight:500;line-height:1.1;color:var(--base-on-surface-faint)}  /* optional subtext row (e.g. download size/progress), squeezes into the fixed height, never grows it */
.tc-btn--stacked .tc-val{font-size:15px;font-weight:700;line-height:20px;color:var(--base-on-surface)}  /* value slot (e.g. speed 1.25×) in place of the icon */
/* ACTIVE state-button colouring rule (icon + label, never icon alone): set the button's `color` to the state's
   themed token and use an SVG icon (.tc-fic = currentColor) so BOTH the glyph and the label take the colour. The
   colour is per-state semantic, NOT --action. Bookshelf "on" = var(--bookshelf); Downloaded = var(--success). */
/* CONTROL / ACTION BAR: a row of stacked buttons bound in one surface card; hit targets tile the whole card */
.tc-btnbar{display:flex;align-items:stretch;background:var(--base-surface);border:1px solid var(--base-outline);border-radius:var(--r-container);overflow:hidden}
.tc-btnbar > .tc-btn{flex:1;min-width:0;height:72px;border-radius:0}
.tc-btnbar--divided > .tc-btn + .tc-btn{border-left:1px solid var(--base-outline)}  /* vertical divider lines, PROP: on for Book-Detail actions, off for NP controls */
/* loading state: calm dots replace the label/icon (the hidden label still reserves the button's width) */
.tc-btn--loading{pointer-events:none;color:transparent}
.tc-btn--loading .tc-ic,.tc-btn--loading .tc-fic{visibility:hidden}
.tc-btn--loading .tc-dots{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%)}
.tc-btn--primary.tc-btn--loading .tc-dots{color:var(--base-on-surface)}
.tc-btn--secondary.tc-btn--loading .tc-dots,.tc-btn--destructive.tc-btn--loading .tc-dots{color:var(--base-on-surface)}
.tc-btn--tertiary.tc-btn--loading .tc-dots{color:var(--accent)}

/* ===== ICON BUTTON  →  TroveIconButton(treatment, size, icon) ================= */
.tc-iconbtn{display:inline-flex;align-items:center;justify-content:center;width:var(--h-control);height:var(--h-control);
  border-radius:var(--r-pill);border:none;background:none;color:var(--base-on-surface-variant);font-size:21px;cursor:pointer}
.tc-iconbtn--filled,.tc-appbar .tc-iconbtn{background:var(--base-surface);border:1px solid var(--base-outline-strong);color:var(--base-on-surface)}   /* app-bar icon buttons are ALWAYS filled (no bare variant in the app bar) */
.tc-iconbtn--sm{width:var(--h-compact);height:var(--h-compact);font-size:18px}

/* ===== LINK  →  TroveLink  (navigational / in-prose only) ==================== */
.tc-link{color:var(--accent);font-family:var(--font-label);font-weight:600;font-size:14px;cursor:pointer;text-decoration:none}
.tc-link--prose{text-decoration:underline;text-underline-offset:2px;text-decoration-thickness:1.5px}  /* in running text: underline is the non-colour cue (WCAG 1.4.1); inherits the link colour */
.tc-link--standalone{display:inline-flex;align-items:center;min-height:44px}   /* hit band when not in running text */

/* ===== CHIP  →  TroveChip(type=filter|input, selected, onRemove) ============= */
.tc-chip{display:inline-flex;align-items:center;gap:7px;background:var(--base-surface);border:1px solid var(--base-outline-strong);
  color:var(--base-on-surface-variant);font-family:var(--font-label);font-size:13.5px;font-weight:500;min-height:34px;
  padding:0 16px;border-radius:var(--r-pill);cursor:pointer}
/* ACTIVE/selected chip: --action-selected fill · --action border · on-surface text (used by filter chips AND the view-selector pivots, which are now chips) */
.tc-chip.tc-on{background:var(--action-selected);border-color:var(--chip-border);color:var(--base-on-surface)}   /* border = --chip-border (its own per-theme token; was action-selected +0.16 L) */
.tc-chip .tc-ic{font-size:16px}                  /* chip-icon LOCKED 16px */
.tc-chip--lead{padding-left:10px}                /* leading slot filled */
.tc-chip--input{padding-right:10px}              /* trailing remove slot filled */
.tc-chip .tc-x{display:inline-flex;color:var(--base-on-surface-faint)}

/* ===== VIEW SELECTOR: a single-select CHIP rail (the Library pivots). Items are tc-chip; the rail scrolls.
   tc-pill was MERGED into tc-chip (principal 2026-06-24, same component). The single-vs-multi select is a behaviour
   of the group (view-selector = single/radio; filter rail = multi/toggle), not a separate visual primitive. ===== */
.tc-viewsel{display:flex;gap:8px;overflow-x:auto;-webkit-overflow-scrolling:touch;padding-bottom:6px}
.tc-viewsel .tc-chip{flex:0 0 auto}   /* chips don't shrink in the scroll rail */

/* ===== RAIL  →  horizontal side-scrolling row of chips/pills (genres, filters) ==
   Single line, NEVER wraps. A long set SCROLLS instead of pushing content below it down. Same mechanism as
   ViewSelector. Bleed it to the screen edges (negative margin) so cut-off items hint at the scroll. */
.tc-rail{display:flex;gap:8px;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.tc-rail::-webkit-scrollbar{display:none}
.tc-rail > *{flex:0 0 auto}

/* ===== SEGMENTED  →  TroveSegmented(options, selected) ======================= */
.tc-seg{display:inline-flex;background:var(--base-surface);border:1px solid var(--base-outline);border-radius:var(--r-control);padding:3px;gap:3px}
.tc-seg button{border:none;background:none;color:var(--base-on-surface-variant);font:inherit;font-family:var(--font-label);
  font-size:13px;font-weight:600;padding:9px 14px;border-radius:calc(var(--r-control) - 3px);min-height:44px;cursor:pointer}
.tc-seg button.tc-on{background:var(--action-selected);color:var(--base-on-surface)}

/* ===== SWITCH  →  TroveSwitch(checked) ====================================== */
.tc-switch{width:46px;height:28px;border-radius:var(--r-pill);background:var(--base-outline-strong);position:relative;cursor:pointer;flex:0 0 auto}
.tc-switch i{position:absolute;top:3px;left:3px;width:22px;height:22px;border-radius:50%;background:var(--base-on-surface-faint);transition:var(--ref-dur-press)}
.tc-switch--on{background:var(--action)}
.tc-switch--on i{left:21px;background:var(--base-on-surface)}

/* ===== SLIDER / SCRUBBER  →  TroveSlider / TroveScrubber ===================== */
.tc-slider{height:44px;display:flex;align-items:center}
.tc-slider .tc-track{height:4px;border-radius:var(--r-pill);background:var(--base-outline-strong);width:100%;position:relative}
.tc-slider .tc-fill{position:absolute;left:0;top:0;bottom:0;background:var(--action);border-radius:var(--r-pill)}
.tc-slider .tc-thumb{position:absolute;top:50%;transform:translate(-50%,-50%);width:18px;height:18px;border-radius:50%;background:var(--action)}
.tc-scrubber .tc-fill,.tc-scrubber .tc-thumb{background:var(--accent)}

/* ===== STEPPER  →  TroveStepper ============================================= */
.tc-stepper{display:inline-flex;align-items:center;border:1px solid var(--base-outline-strong);border-radius:var(--r-control);overflow:hidden}
.tc-stepper button{border:none;background:var(--base-surface);color:var(--base-on-surface);width:44px;height:44px;font-size:18px;cursor:pointer}
.tc-stepper .tc-val{min-width:56px;align-self:stretch;display:flex;align-items:center;justify-content:center;background:var(--base);font-family:var(--font-label);font-size:14px}   /* number portion sits on --base so it reads distinct from the --base-surface buttons (esp. on a light row) */
/* FIELD: text · search · select (folded from the catalog page-local cx-* 2026-06-26). Fills its container; constrain in layout.
   Text:   <div class="tc-field"><input ...></div>
   Search: <div class="tc-field tc-field--search"><input><button class="tc-field__clear"><i class="ti ti-x"></i></button></div>  (+ tc-field--lead with a tc-field__lead leading icon)
   Select: <button class="tc-field tc-field--select"><span>value</span><i class="ti ti-chevron-right tc-ic"></i></button>  (opens a picker)
   States: focus (action ring) · disabled · tc-field--error. */
.tc-field{position:relative;display:flex;align-items:center;width:100%}
.tc-field input{flex:1;min-width:0;height:var(--h-control);background:var(--base-surface);border:1px solid var(--base-outline-strong);border-radius:var(--r-control);color:var(--base-on-surface);font:inherit;font-size:15px;padding:0 12px}
.tc-field input::placeholder{color:var(--base-on-surface-faint)}
.tc-field input:focus{outline:none;border-color:var(--action);box-shadow:0 0 0 3px var(--action-soft)}
.tc-field input:disabled{opacity:var(--disabled-op);cursor:not-allowed}
.tc-field__lead{position:absolute;left:0;top:0;bottom:0;width:40px;display:flex;align-items:center;justify-content:center;color:var(--base-on-surface-faint);font-size:18px;pointer-events:none}
.tc-field--lead input{padding-left:40px}
.tc-field--search input{padding-right:42px}
.tc-field__clear{position:absolute;right:0;top:0;bottom:0;width:42px;display:flex;align-items:center;justify-content:center;background:none;border:none;color:var(--base-on-surface-faint);cursor:pointer}
.tc-field--error input{border-color:var(--danger)}
.tc-field--error input:focus{border-color:var(--danger);box-shadow:0 0 0 3px color-mix(in srgb,var(--danger) 26%,transparent)}
.tc-field--select{gap:8px;min-height:var(--h-control);padding:0 12px;background:var(--base-surface);border:1px solid var(--base-outline-strong);border-radius:var(--r-control);color:var(--base-on-surface);font:inherit;font-size:14.5px;text-align:left;cursor:pointer}
.tc-field--select > span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tc-field--select .tc-ic{color:var(--base-on-surface-faint);font-size:18px;flex:0 0 auto}
.tc-field--select:focus-visible{outline:none;border-color:var(--action);box-shadow:0 0 0 3px var(--action-soft)}
.tc-field--select:disabled{opacity:var(--disabled-op);cursor:not-allowed}
/* MINI-PLAYER: the persistent now-playing bar (folded from prototype.css 2026-06-26; on every screen except Settings & Now Playing; tap → Now Playing).
   <div class="tc-mini"><span class="tc-mini__prog"><i style="width:%"></i></span><a class="tc-mini__tap" href="now-playing.html"><img class="tc-mini__cover"><div class="tc-mini__text"><div class="tc-mini__title">…</div><div class="tc-mini__sub">…</div></div></a><button class="tc-mini__back">…</button><button class="tc-mini__play">…</button></div> */
.tc-mini{position:relative;flex:0 0 auto;display:flex;align-items:center;gap:11px;min-height:60px;padding:0 12px;background:var(--base-elevated);border-top:1px solid var(--base-outline)}
.tc-mini__prog{position:absolute;top:0;left:0;right:0;height:2px;background:var(--bar-track)}   /* progress over the top border, track = bar-track, fill = accent */
.tc-mini__prog i{display:block;height:100%;background:var(--accent)}
.tc-mini__tap{flex:1;min-width:0;align-self:stretch;display:flex;align-items:center;gap:11px;color:inherit;text-decoration:none;transition:opacity var(--ref-dur-press)}   /* the ONLY navigating part; controls are separate buttons */
.tc-mini__tap:active{opacity:var(--press-op)}
.tc-mini__cover{width:38px;height:38px;border-radius:6px;flex:0 0 auto;object-fit:cover}
.tc-mini__text{flex:1;min-width:0}
.tc-mini__title{font-family:var(--font-label);font-weight:600;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tc-mini__sub{font-size:11.5px;color:var(--base-on-surface-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tc-mini__back,.tc-mini__play{flex:0 0 auto;align-self:stretch;width:44px;display:flex;align-items:center;justify-content:center;background:none;border:none;padding:0;color:var(--base-on-surface);cursor:pointer;transition:opacity var(--ref-dur-press)}   /* full-height tall hit targets */
.tc-mini__back:active,.tc-mini__play:active{opacity:var(--press-op)}
.tc-mini__back svg{width:24px;height:24px}
.tc-mini__play svg{width:28px;height:28px}   /* play/pause is the primary control, larger than back-10 */
/* SCREEN STATE: the ONE empty / error / wait pattern (folded from prototype.css 2026-06-26): centred icon-ring + title + one line + up to 2 actions.
   <div class="tc-state tc-state--empty|--error"><div class="ic"><i class="ti …"></i></div><h3>…</h3><p>…</p><div class="tc-state__actions">…</div></div>
   Hidden by default (display:none). A real screen reveals it (inline display:flex / its own layout); the prototype State picker drives it via [data-state] (prototype.css). empty=--accent · error=--danger · (no modifier = neutral wait). */
.tc-state{flex:1;min-height:0;display:none;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:11px;padding:40px 28px}
.tc-state .ic{width:76px;height:76px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:var(--base-surface);border:1px solid var(--base-outline);color:var(--base-on-surface-faint);font-size:34px}
.tc-state--empty .ic{color:var(--accent);border-color:var(--accent);background:color-mix(in srgb,var(--accent) 13%,var(--base-surface))}
.tc-state--error .ic{color:var(--danger);border-color:var(--danger);background:color-mix(in srgb,var(--danger) 13%,var(--base-surface))}
.tc-state h3{margin:4px 0 0;font-family:var(--font-title);font-weight:600;font-size:18px;color:var(--base-on-surface)}
.tc-state p{margin:0;font-size:13.5px;line-height:1.5;max-width:280px;color:var(--base-on-surface-variant)}
.tc-state__actions{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin-top:6px}
/* STORAGE BAR: a segmented usage bar (folded from downloads 2026-06-26; device storage breakdown. The track is the "free" remainder, the segments are the used portions). */
.tc-storagebar{height:10px;border-radius:99px;background:var(--bar-track);overflow:hidden;display:flex}
.tc-storagebar > i{height:100%}
.tc-storagebar .seg-other{background:var(--base-on-surface-faint)}
.tc-storagebar .seg-trove{background:var(--bookshelf)}
/* BANNER: a persistent inline notification card (folded from notifications-2 2026-06-26; distinct from snackbar + dialog): leading state icon + title + sub. Tone modifiers recolour the ICON only. The exception is --accent (below), an accent-forward emphasis variant that also tints the ground + border.
   <div class="tc-banner tc-banner--ok|warn|err|info|accent"><i class="ti … ic"></i><div><div class="tc-banner__title">…</div><div class="tc-banner__sub">…</div></div></div> */
/* INVERSE surface (the snackbar's inverse: --base-on-surface ground + --base text) so a notice POPS off the screen instead of blending into it (UX/principal 2026-07-19; folded from the message-surfaces demo 2026-08-04). The --accent variant below opts back out to its accent-tinted ground. */
.tc-banner{display:flex;align-items:flex-start;gap:12px;background:var(--base-on-surface);border:1px solid transparent;border-radius:var(--r-container);padding:13px var(--overlay-gutter);box-shadow:var(--shadow-1)}
.tc-banner .ic{flex:0 0 auto;font-size:21px;line-height:1.05}
.tc-banner__title{font-weight:600;font-size:14px;color:var(--base)}
.tc-banner__sub{font-size:12.5px;line-height:1.45;color:color-mix(in srgb,var(--base) 66%,transparent);margin-top:2px}
/* tone icons darkened theme-safely so they read on the light inverse ground */
.tc-banner--ok .ic{color:color-mix(in srgb,var(--success) 70%,#000)}
.tc-banner--warn .ic{color:color-mix(in srgb,var(--warning) 76%,#000)}
.tc-banner--err .ic{color:color-mix(in srgb,var(--danger) 90%,#000)}
.tc-banner--info .ic{color:color-mix(in srgb,var(--action) 82%,#000)}
/* ACCENT: an emphasis banner for a ONE-TIME affordance (e.g. the first-run "add your audiobooks" nudge). Leans into --accent: a tinted ground + an accent border + accent icon — but the TITLE stays normal (--base-on-surface) so it reads calm, not shouty. Primary action = tc-btn--tertiary (accent); a dismiss = tc-btn--tertiary in --base-on-surface-variant. (principal 2026-07-12) */
.tc-banner--accent{background:color-mix(in srgb,var(--accent) 18%,var(--base-surface));border-color:color-mix(in srgb,var(--accent) 45%,transparent);box-shadow:none}
.tc-banner--accent .ic{color:var(--accent)}
.tc-banner--accent .tc-banner__title{color:var(--base-on-surface)}
.tc-banner--accent .tc-banner__sub{color:var(--base-on-surface-variant)}
/* LIST COUNT: the standard total-count subheader for a plain list screen: a thin muted strip PINNED at the top (direct child of .tc-screen, below the app bar, above the scrolling body) so it stays visible no matter how long the list is. A bottom count gets pushed off-screen. Hidden with the body in the empty state. */
.tc-listcount{flex:0 0 auto;padding:2px var(--page-gutter) 0;font-family:var(--font-label);font-size:12.5px;color:var(--base-on-surface-faint)}
/* NO-RESULTS: the LIGHTWEIGHT counterpart to tc-state: a screen that HAS content but a filter/narrowing matched nothing right now (the controls stay visible above to adjust). Just a muted centred line, no icon, no actions (unlike the full tc-state empty). e.g. Library genre/status filter with no matches. */
.tc-noresults{padding:36px var(--page-gutter);text-align:center;font-size:13.5px;color:var(--base-on-surface-faint)}

/* ===== MEDIA TRANSPORT  →  TroveTransport  (CUSTOM Trove shapes) ============== */
.tc-transport{display:flex;align-items:center;justify-content:center;gap:18px}
.tc-transport>button{flex:0 0 auto}   /* never shrink: keeps the circular controls from distorting on narrow widths */
.tc-transport .tc-play{width:76px;height:76px;border-radius:50%;border:none;background:linear-gradient(90deg,var(--action-bright),var(--action));color:var(--base);
  display:flex;align-items:center;justify-content:center;cursor:pointer}   /* action gradient fill, system-wide; bars/triangle + dots are --base cutouts */
.tc-play .tc-bars{display:flex;gap:8px;align-items:center}
.tc-play .tc-bars span{display:block;width:7px;height:28px;border-radius:4px;background:var(--base)}
.tc-play .tc-tri{width:0;height:0;border-style:solid;border-width:15px 0 15px 25px;border-color:transparent transparent transparent var(--base);margin-left:5px;display:none}
.tc-play.tc-paused .tc-bars{display:none}
.tc-play.tc-paused .tc-tri{display:block}
/* buffering state: bars/tri hidden, the calm dots show (same loader as buttons) */
.tc-play .tc-dots{display:none}
.tc-play.tc-buffering .tc-bars,.tc-play.tc-buffering .tc-tri{display:none}
.tc-play.tc-buffering .tc-dots{display:inline-flex;color:var(--base)}   /* match the play/pause shapes (--base cutout), not white */
.tc-seek{display:flex;flex-direction:column;align-items:center;justify-content:center;background:none;border:none;
  color:var(--base-on-surface);cursor:pointer;padding:6px;min-height:48px}
.tc-seek svg{width:34px;height:34px}
.tc-chapnav{width:48px;height:48px;border-radius:50%;border:none;background:none;color:var(--base-on-surface-variant);
  display:flex;align-items:center;justify-content:center;font-size:22px;cursor:pointer}

/* ===== MENU  →  TroveMenu + TroveMenuItem ==================================== */
.tc-menu{min-width:220px;background:var(--base-elevated);border:1px solid var(--base-outline-strong);border-radius:var(--r-container);
  padding:6px;box-shadow:var(--shadow-1)}
.tc-menu .tc-mi{display:flex;align-items:center;gap:12px;width:100%;min-height:48px;padding:0 12px;border-radius:var(--r-control);
  background:none;border:none;text-align:left;text-decoration:none;color:var(--base-on-surface);font-family:var(--font-label);font-size:14.5px;cursor:pointer}   /* works as a <button> or <a> too (reset baked in) */
.tc-menu .tc-mi:active{background:var(--row-highlight)}
.tc-menu .tc-mi[disabled]{opacity:var(--disabled-op);pointer-events:none}
.tc-menu .tc-mi .tc-ic{font-size:19px;color:var(--base-on-surface-variant)}
.tc-menu .tc-mi .tc-fic{width:20px;height:20px;flex:0 0 auto;color:var(--base-on-surface-variant)}   /* SVG icon (e.g. filled play) sized like the font icon */
/* MENU in a SHEET, flush variant: the sheet IS the surface, so drop the popup card chrome.
   Use as <div class="tc-menu tc-menu--flush"> inside a tc-sheet. Optional separator line between groups: tc-menu__sep. */
.tc-menu--flush{min-width:0;background:none;border:none;border-radius:0;padding:0;box-shadow:none}
.tc-menu--flush .tc-mi{padding:0 6px;min-height:50px}
.tc-menu__sep{height:1px;background:var(--base-outline);margin:6px 0}

/* ===== OVERLAYS  →  scrim · dialog · snackbar  (Layer 3; Material 3-grounded) ===== */
.tc-scrim{position:absolute;inset:0;background:var(--scrim)}   /* dim backdrop behind modals (sheet / dialog / menu) */
.tc-dialog{background:var(--dialog-surface);border:1px solid var(--base-outline);border-radius:var(--r-container);padding:20px;max-width:320px;box-shadow:var(--shadow-2)}   /* 20px all round (= --ref-s-5) */
.tc-dialog--wide{max-width:none}   /* full-width dialog (e.g. sync-conflict / notification dialogs) */
.tc-dialog__title{margin:0 0 8px}     /* type via .tc-title */
.tc-dialog__body{margin:0}            /* type via .tc-body */
.tc-dialog__actions{display:flex;justify-content:space-between;gap:8px;margin-top:22px}   /* Cancel (left) · confirm (right) */
/* sync-conflict dialog (R-rule surface: surface BOTH positions, user picks; never auto-resolve) */
.tc-dialog--conf .tc-dialog__warn{display:flex;align-items:center;gap:7px;color:var(--warning);font-size:12.5px;font-weight:600;line-height:1.35;margin:4px 0 13px}
.tc-dialog--conf .tc-dialog__warn i{flex:0 0 auto;font-size:16px}
.tc-dialog--conf .tc-dialog__opts{display:flex;flex-direction:column;gap:9px}
.tc-dialog--conf .tc-dialog__opts .tc-btn{justify-content:space-between}
.tc-dialog--conf .tc-dialog__when{font-variant-numeric:tabular-nums;font-weight:500;opacity:.85}
/* OVERLAY: the modal container for sheets + dialogs (relocated from prototype.css 2026-06-26, the dev references this, not the mockup chrome). Covers its positioned ancestor; JS toggles .open. Scrim fades; sheet slides up; dialog pops centered, all on the motion tokens, with the enter/exit asymmetry. (Reduced-motion is handled by the global kill above.) */
.tc-overlay{position:absolute;inset:0;z-index:30;display:none}
.tc-overlay.open{display:block}
.tc-overlay .tc-scrim{opacity:0;transition:opacity var(--ref-dur)}
.tc-overlay.open .tc-scrim{opacity:1}
.tc-overlay .tc-sheet{position:absolute;left:0;right:0;bottom:0;max-height:86%;display:flex;flex-direction:column;transform:translateY(101%);transition:transform var(--ref-dur) var(--ref-ease-exit)}   /* closed = exit timing */
.tc-overlay.open .tc-sheet{transform:translateY(0);transition:transform var(--ref-dur-enter) var(--ref-ease-enter)}   /* open = enter timing */
.tc-overlay .tc-dialog{position:absolute;top:50%;left:50%;width:calc(100% - 2*var(--page-gutter));transform:translate(-50%,-50%) scale(.96);opacity:0;transition:transform var(--ref-dur) var(--ref-ease-exit),opacity var(--ref-dur)}   /* dialogs pop dead-center, both axes */
.tc-overlay.open .tc-dialog{transform:translate(-50%,-50%) scale(1);opacity:1;transition:transform var(--ref-dur-enter) var(--ref-ease-enter),opacity var(--ref-dur-enter)}
/* sheet content structure, every sheet: a pinned head + a scrollable body */
.tc-sheet__body{display:flex;flex-direction:column;gap:var(--ref-s-4)}
.tc-sheet__head{display:flex;align-items:center;justify-content:space-between}
.tc-sheet__scroll{flex:1;min-height:0;overflow-y:auto;margin:0 calc(-1 * var(--page-gutter));padding:0 var(--page-gutter)}
/* SPIN: loading-interstitial utility (e.g. ti-loader-2 on the connect wait screens) */
@keyframes tc-spin{to{transform:rotate(360deg)}}
.tc-spin{animation:tc-spin 1s linear infinite}
/* ONE component, two configs: BRIEF = no __action (auto-dismiss confirmation pill); WITH __action = e.g. Undo / Retry.
   NOTE: this is a STYLED IN-APP Snackbar (Material Snackbar/SnackbarHost), NOT an Android Toast. OS Toasts aren't
   themeable (Toast.setView() deprecated API 30+, custom views blocked from background), so even the no-action pill is a Snackbar. */
/* Material 3 snackbar (principal 2026-07-10): the platform M3 look, uniform app-wide. INVERSE surface (light in dark
   themes, dark in Papyrus), single line, action pinned far-right, NO border, elevation. The inverse = --base-on-surface bg
   + --base text (mode-aware, so it flips correctly per theme with NO new tokens). Hosted in a top-center Popup so it can sit
   ABOVE an open modal (e.g. the Bookmarks sheet). Supersedes the old custom dark pill; --snackbar-surface is now unused
   (deprecated, kept to avoid a 6-theme token churn). NOTE: on Papyrus (the one light theme) the inverse pill is dark, so
   verify the --action label contrast there; on the 5 dark themes the inverse is light and --action reads well. */
.tc-snackbar{display:flex;align-items:center;gap:12px;min-height:48px;background:var(--base-on-surface);border:none;
  border-radius:var(--r-control);padding:12px var(--overlay-gutter);box-shadow:var(--shadow-1)}
.tc-snackbar__text{flex:1;min-width:0;font-family:var(--font-body);font-size:14px;color:var(--base)}
.tc-snackbar__action{flex:0 0 auto;background:none;border:none;color:var(--action);font-family:var(--font-label);font-weight:600;font-size:14px;padding:6px 8px;cursor:pointer;transition:opacity var(--ref-dur-press)}   /* M3 action label pinned far-right (text flex:1 pushes it); --action reads on the light inverse surface */
.tc-snackbar__action:active{opacity:var(--press-op)}

/* ===== ROW / LIST ITEM  →  TroveListItem(leading, content, trailing, mode) === */
.tc-li{display:flex;align-items:center;gap:14px;min-height:var(--h-control);padding:10px 9px;border-radius:var(--r-control);background:var(--base-surface);cursor:pointer}   /* radius 8 (was --r-container 12) + tighter 9px sides, principal 2026-06-27: de-puff the card row */
.tc-li:active{background:var(--row-highlight)}
.tc-li--static{cursor:default}
.tc-li--static:active{background:var(--base-surface)}   /* row is NOT a tap target. An inner control (stepper / switch) handles it; pressing it must not flash the whole row */
.tc-li.tc-on{background:var(--action-selected)}   /* selectable row: SELECTED (single- or multi-select); pair with a check in --action (distinct from .tc-li--chapter.tc-current, which is the playing chapter in --accent) */
.tc-li .tc-lead{width:44px;height:44px;border-radius:4px;background:var(--base-elevated);flex:0 0 auto;display:flex;align-items:center;justify-content:center;color:var(--base-on-surface-faint);font-size:20px}
.tc-li .tc-lead--tint{background:color-mix(in srgb,var(--accent) 14%,var(--base-surface));color:var(--accent)}   /* de-wash the icon tile with a little accent (settings icons), principal 2026-06-27 */
.tc-li .tc-lead--tint-danger{background:color-mix(in srgb,var(--danger) 14%,var(--base-surface));color:var(--danger)}
/* per-category settings-icon tints = the PLACEHOLDER-COVER palette (mirrors .tc-cover--forest/oxblood/indigo/plum/ochre) so settings categories read like little book spines; principal 2026-06-27 */
.tc-li .tc-lead--forest{background:#2e3b27;color:#e7e0c8}
.tc-li .tc-lead--oxblood{background:#5a2e2f;color:#ecdfd0}
.tc-li .tc-lead--indigo{background:#2c3450;color:#e3e2d6}
.tc-li .tc-lead--plum{background:#46324f;color:#ece0ec}
.tc-li .tc-lead--ochre{background:#6e561f;color:#f2e8cf}
.tc-li .tc-content{flex:1;min-width:0}
.tc-li .tc-t{font-family:var(--font-label);font-size:14.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}   /* 1-line ellipsis: match the library list (tc-li--book) so long titles never grow the row; principal 2026-06-27 */
.tc-li .tc-s{font-size:12px;color:var(--base-on-surface-faint);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tc-li .tc-chev{color:var(--base-on-surface-faint);font-size:20px}
.tc-li .tc-grip{flex:0 0 auto;align-self:stretch;display:flex;align-items:center;justify-content:center;width:36px;margin:-10px 0 -10px -6px;color:var(--base-on-surface-faint);font-size:20px;cursor:grab;touch-action:none}   /* drag handle (manual-reorder rows, e.g. Bookshelf): full row-height hit area (≥48dp); drag is NEVER the only reorder path (accessible Move up/Move to top required, PRD §N6) */
/* ListItem, CHAPTER variant: dense divided row · plain numeral lead · duration right · current = accent + play · no card/chevron */
.tc-li--chapter{background:none;border-radius:0;min-height:0;padding:13px 6px;gap:14px;border-bottom:1px solid var(--base-outline)}
.tc-li--chapter:last-child{border-bottom:none}
.tc-li--chapter .tc-num{width:22px;flex:0 0 auto;text-align:center;color:var(--base-on-surface-faint);font-family:var(--font-label);font-size:13px;font-variant-numeric:tabular-nums;line-height:1}
.tc-li--chapter .tc-num .tc-fic{font-size:14px}
.tc-li--chapter .tc-t{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tc-li--chapter .tc-dur{flex:0 0 auto;color:var(--base-on-surface-faint);font-family:var(--font-label);font-size:12.5px;font-variant-numeric:tabular-nums}
.tc-li--chapter.tc-current .tc-num,.tc-li--chapter.tc-current .tc-t,.tc-li--chapter.tc-current .tc-dur{color:var(--accent)}
.tc-li--chapter.tc-current .tc-t{font-weight:600}
/* ListItem, RICH variant: the spacious book card shared by Library's Detailed view + Listen's "Also in progress" (principal
   2026-07-25), so the two cannot drift. A FLOATED square cover with title/author/progress beside it, a series/genre rail,
   and an OPTIONAL full-width description that clears below. Content-hugging (no fixed height): a card is exactly as tall as
   what it holds; a card with no description tucks its rail beside the cover instead of stranding a gap. Built from atoms
   (tc-cover · tc-pbar · tc-tag · tc-rail). The .tc-rich-* bits are hidden unless the row carries --rich, so the same
   BookRow DOM stays compact in List view and expands here. */
.tc-rich-by,.tc-rich-meta,.tc-rich-rail,.tc-rich-desc{display:none}
.tc-li--rich{display:block;padding:16px 2px}
.tc-li--rich::after{content:"";display:table;clear:both}   /* contain the float so the card wraps to content height */
.tc-li--rich .tc-cover{float:left;width:92px;height:92px;border-radius:8px;margin:0 14px 0 0}
.tc-li--rich .tc-s{display:none}   /* the List sort-context line is replaced by the author line here */
.tc-li--rich .tc-rich-by{display:block;font-family:var(--font-label);font-size:13px;color:var(--base-on-surface-variant);margin-top:3px}
.tc-li--rich .tc-rich-meta{display:flex;align-items:center;gap:8px;font-size:11.5px;color:var(--base-on-surface-faint);margin-top:7px}
.tc-li--rich .tc-rich-meta .tc-pbar{width:72px;max-width:72px;margin:0;flex:0 0 auto}
.tc-li--rich .tc-rich-rail{display:flex;margin-top:11px}   /* pair with tc-rail for the horizontal scroll; sits BESIDE the cover under the meta, same spot on every card (matches the Library Detailed card) */
.tc-li--rich .tc-rich-desc{clear:left;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;font-size:13px;line-height:1.5;color:var(--base-on-surface-faint);padding-top:11px}   /* full-width below the cover; padding (not margin) survives the float clearance, and only exists when a description does */

/* ===== BOOK DISPLAY, shared atoms: Cover · BookRow (list) · BookTile (grid) ==
   Same book data, two layouts; only Cover is a new atom (title/author/progress/status reused).
   "Every book is labelled" (decisions §5): a title caption is always present. */
.tc-cover{position:relative;flex:0 0 auto;border-radius:var(--r-control);overflow:hidden;background:var(--base-elevated);container-type:inline-size}  /* audiobook covers are SQUARE (1:1) */
/* DARK-COVER LIFT: a faint white glow separates a cover whose EDGES blend into the dark app background; DARK MODE ONLY. .tc-cover--dark is set by luminance detection: prototype.js (canvas edge-sampling, the demo) -> the real app sets it from the cover Bitmap Palette/edge-luminance (same pipeline as the NP aurora). Threshold tunable. */
html:not([data-mode="light"]) .tc-cover--dark{box-shadow:0 0 2px rgba(255,255,255,.25)}
.tc-cover img{-webkit-user-drag:none}
.tc-tile,.tc-li--book{-webkit-user-drag:none;user-select:none}   /* a press-hold must not start a native drag/selection (would break long-press) */
.tc-cover img{width:100%;height:100%;object-fit:cover;display:block}
.tc-cover--thumb{width:44px;height:44px;border-radius:4px}   /* row thumbnail: 44 (= the icon-lead size) · radius 4 (--ref-r-xs, on-scale), principal 2026-06-27 */
.tc-cover--tile{width:100%;aspect-ratio:1/1}
/* STATE: loading, shimmer skeleton (the global reduced-motion rule disables the animation) */
.tc-cover--loading{background:linear-gradient(100deg,var(--base-elevated) 30%,var(--base-surface) 50%,var(--base-elevated) 70%);background-size:200% 100%;animation:tc-shimmer 1.2s linear infinite}
/* SKELETON - shimmer placeholder for loading TEXT / blocks (covers use .tc-cover--loading; both share @keyframes tc-shimmer). Default = a text line; set width (+ height for blocks) on the element. */
.tc-skeleton{height:13px;border-radius:var(--r-tag);background:linear-gradient(100deg,var(--base-elevated) 30%,var(--base-surface) 50%,var(--base-elevated) 70%);background-size:200% 100%;animation:tc-shimmer 1.2s linear infinite}
@keyframes tc-shimmer{0%{background-position:200% 0}100%{background-position:-200% 0}}
/* STATE: fallback, no/failed art → a generated TYPOGRAPHIC cover, the canonical LISTEN treatment (.bcover):
   a serif title on a tinted field with an inset frame. Each art-less book gets a distinct COLOUR TINT (the real app
   derives it deterministically from the title) so a shelf of cover-less books stays differentiable, not a wall of
   icons. Scales to any cover size via container units (thumb → tile → hero). */
.tc-cover--fallback{display:flex;align-items:center;justify-content:center;text-align:center;background:#efe7d2;color:#22301a}
.tc-cover--fallback::after{content:"";position:absolute;inset:7%;border:1px solid rgba(42,51,31,.26);border-radius:4px;pointer-events:none}
.tc-cover--fallback .tc-fbtitle{font-family:var(--ref-cover);font-variation-settings:'opsz' 144,'wght' 660;line-height:1.04;font-size:14cqw;padding:0 9%;z-index:1;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:5;line-clamp:5;overflow:hidden}
@container (max-width:90px){.tc-cover--fallback .tc-fbtitle{font-size:16cqw;-webkit-line-clamp:4;line-clamp:4;padding:0 6%}}
/* ENTITY-LEAD content inside a tinted fallback cover (the browse/search result row's lead, folded from search/library 2026-06-26): */
.tc-cover--fallback .tc-fbinit{position:relative;z-index:1;font-family:var(--ref-cover);font-weight:600;font-size:30cqw;line-height:1;letter-spacing:.01em}   /* INITIALS: people (author / narrator) */
.tc-cover--fallback .tc-fbicon{position:relative;z-index:1;font-size:24px}   /* category ICON: series / collection */
/* colour tints: each art-less book a distinct colour (default = cream) */
.tc-cover--forest{background:#2e3b27;color:#e7e0c8} .tc-cover--oxblood{background:#5a2e2f;color:#ecdfd0}
.tc-cover--indigo{background:#2c3450;color:#e3e2d6} .tc-cover--plum{background:#46324f;color:#ece0ec} .tc-cover--ochre{background:#6e561f;color:#f2e8cf}
.tc-cover--forest::after,.tc-cover--oxblood::after,.tc-cover--indigo::after,.tc-cover--plum::after,.tc-cover--ochre::after{border-color:rgba(255,255,255,.18)}
/* CORNER treatment (canonical .dlcorner): a triangular wedge in the bottom-right + a white icon. downloaded = green
   wedge + check · unavailable/can't-reach = red wedge + cloud (pair with .tc-cover--unavailable to dim the art). */
.tc-corner{position:absolute;right:0;bottom:0;width:32px;height:32px;z-index:3;pointer-events:none}
.tc-corner::before{content:"";position:absolute;inset:0;clip-path:polygon(100% 0,100% 100%,0 100%);background:rgba(0,0,0,.4)}  /* SEPARATOR: soft dark line along the diagonal */
.tc-corner .tc-w{position:absolute;inset:2px 0 0 2px;clip-path:polygon(100% 0,100% 100%,0 100%)}                     /* the solid colour wedge, inset to reveal the separator */
.tc-corner svg{position:absolute;right:3px;bottom:3px;width:14px;height:14px;filter:drop-shadow(0 0 1px rgba(0,0,0,.45))}
.tc-corner--downloaded svg{right:2px;bottom:2px}   /* down-arrow needs a hair more inset than the other wedge glyphs; scoped so it does not move them, principal 2026-06-28 */
.tc-corner--downloaded .tc-w{background:#5c8a4a}     /* solid muted green */
.tc-corner--unavailable .tc-w{background:#bc5b50}    /* solid muted red */
.tc-corner--unavailable svg{width:12px;height:12px}  /* cloud-off is wider than the check. Keep it inside the wedge */
.tc-cover--thumb .tc-corner{width:22px;height:22px}
.tc-cover--thumb .tc-corner .tc-w{inset:1.5px 0 0 1.5px}
.tc-cover--thumb .tc-corner svg{right:2.5px;bottom:2.5px;width:10px;height:10px}
.tc-cover--thumb .tc-corner--unavailable svg{width:9px;height:9px}
/* OVERLAY: unavailable, phase the ART out (the corner wedge stays crisp) */
.tc-cover--unavailable img{opacity:.4;filter:grayscale(.5)}
/* progress bar atom (small linear; accent = progress): the start of the Layer-2 progress pattern */
.tc-pbar{height:3px;border-radius:var(--r-pill);background:var(--bar-track);position:relative;overflow:hidden;margin-top:7px;max-width:170px}
.tc-pbar i{position:absolute;left:0;top:0;bottom:0;background:var(--accent);border-radius:var(--r-pill)}
.tc-pbar--done i{width:100%;background:var(--success)}   /* FINISHED book: a FULL bar in the success colour (convention: complete reads as done, not a long in-progress bar) */
/* determinate circular RING (e.g. download progress): set --p 0..1 */
.tc-ring{width:20px;height:20px;transform:rotate(-90deg);flex:0 0 auto}
.tc-ring circle{fill:none;stroke-width:3}
.tc-ring .trk{stroke:var(--bar-track)}
.tc-ring .prg{stroke:var(--action);stroke-linecap:round;stroke-dasharray:88;stroke-dashoffset:calc(88 - 88*var(--p,0));transition:stroke-dashoffset var(--ref-dur) var(--ref-ease)}
/* BookRow (list), row family: cover-thumb · title+author(+progress) · trailing downloaded status */
.tc-li--book{background:none;border-radius:0;min-height:0;padding:10px 6px;gap:14px;border-bottom:1px solid var(--base-outline)}
.tc-li--book:last-child{border-bottom:none}
.tc-li--book .tc-t{font-size:14.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* BookTile (grid): cover hero · title caption · author. SAME atoms, vertical layout */
.tc-tile{display:flex;flex-direction:column;gap:7px;cursor:pointer;min-width:0}
.tc-tile .tc-cap{font-family:var(--font-label);font-size:13px;line-height:1.25;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
.tc-tile .tc-by{font-family:var(--font-label);font-size:11.5px;color:var(--base-on-surface-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* ===== TAG / STATUS (non-interactive, NOT a button) ======================= */
.tc-tag{display:inline-flex;align-items:center;gap:5px;background:var(--base-surface);color:var(--base-on-surface-variant);
  font-family:var(--font-label);font-size:11.5px;font-weight:600;padding:4px 9px;border-radius:var(--r-tag)}
.tc-tag i{font-size:13px}
.tc-tag--success{color:var(--success)} .tc-tag--danger{color:var(--danger)}

/* ===== INLINE FILLED ICON (web only, Tabler webfont CDN is outline-only) === */
.tc-fic{width:1em;height:1em;fill:currentColor;display:inline-block;vertical-align:-.14em;flex:0 0 auto}
.tc-btn .tc-fic{font-size:18px}

/* ===== TYPE SCALE (Layer 2): display/headline/title = Lora (serif) · body/label = Hanken (sans).
   Grounded in M3's 5 roles, trimmed for a calm single app; PROPOSED sizes, tune in the catalog specimen.
   Type classes carry font only; colour is applied separately (muted default kept on body/caption for convenience). */
.tc-display{font-family:var(--font-display);font-weight:600;font-size:34px;line-height:1.1}     /* large screen titles (Listen · Library · Bookshelf) */
.tc-headline{font-family:var(--font-headline);font-weight:600;font-size:24px;line-height:1.15}  /* screen titles */
.tc-title-lg{font-family:var(--font-title);font-weight:600;font-size:20px;line-height:1.2}       /* book title (hero) */
.tc-title{font-family:var(--font-title);font-weight:600;font-size:16px;line-height:1.25}         /* section headers, card/dialog titles */
.tc-body{font-family:var(--font-body);font-weight:400;font-size:15px;line-height:1.5;color:var(--base-on-surface-variant)}      /* descriptions */
.tc-body-sm{font-family:var(--font-body);font-weight:400;font-size:13px;line-height:1.45;color:var(--base-on-surface-variant)}  /* secondary text */
.tc-label-lg{font-family:var(--font-label);font-weight:600;font-size:15px;line-height:1}         /* button text */
.tc-label{font-family:var(--font-label);font-weight:500;font-size:13.5px;line-height:1.2}        /* list title · chip · metaLine */
.tc-label-sm{font-family:var(--font-label);font-weight:500;font-size:12px;line-height:1.3;color:var(--base-on-surface-faint)}    /* caption · facts · meta-line */
.tc-value{font-family:var(--font-label);font-weight:600;font-size:24px;line-height:1.1;font-variant-numeric:tabular-nums}  /* large SANS numeric readout (speed/sleep value, durations). The scale's big sizes are serif, wrong for numbers */

/* --- website-only: native page scrollbar (folded in from the old site.css) --- */
/* Restore the NATIVE page scrollbar. trove-core hides ALL scrollbars globally
   (*{scrollbar-width:none}) so the app MOCKUPS read like a phone — wrong for a
   real website. Re-enable it on the document only; the intentional per-component
   hide on .tc-rail (the horizontal book carousel) is left untouched. */
html{scrollbar-width:auto;-ms-overflow-style:auto}
html::-webkit-scrollbar{width:14px;height:14px;display:block}
html::-webkit-scrollbar-thumb{background:var(--outline,#8886);border-radius:8px}
html::-webkit-scrollbar-thumb:hover{background:var(--muted,#8889)}
html::-webkit-scrollbar-track{background:transparent}
