/* =============================================================================
// DESIGN TOKENS
// CSS custom properties for colors, typography, spacing, shadows, and layout.
// ============================================================================= */
:root, [data-theme="light"] {
    --color-bg: #e8e0d0;
    --color-surface: #f5efe3;
    --color-surface-2: #f9f4eb;
    --color-surface-offset: #ddd5c4;
    --color-surface-dynamic: #d4cab8;
    --color-divider: #bdb5a6;
    --color-border: #ada493;
    --color-text: #1e1a14;
    --color-text-muted: #6a6055;
    --color-text-faint: #9a9086;
    --color-text-inverse: #faf8f4;
    --color-primary: #8b5e3c;
    --color-primary-hover: #6e4a2d;
    --color-primary-active: #523620;
    --color-primary-highlight: #e8ddd4;
    --color-banner-highlight: #e2c9ac;
    --color-accent: #c8956c;
    --color-gold: #c9a227;
    --color-plus: #a4763a;
    --color-plus-ink: #2e2413;
    --font-display: 'Cormorant Garamond', Georgia, serif;
    --font-body: 'Inter', system-ui, sans-serif;
    --text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
    --text-sm: clamp(0.875rem, 0.8rem + 0.35vw, 1rem);
    --text-base: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
    --text-lg: clamp(1.125rem, 1rem + 0.75vw, 1.5rem);
    --text-xl: clamp(1.5rem, 1.2rem + 1.25vw, 2.25rem);
    --text-2xl: clamp(2rem, 1.4rem + 2vw, 3rem);
    --text-quote: clamp(1.4rem, 1rem + 2vw, 2.6rem);
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.25rem;
    --space-6: 1.5rem;
    --space-8: 2rem;
    --space-10: 2.5rem;
    --space-12: 3rem;
    --space-16: 4rem;
    --space-20: 5rem;
    --radius-sm: 0.375rem;
    --radius-md: 0.5rem;
    --radius-lg: 0.75rem;
    --radius-xl: 1rem;
    --radius-full: 9999px;
    --shadow-sm: 0 1px 4px oklch(0.2 0.04 50 / 0.10);
    --shadow-md: 0 4px 20px oklch(0.2 0.04 50 / 0.14);
    --shadow-lg: 0 12px 44px oklch(0.2 0.04 50 / 0.18);
    --transition: 180ms cubic-bezier(0.16, 1, 0.3, 1);
    --content-narrow: 640px;
    --content-default: 960px;
    --content-wide: 1200px;
}

[data-theme="dark"] {
    --color-bg: #18160f;
    --color-surface: #1e1c15;
    --color-surface-2: #232119;
    --color-surface-offset: #1a1811;
    --color-surface-dynamic: #2b2820;
    --color-divider: #2e2b22;
    --color-border: #3a3729;
    --color-text: #e8e3d8;
    --color-text-muted: #8a8272;
    --color-text-faint: #5a5446;
    --color-text-inverse: #18160f;
    --color-primary: #d4956a;
    --color-primary-hover: #e8a87a;
    --color-primary-active: #f0b888;
    --color-primary-highlight: #3a2d22;
    --color-banner-highlight: #3a2d22;
    --color-accent: #c8956c;
    --color-gold: #d4a830;
    --color-plus: #c2a878;
    --color-plus-ink: #241f16;
    --shadow-sm: 0 1px 3px oklch(0 0 0 / 0.25);
    --shadow-md: 0 4px 16px oklch(0 0 0 / 0.35);
    --shadow-lg: 0 12px 40px oklch(0 0 0 / 0.45);
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme]) {
        --color-bg: #18160f;
        --color-surface: #1e1c15;
        --color-surface-2: #232119;
        --color-surface-offset: #1a1811;
        --color-surface-dynamic: #2b2820;
        --color-divider: #2e2b22;
        --color-border: #3a3729;
        --color-text: #e8e3d8;
        --color-text-muted: #8a8272;
        --color-text-faint: #5a5446;
        --color-text-inverse: #18160f;
        --color-primary: #d4956a;
        --color-primary-hover: #e8a87a;
        --color-primary-active: #f0b888;
        --color-primary-highlight: #3a2d22;
        --color-banner-highlight: #3a2d22;
        --color-accent: #c8956c;
        --color-gold: #d4a830;
        --shadow-sm: 0 1px 3px oklch(0 0 0/.25);
        --shadow-md: 0 4px 16px oklch(0 0 0/.35);
        --shadow-lg: 0 12px 40px oklch(0 0 0/.45);
    }
}

/* =============================================================================
// THEME STYLES
// Five selectable visual styles (TASK-119), independent of the light/dark
// toggle above. "classic" reuses the default palette already defined in
// :root/[data-theme] — only the other four need overrides here. Typography,
// spacing and radius tokens are intentionally NOT overridden per style, only
// colors — see the [data-theme-style] + [data-theme] compound selectors.
// ============================================================================= */
[data-theme-style="forest"][data-theme="light"] {
    --color-bg: #eef3e6;
    --color-surface: #f7faf1;
    --color-surface-2: #fbfdf7;
    --color-surface-offset: #e2ead6;
    --color-surface-dynamic: #d3e0c2;
    --color-divider: #c4d2b3;
    --color-border: #b0c19c;
    --color-text: #1f2e17;
    --color-text-muted: #5c6e4d;
    --color-text-faint: #8a9a7a;
    --color-text-inverse: #f7faf1;
    --color-primary: #4d7c3f;
    --color-primary-hover: #3d6431;
    --color-primary-active: #2e4d25;
    --color-primary-highlight: #dbe8cd;
    --color-banner-highlight: #cfe0ba;
    --color-accent: #7fa563;
    --color-gold: #a8b23a;
    --color-plus: #7e8a34;
    --color-plus-ink: #1f2e17;
}

[data-theme-style="forest"][data-theme="dark"] {
    --color-bg: #10160d;
    --color-surface: #161d11;
    --color-surface-2: #1b2415;
    --color-surface-offset: #131a0f;
    --color-surface-dynamic: #212b19;
    --color-divider: #263420;
    --color-border: #33452a;
    --color-text: #e2ecd8;
    --color-text-muted: #8ba379;
    --color-text-faint: #566b48;
    --color-text-inverse: #10160d;
    --color-primary: #7fbf5f;
    --color-primary-hover: #93d072;
    --color-primary-active: #a8e087;
    --color-primary-highlight: #24361c;
    --color-banner-highlight: #24361c;
    --color-accent: #8fc46f;
    --color-gold: #c3d24a;
    --color-plus: #b8c877;
    --color-plus-ink: #10160d;
}

[data-theme-style="cosmos"][data-theme="light"] {
    --color-bg: #eef0fb;
    --color-surface: #f7f8fd;
    --color-surface-2: #fbfbfe;
    --color-surface-offset: #e2e5f5;
    --color-surface-dynamic: #d1d6ee;
    --color-divider: #c3c9e6;
    --color-border: #adb5db;
    --color-text: #1a1a2e;
    --color-text-muted: #5c5f7a;
    --color-text-faint: #8c8fac;
    --color-text-inverse: #f7f8fd;
    --color-primary: #5b4fc4;
    --color-primary-hover: #4a3fb0;
    --color-primary-active: #392f8c;
    --color-primary-highlight: #e0ddf7;
    --color-banner-highlight: #d6d1f2;
    --color-accent: #8a7fd8;
    --color-gold: #c9a227;
    --color-plus: #5f52b5;
    --color-plus-ink: #f7f8fd;
}

[data-theme-style="cosmos"][data-theme="dark"] {
    --color-bg: #0a0a1a;
    --color-surface: #101020;
    --color-surface-2: #141428;
    --color-surface-offset: #0d0d1c;
    --color-surface-dynamic: #191934;
    --color-divider: #22224a;
    --color-border: #2c2c5c;
    --color-text: #e4e2f7;
    --color-text-muted: #9490c2;
    --color-text-faint: #5e5a8f;
    --color-text-inverse: #0a0a1a;
    --color-primary: #a78bfa;
    --color-primary-hover: #bda3fc;
    --color-primary-active: #d0bcfe;
    --color-primary-highlight: #2a2158;
    --color-banner-highlight: #2a2158;
    --color-accent: #c084fc;
    --color-gold: #f0c94a;
    /* Silver rather than the warm gold the other themes use: Cosmos' Plus
       accent should read like its own falling stars, which are drawn in
       --color-text (#e4e2f7). Deliberately a touch dimmer and cooler than that,
       so the pill stays an accent instead of looking like plain white text. */
    --color-plus: #c9c6de;
    --color-plus-ink: #0a0a1a;
}

[data-theme-style="ocean"][data-theme="light"] {
    --color-bg: #e4f2f3;
    --color-surface: #f2fafa;
    --color-surface-2: #f8fdfd;
    --color-surface-offset: #d4e9ea;
    --color-surface-dynamic: #c0dcdd;
    --color-divider: #b0d0d1;
    --color-border: #9bc0c2;
    --color-text: #0f2a2c;
    --color-text-muted: #4c7679;
    --color-text-faint: #7fa5a7;
    --color-text-inverse: #f2fafa;
    --color-primary: #1c7d8c;
    --color-primary-hover: #146373;
    --color-primary-active: #0e4c59;
    --color-primary-highlight: #cdeaec;
    --color-banner-highlight: #bfe4e6;
    --color-accent: #4fa6b5;
    --color-gold: #c9a227;
    --color-plus: #5f7d6a;
    --color-plus-ink: #0f2a2c;
}

[data-theme-style="ocean"][data-theme="dark"] {
    --color-bg: #071a1d;
    --color-surface: #0c2427;
    --color-surface-2: #102c30;
    --color-surface-offset: #091f22;
    --color-surface-dynamic: #143339;
    --color-divider: #1a3d43;
    --color-border: #22505a;
    --color-text: #d9f0f2;
    --color-text-muted: #7cabb0;
    --color-text-faint: #4a747a;
    --color-text-inverse: #071a1d;
    --color-primary: #4fd3e8;
    --color-primary-hover: #6fddef;
    --color-primary-active: #93e6f4;
    --color-primary-highlight: #123a41;
    --color-banner-highlight: #123a41;
    --color-accent: #5fc6d8;
    --color-gold: #e0c860;
    --color-plus: #cabf82;
    --color-plus-ink: #071a1d;
}

[data-theme-style="sunset"][data-theme="light"] {
    --color-bg: #fce8e4;
    --color-surface: #fef4f0;
    --color-surface-2: #fff8f5;
    --color-surface-offset: #f7d9d0;
    --color-surface-dynamic: #f0c2b4;
    --color-divider: #eab5a5;
    --color-border: #e0a08d;
    --color-text: #3a1a14;
    --color-text-muted: #8a5245;
    --color-text-faint: #b3877a;
    --color-text-inverse: #fef4f0;
    --color-primary: #d9634a;
    --color-primary-hover: #c14e37;
    --color-primary-active: #a03c28;
    --color-primary-highlight: #f8d5c8;
    --color-banner-highlight: #f4c3b0;
    --color-accent: #e88a6a;
    --color-gold: #e0a527;
    --color-plus: #bd6c33;
    --color-plus-ink: #3a1a14;
}

[data-theme-style="sunset"][data-theme="dark"] {
    --color-bg: #1a0f16;
    --color-surface: #23141d;
    --color-surface-2: #2b1924;
    --color-surface-offset: #1e1119;
    --color-surface-dynamic: #331e2c;
    --color-divider: #3d2534;
    --color-border: #4d2e40;
    --color-text: #f5dfe8;
    --color-text-muted: #b1809a;
    --color-text-faint: #78506a;
    --color-text-inverse: #1a0f16;
    --color-primary: #ef7fa8;
    --color-primary-hover: #f397b8;
    --color-primary-active: #f7afc8;
    --color-primary-highlight: #3d1f34;
    --color-banner-highlight: #3d1f34;
    --color-accent: #d97fa3;
    --color-gold: #f0b860;
    --color-plus: #b0748a;
    --color-plus-ink: #1a0f16;
}

/* Noir — ink & paper monochrome (Epigraph Plus exclusive). */
[data-theme-style="noir"][data-theme="light"] {
    --color-bg: #f4f3ef;
    --color-surface: #fbfaf6;
    --color-surface-2: #ffffff;
    --color-surface-offset: #eceae3;
    --color-surface-dynamic: #e2e0d7;
    --color-divider: #d9d7ce;
    --color-border: #c4c2b8;
    --color-text: #1a1a1c;
    --color-text-muted: #6a6a66;
    --color-text-faint: #9c9c96;
    --color-text-inverse: #fbfaf6;
    --color-primary: #26262a;
    --color-primary-hover: #131315;
    --color-primary-active: #000000;
    --color-primary-highlight: #e6e5dd;
    --color-banner-highlight: #e6e5dd;
    --color-accent: #55554f;
    --color-gold: #9a8a5e;
    --color-plus: #3d3d39;
    --color-plus-ink: #f4f3ef;
}

[data-theme-style="noir"][data-theme="dark"] {
    --color-bg: #0f0f10;
    --color-surface: #17171a;
    --color-surface-2: #1d1d21;
    --color-surface-offset: #131316;
    --color-surface-dynamic: #232327;
    --color-divider: #29292e;
    --color-border: #3a3a40;
    --color-text: #e4e2dd;
    --color-text-muted: #93918b;
    --color-text-faint: #57575c;
    --color-text-inverse: #0f0f10;
    --color-primary: #ebe8e1;
    --color-primary-hover: #f6f3ec;
    --color-primary-active: #ffffff;
    --color-primary-highlight: #24242a;
    --color-banner-highlight: #24242a;
    --color-accent: #b4b0a7;
    --color-gold: #c7bfa9;
    --color-plus: #a8a8a5;
    --color-plus-ink: #0f0f10;
}

/* =============================================================================
// THEME DECOR
// Fixed, full-viewport, non-interactive animated background per theme style.
// Every item derives its color from the active theme's own custom
// properties (--color-primary/--color-accent/--color-gold/--color-text), so
// switching light/dark automatically restyles the decoration too — no
// duplicate per-mode rules needed here. Only the group matching the current
// [data-theme-style] is shown; the rest stay display:none.
// ============================================================================= */
#theme-decor {
    position: fixed;
    inset: 0;
    z-index: -1;
    overflow: hidden;
    pointer-events: none;
}

.decor {
    position: absolute;
    inset: 0;
    display: none;
}

[data-theme-style="classic"] .decor-classic,
[data-theme-style="forest"] .decor-forest,
[data-theme-style="cosmos"] .decor-cosmos,
[data-theme-style="ocean"] .decor-ocean,
[data-theme-style="sunset"] .decor-sunset,
[data-theme-style="noir"] .decor-noir {
    display: block;
}

@media (prefers-reduced-motion: reduce) {
    #theme-decor {
        display: none;
    }
}

/* -- classic: quote glyphs drifting upward -- */
.decor-glyph {
    position: absolute;
    top: 100%;
    left: var(--x, 10%);
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(2.5rem, 6vw, 5rem);
    line-height: 1;
    color: var(--color-primary);
    opacity: 0;
    user-select: none;
    animation: decorRise var(--dur, 30s) linear var(--delay, 0s) infinite;
}

@keyframes decorRise {
    0%   { transform: translateY(0) translateX(0) rotate(0deg); opacity: 0; }
    8%   { opacity: 0.10; }
    92%  { opacity: 0.10; }
    100% { transform: translateY(-120vh) translateX(24px) rotate(6deg); opacity: 0; }
}

/* -- forest: leaves falling and swaying -- */
.decor-leaf {
    position: absolute;
    top: -8%;
    left: var(--x, 10%);
    width: 10px;
    height: 14px;
    background: var(--color-accent);
    border-radius: 0 70% 0 70%;
    opacity: 0;
    animation: decorFall var(--dur, 16s) linear var(--delay, 0s) infinite;
}

@keyframes decorFall {
    0%   { transform: translateY(0) translateX(0) rotate(0deg); opacity: 0; }
    10%  { opacity: 0.35; }
    90%  { opacity: 0.35; }
    100% { transform: translateY(115vh) translateX(40px) rotate(200deg); opacity: 0; }
}

/* -- cosmos: twinkling stars + an occasional shooting star -- */
.decor-star {
    position: absolute;
    top: var(--y, 20%);
    left: var(--x, 10%);
    width: 2px;
    height: 2px;
    border-radius: 50%;
    background: var(--color-text);
    box-shadow: 0 0 4px var(--color-gold);
    opacity: 0.1;
    animation: decorTwinkle var(--dur, 4s) ease-in-out var(--delay, 0s) infinite;
}

@keyframes decorTwinkle {
    0%, 100% { opacity: 0.1; transform: scale(1); }
    50%      { opacity: 0.9; transform: scale(1.6); }
}

.decor-shooting {
    position: absolute;
    top: 15%;
    left: -5%;
    width: 2px;
    height: 2px;
    border-radius: 50%;
    background: var(--color-gold);
    box-shadow: 0 0 6px 1px var(--color-gold);
    opacity: 0;
    animation: decorShoot 9s linear infinite;
}

@keyframes decorShoot {
    0%, 92% { opacity: 0; transform: translate(0, 0); }
    93%     { opacity: 1; }
    97%     { opacity: 1; transform: translate(60vw, 30vh); }
    100%    { opacity: 0; transform: translate(65vw, 32vh); }
}

/* -- ocean: bubbles rising -- */
.decor-bubble {
    position: absolute;
    bottom: -5%;
    left: var(--x, 10%);
    width: var(--size, 12px);
    height: var(--size, 12px);
    border-radius: 50%;
    border: 1.5px solid var(--color-accent);
    opacity: 0;
    animation: decorBubble var(--dur, 16s) ease-in var(--delay, 0s) infinite;
}

@keyframes decorBubble {
    0%   { transform: translateY(0) translateX(0); opacity: 0; }
    10%  { opacity: 0.5; }
    90%  { opacity: 0.35; }
    100% { transform: translateY(-115vh) translateX(30px); opacity: 0; }
}

/* -- sunset: slow-drifting soft glow blobs -- */
.decor-blob {
    position: absolute;
    width: 45vmax;
    height: 45vmax;
    border-radius: 50%;
    filter: blur(60px);
    opacity: 0.16;
    animation: decorBlobDrift 40s ease-in-out infinite alternate;
}

.decor-blob-1 {
    top: -10%;
    left: -10%;
    background: radial-gradient(circle, var(--color-primary), transparent 70%);
    animation-duration: 38s;
}

.decor-blob-2 {
    bottom: -15%;
    right: -10%;
    background: radial-gradient(circle, var(--color-accent), transparent 70%);
    animation-duration: 46s;
    animation-delay: -8s;
}

.decor-blob-3 {
    top: 30%;
    right: 20%;
    width: 30vmax;
    height: 30vmax;
    background: radial-gradient(circle, var(--color-gold), transparent 70%);
    animation-duration: 52s;
    animation-delay: -20s;
}

@keyframes decorBlobDrift {
    0%   { transform: translate(0, 0) scale(1); }
    50%  { transform: translate(6%, -4%) scale(1.08); }
    100% { transform: translate(-4%, 5%) scale(0.96); }
}

/* -- noir: ink dust drifting up like flecks on paper. Varied size/opacity with
   a few soft-focus motes (.decor-ink--soft) for depth; each mote's peak opacity
   is --o and its sideways drift is --dx. Base --o values are tuned for the dark
   mode; in light mode --ink-boost scales them so dark-ink-on-paper reads a hair
   softer than the dark set (but still more present than a plain 1:1 map). -- */
.decor-ink {
    position: absolute;
    bottom: -4%;
    left: var(--x, 10%);
    width: var(--size, 4px);
    height: var(--size, 4px);
    border-radius: 50%;
    background: var(--color-primary);
    opacity: 0;
    animation: decorDrift var(--dur, 26s) linear var(--delay, 0s) infinite;
}

.decor-ink--soft {
    filter: blur(2.5px);
}

[data-theme-style="noir"][data-theme="light"] .decor-ink {
    --ink-boost: 0.9;
}

@keyframes decorDrift {
    0%   { transform: translateY(0) translateX(0); opacity: 0; }
    12%  { opacity: calc(var(--o, 0.14) * var(--ink-boost, 1)); }
    88%  { opacity: calc(var(--o, 0.14) * var(--ink-boost, 1)); }
    100% { transform: translateY(-118vh) translateX(var(--dx, -28px)); opacity: 0; }
}

/* -- noir: a faint monochrome glow that very slowly wanders across the page
   behind the ink dust, so the background gradient shifts "under changing light".
   Drawn from --color-primary, so it's a soft light in dark mode and a soft
   ink-shadow on paper in light mode. Sits first in .decor-noir, behind the
   motes. -- */
.decor-noir-glow {
    position: absolute;
    inset: -40%;
    background: radial-gradient(circle at 50% 50%,
        color-mix(in srgb, var(--color-primary) 7%, transparent),
        transparent 55%);
    pointer-events: none;
    animation: decorNoirGlow 34s ease-in-out infinite alternate;
}

@keyframes decorNoirGlow {
    0%   { transform: translate(-12%, -8%); }
    100% { transform: translate(14%, 10%); }
}

/* =============================================================================
// BASE RESET
// Global element resets, default typography, focus styles, and motion prefs.
// ============================================================================= */
*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html {
    -webkit-text-size-adjust: none;
    text-size-adjust: none;
    -webkit-font-smoothing: antialiased;
    scroll-behavior: smooth;
    overflow-x: hidden;
}

body {
    min-height: 100dvh;
    font-family: var(--font-body);
    font-size: var(--text-base);
    color: var(--color-text);
    background: var(--color-bg);
    line-height: 1.6;
    /* `clip`, not `hidden`: still trims any horizontal overflow (decorative quote glyphs etc.),
       but does NOT establish a scroll container. `overflow-x: hidden` here forced overflow-y to
       compute as `auto` (per spec, a non-visible axis makes the other axis auto), so both <html>
       (which also has overflow-x:hidden) AND <body> became vertical scroll containers — two
       fighting scrollbars. With `clip`, body's overflow-y stays `visible` and <html> is the sole
       scroller. */
    overflow-x: clip;
}

img {
    display: block;
    max-width: 100%;
    height: auto;
}

button {
    cursor: pointer;
    background: none;
    border: none;
    font: inherit;
    color: inherit;
}

a, button, [role="button"] {
    transition: color var(--transition), background var(--transition), border-color var(--transition), box-shadow var(--transition), opacity var(--transition);
}

:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 3px;
    border-radius: var(--radius-sm);
}

::selection {
    background: oklch(from var(--color-primary) l c h / 0.2);
    color: var(--color-text);
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}

/* =============================================================================
// LAYOUT
// Top-level application shell containers.
//  ============================================================================= */
.app {
    display: flex;
    flex-direction: column;
    min-height: 100dvh;
}

main {
    flex: 1;
}

/* =============================================================================
// HEADER
// Sticky top header with logo and theme toggle.
// ============================================================================= */
header {
    position: sticky;
    top: 0;
    z-index: 100;
    background: oklch(from var(--color-bg) l c h / 0.92);
    backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--color-divider);
    padding: var(--space-3) var(--space-6);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
}

.logo {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text);
    text-decoration: none;
    letter-spacing: 0.01em;
    perspective: 200px;
}

.logo svg {
    color: var(--color-primary);
    flex-shrink: 0;
    transition: transform 420ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.header-actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.btn-icon {
    width: 36px;
    height: 36px;
    border-radius: var(--radius-full);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-muted);
    transition: transform 90ms ease;
}

.btn-icon:hover {
    background: var(--color-surface-offset);
    color: var(--color-text);
}

.btn-icon:active {
    transform: scale(0.94);
}

[data-lang-toggle] {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.02em;
}

/* =============================================================================
// ACCOUNT MENU (TASK-132)
// The signed-in avatar in the header replaces the old log-out icon. Clicking it
// opens a small dropdown: a Plus-status line (only for Plus accounts) and the
// log-out action. Avatar reuses the same surface as the Settings account avatar;
// the dropdown mirrors the sort menu's shape.
// ============================================================================= */
.account-menu {
    position: relative;
    display: flex;
    align-items: center;
}

.account-avatar-btn {
    width: 36px;
    height: 36px;
    border-radius: var(--radius-full);
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    padding: 0;
    cursor: pointer;
    transition: box-shadow var(--transition), transform 90ms ease;
}

.account-avatar-btn:hover,
.account-avatar-btn.open {
    box-shadow: 0 0 0 2px var(--color-primary);
}

.account-avatar-btn:active {
    transform: scale(0.94);
}

.account-menu-dropdown {
    display: none;
    position: absolute;
    right: 0;
    top: calc(100% + var(--space-2));
    background: var(--color-surface-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: var(--space-1);
    min-width: 200px;
    z-index: 50;
}

.account-menu.open .account-menu-dropdown {
    display: block;
}

.account-menu-plus {
    padding: var(--space-2) var(--space-3) var(--space-3);
    margin-bottom: var(--space-1);
    border-bottom: 1px solid var(--color-divider);
}

.account-menu-plus-head {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.account-menu-plus-benefits {
    display: flex;
    flex-direction: column;
    gap: 7px;
    margin-top: var(--space-2);
}

.account-menu-plus-benefits-title {
    font-size: 0.66rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-text-faint);
}

.account-menu-plus-benefit {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-xs);
    color: color-mix(in oklch, var(--color-text) 60%, var(--color-text-muted));
    white-space: nowrap;
}

.account-menu-plus-benefit svg {
    color: var(--color-plus);
    flex-shrink: 0;
}

.account-menu-plus-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--color-plus);
    flex-shrink: 0;
}

.account-menu-plus-label {
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text);
}

.account-menu-plus-state {
    margin-left: auto;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.account-menu-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text);
    cursor: pointer;
    text-align: left;
    background: none;
    border: none;
    font-family: var(--font-body);
    transition: background var(--transition), color var(--transition);
}

.account-menu-item svg {
    color: var(--color-text-muted);
    flex-shrink: 0;
}

.account-menu-item:hover {
    background: var(--color-surface-offset);
}

/* =============================================================================
// NAVIGATION TABS
// Pill-style tabs for switching between main views.
// ============================================================================= */
.nav-tabs {
    position: relative;
    display: flex;
    gap: var(--space-1);
    background: var(--color-surface-offset);
    border-radius: var(--radius-full);
    padding: var(--space-1);
}

.nav-tab-indicator {
    position: absolute;
    top: var(--space-1);
    bottom: var(--space-1);
    left: var(--space-1);
    width: 0;
    background: var(--color-surface-2);
    border-radius: var(--radius-full);
    box-shadow: var(--shadow-sm);
    opacity: 1;
    z-index: 0;
    pointer-events: none;
}

.nav-tabs.indicator-ready .nav-tab-indicator {
    transition: left 320ms cubic-bezier(0.16, 1, 0.3, 1),
                width 320ms cubic-bezier(0.16, 1, 0.3, 1),
                opacity 320ms ease;
}

.nav-tab {
    position: relative;
    z-index: 1;
    padding: var(--space-1) var(--space-4);
    border-radius: var(--radius-full);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-muted);
    cursor: pointer;
    white-space: nowrap;
    transition: color 200ms ease;
}

.nav-tab.active {
    color: var(--color-text);
}

.nav-tab:hover:not(.active) {
    color: var(--color-text);
}

/* =============================================================================
// BUTTONS (shared)
// Primary / secondary button styles reused across views.
// ============================================================================= */
.btn-primary {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-5);
    background: var(--color-primary);
    color: var(--color-text-inverse);
    border-radius: var(--radius-full);
    font-size: var(--text-sm);
    font-weight: 500;
    transition: transform 90ms ease;
}

.btn-primary:hover {
    background: var(--color-primary-hover);
}

.btn-primary:active {
    transform: scale(0.94);
}

.btn-primary:disabled,
.btn-danger:disabled,
.btn-secondary:disabled {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}

.btn-secondary {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-5);
    background: var(--color-surface-offset);
    color: var(--color-text);
    border-radius: var(--radius-full);
    font-size: var(--text-sm);
    font-weight: 500;
    border: 1px solid var(--color-border);
    transition: transform 90ms ease;
}

.btn-secondary:hover {
    background: var(--color-surface-dynamic);
}

.btn-secondary:active {
    transform: scale(0.94);
}

.btn-danger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-5);
    border-radius: var(--radius-full);
    font-size: var(--text-sm);
    font-weight: 500;
    background: #c0392b;
    color: #fff;
    border: 1.5px solid transparent;
    transition: background var(--transition), opacity var(--transition), transform 90ms ease;
    white-space: nowrap;
    flex-shrink: 0;
}

.btn-danger:hover {
    background: #a93226;
}

.btn-danger:active {
    opacity: 0.85;
    transform: scale(0.94);
}

/* =============================================================================
// VIEWS
// View visibility toggle and scroll locking helper.
// ============================================================================= */
.view {
    display: none;
    opacity: 0;
}

.view.active {
    display: block;
    animation: viewFadeIn 220ms cubic-bezier(0.16, 1, 0.3, 1) forwards;
}

@keyframes viewFadeIn {
    from {
        opacity: 0;
        transform: translateY(6px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

body.no-scroll {
    overflow: hidden;
    height: 100dvh;
}

/* Locks background scroll while the shared modal is open. Pins the body with position:fixed
   (the inline top:-scrollY offset is set by lockBackgroundScroll() in ui.js) so the page keeps
   its scroll position visually under the blur instead of collapsing to the top. Kept separate
   from .no-scroll (owned by the qod fullscreen-fit logic) so the two don't fight over it. */
body.modal-lock-scroll {
    position: fixed;
    left: 0;
    right: 0;
    width: 100%;
    overflow: hidden;
}

/* =============================================================================
// QUOTE OF THE DAY
// Hero card that displays today's quote with actions.
// ============================================================================= */
.qod-section {
    min-height: calc(100dvh - 57px);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: var(--space-12) var(--space-6);
    text-align: center;
    position: relative;
}

.qod-bg-ornament {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: min(600px, 90vw);
    height: min(600px, 90vw);
    background: radial-gradient(ellipse, oklch(from var(--color-primary) l c h / 0.06) 0%, transparent 70%);
    pointer-events: none;
}

.qod-date {
    font-size: var(--text-xs);
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-primary);
    margin-bottom: var(--space-6);
}

/* QoD card — fluid width, grows before font shrinks */
.qod-card {
    width: min(92vw, 1100px);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-xl);
    padding: var(--space-10) var(--space-12);
    box-shadow: var(--shadow-lg);
    position: relative;
    cursor: grab;
    user-select: none;
    will-change: transform;
    transition: width 300ms ease;
    touch-action: pan-y; /* browser handles vertical scroll, JS gets horizontal */
    -webkit-user-select: none; /* prevent text selection on iOS during swipe */
    user-select: none; /* already present — keep it */
    -webkit-touch-callout: none; /* suppress long-press callout menu on iOS */
}

/* Size modifier classes — width first, font second */
.qod-card.qod-size-short {
    width: min(92vw, 480px);
}

.qod-card.qod-size-medium {
    width: min(92vw, 740px);
}

.qod-card.qod-size-long {
    width: min(92vw, 960px);
}

.qod-card.qod-size-very-long {
    width: min(92vw, 1100px);
}

.qod-card.is-dragging {
    transition: none;
}

.qod-card::before {
    content: '"';
    position: absolute;
    top: calc(-1 * var(--space-8));
    left: var(--space-8);
    font-family: var(--font-display);
    font-size: 10rem;
    line-height: 1;
    color: var(--color-primary);
    opacity: 0.15;
    pointer-events: none;
    user-select: none;
}

.qod-quote {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 400;
    line-height: 1.5;
    color: var(--color-text);
    margin-bottom: var(--space-6);
    /* Font size is set synchronously by JS before layout measurement — no transition needed */
}

.qod-author {
    font-size: var(--text-sm);
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-primary);
}

.qod-source {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-top: var(--space-1);
    font-style: italic;
}

.qod-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    justify-content: center;
    margin-top: var(--space-8);
}

.qod-actions button {
    transition: transform 90ms ease;
}

.qod-actions button:active {
    transform: scale(0.94);
}

#btn-fav-qod {
    /* min-width is set precisely by syncFavButtonWidth() in quotes.js — a fixed guess here
       can't reliably fit both label variants across languages/fonts. */
    justify-content: center;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}

#btn-fav-qod.is-active {
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    border-color: var(--color-primary-highlight);
}

#qod-fav-label {
    transition: opacity 140ms ease;
}

.qod-progress {
    margin-top: var(--space-6);
    font-size: var(--text-xs);
    color: var(--color-text-faint);
}

.swipe-overlay {
    position: absolute;
    inset: 0;
    border-radius: var(--radius-xl);
    opacity: 0;
    pointer-events: none;
    transition: opacity 80ms linear;
}

.swipe-overlay-left {
    background: linear-gradient(to right,
    oklch(from var(--color-primary) l c h / 0.18) 0%,
    transparent 70%);
}

.swipe-overlay-right {
    background: linear-gradient(to left,
    oklch(from var(--color-primary) l c h / 0.18) 0%,
    transparent 70%);
}

.btn-disabled-empty {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: auto !important; /* allow click to show toast */
}

/* =============================================================================
// QUOTES LIST
// Grid layout that shows all stored quotes with search/filter controls.
// ============================================================================= */
.list-section {
    padding: var(--space-8) var(--space-6);
    max-width: var(--content-default);
    margin: 0 auto;
}

.list-header {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    margin-bottom: var(--space-6);
    flex-wrap: wrap;
}

.list-header h2 {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 500;
    flex: 1;
}

.search-wrap {
    position: relative;
    flex: 1;
    min-width: 200px;
    max-width: 360px;
}

.search-wrap svg {
    position: absolute;
    left: var(--space-3);
    top: 50%;
    transform: translateY(-50%);
    color: var(--color-text-muted);
    pointer-events: none;
}

.search-input {
    width: 100%;
    padding: var(--space-2) var(--space-3) var(--space-2) 2.4rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    font-size: max(var(--text-sm), 1rem);
    color: var(--color-text);
    font-family: var(--font-body);
}

.search-input:focus {
    outline: 2px solid var(--color-primary);
    border-color: transparent;
}

.search-input::placeholder {
    color: var(--color-text-faint);
}

.search-input::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
    width: 14px;
    height: 14px;
    background-color: var(--color-text-muted);
    cursor: pointer;
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cline x1='18' y1='6' x2='6' y2='18' stroke='white' stroke-width='2.5' stroke-linecap='round'/%3E%3Cline x1='6' y1='6' x2='18' y2='18' stroke='white' stroke-width='2.5' stroke-linecap='round'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cline x1='18' y1='6' x2='6' y2='18' stroke='white' stroke-width='2.5' stroke-linecap='round'/%3E%3Cline x1='6' y1='6' x2='18' y2='18' stroke='white' stroke-width='2.5' stroke-linecap='round'/%3E%3C/svg%3E");
    -webkit-mask-size: contain;
    mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
}

.search-input::-webkit-search-cancel-button:hover {
    background-color: var(--color-text);
}

.quotes-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
    gap: var(--space-4);
}

.list-load-more {
    display: flex;
    justify-content: center;
    margin-top: var(--space-6);
}

.list-load-more .btn-secondary {
    padding: var(--space-3) var(--space-6);
}

.quote-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-6);
    box-shadow: var(--shadow-sm);
    position: relative;
    overflow: hidden;
    cursor: default;
    transition: background var(--transition), box-shadow var(--transition), transform var(--transition);
    animation: cardAppear 280ms cubic-bezier(0.16, 1, 0.3, 1) both;
}

@keyframes cardAppear {
    from {
        opacity: 0;
        transform: translateY(8px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.quote-card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-1px);
}

/* Brief highlight for the card landed on via a "View in my collection" redirect from the public
   share page. Deliberately a transition on box-shadow, not a keyframe animation — .quote-card
   already has its own `animation: cardAppear ...`, and toggling a class that also sets `animation`
   replaces that shorthand, which makes the browser treat it as a new animation once the class is
   removed and restarts cardAppear (the card visibly disappears and re-fades-in). box-shadow
   transitions don't touch the animation property at all, so this can't retrigger it.

   Own transition-duration (not the shared var(--transition), which is a snappy 180ms tuned for
   hover micro-interactions) — reusing that made both the fade-in and fade-out read as an abrupt
   snap rather than the graceful highlight this is meant to be. A CSS transition's duration is
   taken from the state being transitioned TO, so a fade-OUT that used .quote-card's own 180ms
   transition (the class being removed) would still be fast even with a slower fade-in here — the
   .just-shared-fade-out modifier keeps .just-shared (and its 900ms transition) applied while
   flipping the box-shadow value back, so the class removal itself is a no-op restyle and both
   directions share the same slow, graceful timing. See highlightPendingSharedImport() in quotes.js. */
.quote-card.just-shared {
    box-shadow: 0 0 0 3px var(--color-primary);
    transition: box-shadow 900ms ease;
}

.quote-card.just-shared.just-shared-fade-out {
    box-shadow: var(--shadow-sm);
}

.quote-card-num {
    position: absolute;
    top: var(--space-3);
    right: var(--space-4);
    font-size: var(--text-xs);
    color: var(--color-text-faint);
    font-variant-numeric: tabular-nums;
}

.quote-card-text {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--text-lg);
    line-height: 1.55;
    color: var(--color-text);
    margin-bottom: var(--space-4);
    /* Clamp to 4 lines */
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
    transition: font-size var(--transition);
}

/* Fade mask at the bottom of clipped cards */
.quote-card-text-wrap {
    position: relative;
    margin-bottom: var(--space-4);
}

/* Fade only on actually clipped cards */
.quote-card-text-wrap.is-clipped::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 2.5rem;
    background: linear-gradient(transparent, var(--color-surface));
    pointer-events: none;
}

/* Remove old margin from text since wrap has it now */
.quote-card-text-wrap .quote-card-text {
    margin-bottom: 0;
}

/* Expanded card — full width in grid, full text visible */
.quote-card.is-expanded {
    cursor: default;
    /* No grid-column: 1/-1 — stays in place, just grows down */
}

/* The raised look is a separate class from is-expanded (which unclamps the
   text) so the two can be timed independently: on collapse the raise is dropped
   at the start, fading the background out *with* the height rather than
   snapping back once the height animation has already finished. Background is
   in .quote-card's transition list for exactly this. */
.quote-card.is-raised {
    background: var(--color-surface-2);
    box-shadow: var(--shadow-lg);
}

.quote-card.is-expanded .quote-card-text {
    display: block;
    -webkit-line-clamp: unset;
    overflow: visible;
}

.quote-card.is-expanded .quote-card-text-wrap::after {
    display: none;
}

/* Expand hint — shown only on clipped cards */
.quote-card-expand-hint {
    display: none;
    font-size: var(--text-xs);
    color: var(--color-text-faint);
    margin-top: var(--space-2);
    cursor: pointer;
    user-select: none;
    transition: color var(--transition);
}

.quote-card-text-wrap.is-clipped ~ .quote-card-expand-hint {
    display: block;
}

.quote-card.is-expanded .quote-card-expand-hint {
    display: block;
    color: var(--color-text-muted);
}

.quote-card:has(.quote-card-text-wrap.is-clipped) {
    cursor: pointer;
}

.quote-card-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    min-width: 0; /* prevents overflow from breaking flex layout */
}

.quote-card-author {
    font-size: var(--text-xs);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-primary);
}

.quote-card-author,
.quote-card-source {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}

.quote-card-source {
    font-size: var(--text-xs);
    color: var(--color-text-faint);
    font-style: italic;
}

/* Prevents long author/source from pushing action buttons off-screen */
.quote-card-meta > div:first-child {
    min-width: 0;
    overflow: hidden;
}

.quote-card-actions {
    display: flex;
    gap: var(--space-1);
    opacity: 0;
    transition: opacity var(--transition);
    flex-shrink: 0;
}

.quote-card:hover .quote-card-actions {
    opacity: 1;
}

.card-btn {
    width: 28px;
    height: 28px;
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--color-text-muted);
    transition: transform 90ms ease;
}

.card-btn:hover {
    background: var(--color-surface-offset);
    color: var(--color-primary);
}

.card-btn:active {
    transform: scale(0.9);
}

.card-btn.fav.active {
    /* Favorite = the theme accent, matching the QOD "В избранном" button (#btn-fav-qod.is-active),
       so the favorite colour is consistent app-wide and native to every theme (TASK-136). */
    color: var(--color-primary);
}

/* Saved state of the friend-quote "+" (TASK-129): a settled accent check, no
   hover/press affordance since saving is idempotent and there's nothing left to
   do. Kept as a .card-btn so it lines up with the copy button beside it. */
.card-btn.friend-save-btn--saved {
    color: var(--color-primary);
    cursor: default;
}

.card-btn.friend-save-btn--saved:hover {
    background: transparent;
    color: var(--color-primary);
}

.card-btn.edit:hover {
    background: var(--color-surface-offset);
    color: var(--color-primary);
}

.card-btn.danger:hover {
    color: #c0392b;
    background: oklch(from #c0392b l c h / 0.1);
}

.quote-card-tags {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-bottom: var(--space-3);
}

.quote-tag-chip {
    padding: 2px var(--space-3);
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    border-radius: var(--radius-full);
    font-size: var(--text-xs);
    font-weight: 500;
    cursor: pointer;
    transition: background var(--transition), color var(--transition);
}

.quote-tag-chip:hover {
    background: var(--color-primary);
    color: var(--color-text-inverse);
}

/* Read-only tag on a friend's quote (TASK-129) — same chip, but tapping it can't
   search a collection that isn't yours, so it isn't a button and doesn't invite
   a click. */
.quote-tag-chip--static {
    cursor: default;
}

.quote-tag-chip--static:hover {
    background: var(--color-primary-highlight);
    color: var(--color-primary);
}

.empty-state {
    grid-column: 1/-1;
    padding: var(--space-20) var(--space-8);
    text-align: center;
    color: var(--color-text-muted);
}

.empty-state-icon {
    display: flex;
    justify-content: center;
    margin-bottom: var(--space-4);
    color: var(--color-text-faint);
    animation: emptyStateBob 2600ms ease-in-out infinite;
}

@keyframes emptyStateBob {
    0%, 100% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(-6px);
    }
}

.empty-state p {
    margin-top: var(--space-2);
    font-size: var(--text-sm);
}

.stats-bar {
    display: flex;
    gap: var(--space-6);
    margin-bottom: var(--space-6);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    flex-wrap: wrap;
}

.stats-bar span strong {
    color: var(--color-text);
    font-weight: 600;
}

.filter-tabs {
    display: flex;
    gap: var(--space-2);
    margin-bottom: var(--space-4);
    flex-wrap: wrap;
    align-items: center;
}

.filter-tab {
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-full);
    font-size: var(--text-xs);
    font-weight: 500;
    cursor: pointer;
    border: 1px solid var(--color-border);
    color: var(--color-text-muted);
}

.filter-tab.active {
    background: var(--color-primary);
    color: var(--color-text-inverse);
    border-color: var(--color-primary);
}

.filter-tab:hover:not(.active) {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

/* =============================================================================
// SORT DROPDOWN
// Custom pill-style sort control matching .filter-tab aesthetics.
// ============================================================================= */
.sort-dropdown {
    position: relative;
    margin-left: auto;
}

.sort-btn {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-full);
    font-size: var(--text-xs);
    font-weight: 500;
    cursor: pointer;
    border: 1px solid var(--color-border);
    color: var(--color-text-muted);
    background: none;
    white-space: nowrap;
    transition: border-color var(--transition), color var(--transition), background var(--transition), transform 90ms ease;
    user-select: none;
}

.sort-btn:hover {
    border-color: var(--color-primary);
    color: var(--color-text);
}

.sort-btn:active {
    transform: scale(0.94);
}

.sort-btn.open {
    border-color: var(--color-primary);
    color: var(--color-text);
    background: var(--color-primary-highlight);
}

/* Unify with the other Settings action buttons (.export-btn) — a resting
   muted state made sense for the quote-list sort trigger it was designed for,
   but read as an unrelated third color next to the always-bright Export/Import/
   Copy/etc. buttons here. */
#notif-interval-btn {
    color: var(--color-text);
}

.sort-btn svg {
    flex-shrink: 0;
    transition: transform var(--transition);
}

.sort-btn.open svg.chevron {
    transform: rotate(180deg);
}

.sort-menu {
    display: none;
    position: absolute;
    right: 0;
    top: calc(100% + var(--space-2));
    background: var(--color-surface-2);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: var(--space-1);
    min-width: 180px;
    z-index: 50;
}

.sort-menu.open {
    display: block;
}

.sort-menu-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text-muted);
    cursor: pointer;
    text-align: left;
    background: none;
    border: none;
    font-family: var(--font-body);
    transition: background var(--transition), color var(--transition);
    white-space: nowrap;
}

@keyframes sortMenuItemIn {
    from {
        opacity: 0;
        transform: translateY(-4px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.sort-menu.open .sort-menu-item {
    animation: sortMenuItemIn 180ms ease both;
}

.sort-menu.open .sort-menu-item:nth-child(1) {
    animation-delay: 0ms;
}

.sort-menu.open .sort-menu-item:nth-child(2) {
    animation-delay: 30ms;
}

.sort-menu.open .sort-menu-item:nth-child(3) {
    animation-delay: 60ms;
}

.sort-menu.open .sort-menu-item:nth-child(4) {
    animation-delay: 90ms;
}

.sort-menu-item:hover {
    background: var(--color-surface-offset);
    color: var(--color-text);
}

.sort-menu-item.active {
    color: var(--color-primary);
    background: var(--color-primary-highlight);
}

.sort-menu-item.active svg {
    opacity: 1;
}

.sort-menu-item svg {
    opacity: 0;
    flex-shrink: 0;
}

/* =============================================================================
// ADD QUOTE
// Form for manually adding quotes and JSON import UI.
// ============================================================================= */
.add-section {
    padding: var(--space-8) var(--space-6);
    max-width: var(--content-default);
    margin: 0 auto;
}

.add-section h2 {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 500;
    margin-bottom: var(--space-2);
}

.add-section .subtitle {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-bottom: var(--space-8);
}

.form-group {
    margin-bottom: var(--space-5);
}

.form-label {
    display: block;
    font-size: var(--text-sm);
    font-weight: 500;
    margin-bottom: var(--space-2);
    color: var(--color-text);
}

.form-label span {
    color: var(--color-text-faint);
    font-weight: 400;
}

.form-input-wrap .form-input,
.edit-input-wrap .edit-input {
    padding-right: 4rem;
}

.form-input, .form-textarea {
    width: 100%;
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--text-base);
    color: var(--color-text);
    font-family: var(--font-body);
    transition: border-color var(--transition), box-shadow var(--transition);
}

.form-textarea {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--text-lg);
    min-height: 140px;
    max-height: 320px;
    resize: vertical;
    line-height: 1.6;
    padding-bottom: calc(var(--space-4) + 1.2rem);
}

.form-input:focus, .form-textarea:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px oklch(from var(--color-primary) l c h / 0.15);
}

.form-input::placeholder, .form-textarea::placeholder {
    color: var(--color-text-faint);
    font-style: italic;
}

.form-row {
    display: grid;
    grid-template-columns:1fr 1fr;
    gap: var(--space-4);
}

.form-actions {
    display: flex;
    gap: var(--space-3);
    margin-top: var(--space-6);
}

.form-divider {
    border: none;
    border-top: 1px solid var(--color-divider);
    margin: var(--space-10) 0;
}

.section-subheading {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 500;
    margin-bottom: var(--space-2);
}

.import-hint {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-bottom: var(--space-4);
}

.inline-code {
    background: var(--color-surface-offset);
    padding: 2px 6px;
    border-radius: 4px;
    font-size: 0.85em;
}

.import-area {
    border: 2px dashed var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-8);
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition);
    display: flex;
    flex-direction: column;
    align-items: center;
}

.import-area:hover {
    border-color: var(--color-primary);
    background: var(--color-primary-highlight);
}

.import-area p {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-top: var(--space-2);
}

.import-area strong {
    color: var(--color-text);
}

.import-area-icon {
    margin-bottom: var(--space-3);
    color: var(--color-text-muted);
}

.import-file-input {
    display: none;
}

.json-example-wrap {
    margin-top: var(--space-4);
}

.json-example-label {
    font-size: var(--text-xs);
    color: var(--color-text-faint);
    margin-bottom: var(--space-2);
}

.json-example {
    background: var(--color-surface-offset);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    font-size: 0.78rem;
    overflow-x: auto;
    color: var(--color-text-muted);
    line-height: 1.7;
}

.is-hidden {
    display: none;
}

.import-source-toggle {
    position: relative;
    display: inline-flex;
    background: var(--color-surface-offset);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    padding: 3px;
    margin-bottom: var(--space-6);
}

/* Slides under whichever tab is active — same measure-and-transform approach as
   .nav-tab-indicator, see moveToggleIndicator() in ui.js. */
.import-source-indicator {
    position: absolute;
    top: 3px;
    bottom: 3px;
    left: 3px;
    width: 0;
    background: var(--color-primary);
    border-radius: var(--radius-full);
    z-index: 0;
    pointer-events: none;
}

.import-source-toggle.indicator-ready .import-source-indicator {
    transition: left 280ms cubic-bezier(0.16, 1, 0.3, 1), width 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

.import-source-tab {
    position: relative;
    z-index: 1;
    padding: var(--space-2) var(--space-5);
    border: none;
    border-radius: var(--radius-full);
    font-size: var(--text-sm);
    font-weight: 500;
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    transition: color var(--transition);
}

.import-source-tab.is-active {
    color: var(--color-text-inverse);
}

.settings-item .import-source-toggle {
    margin-bottom: 0;
}

/* Unify with the other Settings action buttons (.export-btn) — the muted resting
   color made sense for the JSON/Yandex import source picker it was designed for,
   but read as a third, unrelated color next to the always-bright buttons here. */
.settings-item .import-source-tab:not(.is-active) {
    color: var(--color-text);
}

.import-benefit-banner {
    display: flex;
    gap: var(--space-3);
    background: var(--color-banner-highlight);
    color: var(--color-primary-active);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    margin-bottom: var(--space-6);
}

.import-benefit-banner svg {
    flex-shrink: 0;
    margin-top: 2px;
}

.import-benefit-banner p {
    font-size: var(--text-sm);
    line-height: 1.6;
    margin: 0;
}

.import-step {
    display: flex;
    gap: var(--space-3);
    margin-bottom: var(--space-4);
}

.import-step-num {
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    font-size: var(--text-xs);
    font-weight: 500;
    display: flex;
    align-items: center;
    justify-content: center;
}

.import-step p {
    font-size: var(--text-sm);
    color: var(--color-text);
    line-height: 1.6;
    margin: 0;
}

.import-highlight {
    color: var(--color-primary);
    text-decoration: none;
}

.import-highlight:hover {
    text-decoration: underline;
}

.import-step-body {
    flex: 1;
}

.import-step-body p {
    margin-bottom: var(--space-3);
}

.import-copy-btn {
    padding: var(--space-2) var(--space-4);
    font-size: var(--text-xs);
}

.import-step-body .import-step-hint {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin: var(--space-2) 0 0;
}

.import-faq {
    margin-top: var(--space-6);
    border-top: 1px solid var(--color-divider);
    padding-top: var(--space-4);
}

.import-faq-summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.import-faq-summary::-webkit-details-marker {
    display: none;
}

.import-faq-summary-label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.import-faq-chevron {
    transition: transform var(--transition);
}

.import-faq[open] .import-faq-chevron {
    transform: rotate(180deg);
}

.import-faq-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-4) 0 0 var(--space-6);
}

.import-faq-q {
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text);
    margin: 0 0 var(--space-1);
}

.import-faq-a {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    line-height: 1.6;
    margin: 0;
}

.tag-input-wrap {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    align-items: center;
}

.tag-input {
    width: 120px;
    min-width: 60px;
    max-width: 180px;
    padding: var(--space-1) var(--space-2);
    height: auto;
    font-size: var(--text-xs);
    line-height: 1.5;
}

.tag-add-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    background: transparent;
    border: 1px solid var(--color-border);
    color: var(--color-text-muted);
    border-radius: var(--radius-full);
    font-size: var(--text-xs);
    line-height: 1.5;
    font-weight: 500;
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition), background var(--transition);
}

.tag-add-btn:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
    background: var(--color-primary-highlight);
}

.tag {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3) var(--space-1) var(--space-3);
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    border-radius: var(--radius-full);
    font-size: var(--text-xs);
    font-weight: 500;
    animation: tagPopIn 220ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

@keyframes tagPopIn {
    from {
        transform: scale(0.5);
        opacity: 0;
    }
    to {
        transform: scale(1);
        opacity: 1;
    }
}

.tag button {
    display: flex;
    align-items: center;
    color: inherit;
    opacity: 0.6;
}

.tag button:hover {
    opacity: 1;
}

/* =============================================================================
// CHAR COUNTER
// Character counter displayed below quote textarea fields.
// ============================================================================= */
.char-counter {
    position: absolute;
    bottom: var(--space-3);
    right: var(--space-3);
    font-size: 0.7rem;
    color: var(--color-text-faint);
    font-variant-numeric: tabular-nums;
    transition: color var(--transition), opacity var(--transition);
    user-select: none;
    pointer-events: none;
    line-height: 1;
    letter-spacing: 0.02em;
    opacity: 0;
    background: color-mix(in oklch, var(--color-surface-offset) 85%, transparent);
    padding: 0.15rem 0.3rem;
    border-radius: var(--radius-sm);
    backdrop-filter: blur(2px);
}

.form-textarea-wrap .char-counter,
.edit-textarea-wrap .char-counter {
    bottom: calc(var(--space-2) + 0.4rem);
    right: calc(var(--space-3));
}

.form-textarea-wrap:focus-within .char-counter,
.edit-textarea-wrap:focus-within .char-counter,
.form-input-wrap:focus-within .char-counter,
.edit-input-wrap:focus-within .char-counter {
    opacity: 0.6;
}

.char-counter.is-warning {
    color: var(--color-gold);
    opacity: 1 !important;
}

.char-counter.is-over {
    color: #c0392b;
    font-weight: 600;
    opacity: 1 !important;
}

.form-textarea-wrap,
.edit-textarea-wrap,
.form-input-wrap,
.edit-input-wrap {
    position: relative;
}

/* =============================================================================
// SETTINGS
// Configuration panel with data export/import and danger-zone actions.
// ============================================================================= */
.settings-section {
    padding: var(--space-8) var(--space-6);
    max-width: var(--content-default);
    margin: 0 auto;
}

.settings-section h2 {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 500;
    margin-bottom: var(--space-8);
}

.settings-group {
    margin-bottom: var(--space-8);
}

.settings-group-title {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin-bottom: var(--space-3);
}

.settings-card {
    background: var(--color-surface);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

/* Let an open dropdown (e.g. the notification-interval menu) escape the card's
   rounded-corner clipping instead of being cut off — see toggleNotifIntervalMenu(). */
.settings-card.dropdown-open {
    overflow: visible;
}

.settings-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--color-divider);
}

.settings-item:last-child {
    border-bottom: none;
}

.settings-item--stack {
    flex-direction: column;
    align-items: stretch;
}

.theme-style-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
    gap: var(--space-3);
    margin-top: var(--space-1);
}

.theme-style-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-2);
    background: var(--color-surface-2);
    border: 1.5px solid var(--color-divider);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: border-color var(--transition), transform var(--transition), box-shadow var(--transition);
}

.theme-style-card:hover {
    border-color: var(--color-border);
    transform: translateY(-1px);
}

.theme-style-card.is-active {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 1px var(--color-primary);
}

.theme-style-swatch {
    position: relative;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-full);
    overflow: hidden;
    border: 1px solid var(--color-divider);
}

.theme-style-swatch span {
    position: absolute;
    border-radius: 50%;
}

.theme-style-swatch .swatch-primary {
    inset: 0;
}

.theme-style-swatch .swatch-accent {
    width: 55%;
    height: 55%;
    right: -8%;
    bottom: -8%;
}

.theme-style-lock {
    inset: 0;
    display: none;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.45);
    color: var(--color-text-inverse);
}

.theme-style-card--locked .theme-style-lock {
    display: flex;
}

.theme-style-card--locked {
    opacity: 0.6;
    pointer-events: none;
    cursor: default;
}

.theme-style-card-label {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    text-align: center;
}

.theme-style-card.is-active .theme-style-card-label {
    color: var(--color-text);
    font-weight: 600;
}

.theme-style-card-hint {
    font-size: 9px;
    color: var(--color-text-faint);
    text-align: center;
    line-height: 1.3;
}

.settings-item-info h4 {
    font-size: var(--text-base);
    font-weight: 500;
}

.settings-item-info p {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-top: var(--space-1);
}

.settings-github-link,
.settings-support-link {
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-5);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    font-size: var(--text-sm);
    color: var(--color-text);
    background: var(--color-surface);
    white-space: nowrap;
    transition: border-color var(--transition), color var(--transition);
}

.settings-github-link:hover,
.settings-support-link:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

.settings-contact-email {
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text-faint);
    background: var(--color-surface-offset);
    border-radius: var(--radius-full);
    padding: 2px var(--space-3);
    white-space: nowrap;
    flex-shrink: 0;
}

.settings-account-info {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
}

.settings-account-avatar {
    width: 36px;
    height: 36px;
    border-radius: var(--radius-full);
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    margin-top: 1px;
    border: none;
    padding: 0;
    cursor: pointer;
    transition: box-shadow var(--transition), transform 90ms ease;
}

.settings-account-avatar:hover {
    box-shadow: 0 0 0 2px var(--color-primary);
}

.settings-account-avatar:active {
    transform: scale(0.94);
}

.avatar-picker-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--space-6) var(--space-3);
    justify-items: center;
}

.avatar-picker-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
}

.avatar-picker-label {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    text-align: center;
}

.avatar-picker-option {
    position: relative;
    width: 64px;
    height: 64px;
    border-radius: var(--radius-full);
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    border: 2px solid transparent;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: border-color var(--transition), transform var(--transition);
}

.avatar-picker-option:hover {
    transform: scale(1.06);
}

.avatar-picker-option--selected {
    border-color: var(--color-primary);
}

.avatar-picker-badge {
    position: absolute;
    right: -2px;
    bottom: -2px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: var(--color-primary);
    color: var(--color-text-inverse);
    display: flex;
    align-items: center;
    justify-content: center;
    transform: scale(0);
    transition: transform 260ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

.avatar-picker-option--selected .avatar-picker-badge {
    transform: scale(1);
}

/* Epigraph Plus avatars (TASK-132): a small "Plus" pill in the top-left corner,
   and a dimmed locked state for non-Plus users (clicking shows the "available in
   Plus" toast). The pill uses the same per-theme --color-plus / --color-plus-ink
   tokens as the Settings account strip, so it re-tints with the active theme. */
.avatar-picker-plus {
    position: absolute;
    left: -4px;
    top: -3px;
    padding: 1.5px 6px;
    border-radius: var(--radius-full);
    background: var(--color-plus);
    color: var(--color-plus-ink);
    font-size: 8px;
    font-weight: 600;
    letter-spacing: 0.02em;
    line-height: 1;
    box-shadow: var(--shadow-sm);
    z-index: 2;
}

.avatar-picker-option--locked {
    opacity: 0.5;
    cursor: default;
}

.avatar-picker-option--locked:hover {
    transform: none;
}

/* =============================================================================
// ANIMATED AVATARS (TASK-132)
// Looping micro-animations for the Plus avatar set (snail, bee, frog,
// nightingale). Class names are namespaced av-* and live on sub-elements inside
// the inline SVG markup in avatars.js, so the motion follows the avatar wherever
// it renders (top bar, Settings, picker). All disabled under reduced-motion.
// ============================================================================= */
.av-stalk, .av-bob, .av-buzz-l, .av-buzz-r, .av-blink,
.av-ripple, .av-leaf, .av-tilt, .av-tailbob, .av-note {
    transform-box: fill-box;
}

.av-stalk { transform-origin: center bottom; animation: avWave 2.8s ease-in-out infinite; }
.av-bob { transform-origin: center; animation: avBob 3.6s ease-in-out infinite; }
.av-buzz-l { transform-origin: right center; animation: avBuzz 0.22s linear infinite; }
.av-buzz-r { transform-origin: left center; animation: avBuzz 0.22s linear infinite; }
.av-blink { transform-origin: center; animation: avBlink 4s ease-in-out infinite; }
.av-ripple { transform-origin: center; animation: avRipple 3.4s ease-out infinite; }
.av-ripple-2 { animation-delay: 1.7s; }
.av-leaf {
    transform-origin: center;
    animation-name: avLeaf;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
}
.av-leaf-1 { --lx: 5px; animation-duration: 8.5s; animation-delay: 0s; }
.av-leaf-2 { --lx: -4px; animation-duration: 10.5s; animation-delay: -3.5s; }
.av-leaf-3 { --lx: 6px; animation-duration: 9.5s; animation-delay: -6.5s; }
.av-leaf-4 { --lx: -6px; animation-duration: 12s; animation-delay: -9s; }
.av-tilt { transform-origin: center bottom; animation: avTilt 3.8s ease-in-out infinite; }
.av-tailbob { transform-origin: center top; animation: avTailbob 3.4s ease-in-out infinite; }
.av-note { transform-origin: center; animation: avNote 3s ease-out infinite; }

@keyframes avWave { 0%, 100% { transform: rotate(-6deg); } 50% { transform: rotate(6deg); } }
@keyframes avBob { 0%, 100% { transform: translateY(-0.84px); } 50% { transform: translateY(0.84px); } }
@keyframes avBuzz { 0%, 100% { transform: scaleX(1); } 50% { transform: scaleX(0.4); } }
@keyframes avBlink { 0%, 90%, 100% { transform: scaleY(1); } 95% { transform: scaleY(0.12); } }
@keyframes avRipple { 0% { transform: scale(0.4); opacity: 0.5; } 100% { transform: scale(1.35); opacity: 0; } }
@keyframes avLeaf {
    0% { transform: translateY(-9px) rotate(0); opacity: 0; }
    16% { opacity: 0.5; }
    52% { opacity: 0.5; }
    100% { transform: translateY(14px) translateX(var(--lx)) rotate(185deg); opacity: 0; }
}
@keyframes avTilt { 0%, 100% { transform: rotate(-8deg); } 50% { transform: rotate(5deg); } }
@keyframes avTailbob { 0%, 100% { transform: rotate(-4deg); } 50% { transform: rotate(5deg); } }
@keyframes avNote { 0% { opacity: 0; transform: translate(0, 0); } 25% { opacity: 1; } 100% { opacity: 0; transform: translate(3px, -9px); } }

@media (prefers-reduced-motion: reduce) {
    .av-stalk, .av-bob, .av-buzz-l, .av-buzz-r, .av-blink,
    .av-ripple, .av-leaf, .av-tilt, .av-tailbob, .av-note {
        animation: none;
    }
    /* The falling leaves and water ripples are pure ambience — hide them fully
       when motion is off rather than leaving frozen artifacts on the frog. */
    .av-leaf, .av-ripple {
        opacity: 0;
    }
}

.settings-account-name {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    line-height: 1.2;
}

/* Plus accent strip on the account row (TASK-132, direction N7). A thin gold
   bar on the card's left edge, shown only when the account has Plus (the
   .is-plus class is toggled in updateSettingsAccount()). On hover it widens and
   reveals a vertical "plus" in spaced small-caps. The strip stays within the
   row's left padding (space-5), so the widened state never overlaps content. */
.settings-account-item {
    position: relative;
    transition: padding-left 0.28s cubic-bezier(0.34, 1.4, 0.64, 1);
}

/* On hover the strip widens, so nudge the row's content right by the same amount
   — the widened strip then sits in the freed space instead of clipping the
   avatar. At rest the row keeps the shared left padding, aligned with the rows
   below it. */
.settings-account-item.is-plus:hover {
    padding-left: calc(var(--space-5) + 16px);
}

.account-plus-strip {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 3px;
    background: var(--color-plus);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    opacity: 0;
    pointer-events: none;
    transition: width 0.28s cubic-bezier(0.34, 1.4, 0.64, 1);
}

.settings-account-item.is-plus .account-plus-strip {
    opacity: 1;
}

.settings-account-item.is-plus:hover .account-plus-strip {
    width: 18px;
}

.account-plus-strip-label {
    writing-mode: vertical-rl;
    font-size: 0.55rem;
    font-weight: 500;
    letter-spacing: 0.28em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--color-plus-ink);
    opacity: 0;
    transition: opacity 0.3s ease 0.05s;
}

.settings-account-item.is-plus:hover .account-plus-strip-label {
    opacity: 1;
}

/* =============================================================================
// BADGE RANK PILL (TASK-122)
// Nine ascending prestige levels for the equipped badge shown next to the
// username — background saturation grows with rank ("option A" from the
// design pass), top two ranks get a soft glow. Explicit hex per mode
// (dark = the originally-approved mockup values, light = a hand-built
// analog using the same method), scoped under [data-theme], not derived via
// color-mix() — only tuned for Classic's light/dark, not per theme style.
// Auto-equipped, not user-styled — see updateSettingsAccount() in auth.js.
// ============================================================================= */
.badge-pill {
    display: inline-flex;
    align-items: center;
    font-size: var(--text-xs);
    font-weight: 500;
    padding: 2px 9px;
    border-radius: var(--radius-full);
    border: 1px solid transparent;
    white-space: nowrap;
}

[data-theme="dark"] .badge-pill--r0 { background: #232119; color: #8a8272; border-color: #3a3729; }
[data-theme="dark"] .badge-pill--r1 { background: #33281c; color: #96826c; border-color: #4a3a28; }
[data-theme="dark"] .badge-pill--r2 { background: #43301f; color: #a8926e; border-color: #5a4530; }
[data-theme="dark"] .badge-pill--r3 { background: #573a22; color: #c0a378; border-color: #6a4f34; }
[data-theme="dark"] .badge-pill--r4 { background: #6e4526; color: #d4b080; border-color: #7a5638; }
[data-theme="dark"] .badge-pill--r5 { background: #8a5530; color: #ecc493; border-color: #96643c; }
[data-theme="dark"] .badge-pill--r6 { background: #ab6b40; color: #ffe0b3; border-color: #b87848; font-weight: 600; }
[data-theme="dark"] .badge-pill--r7 {
    background: #c67f52; color: #fff0d8; border-color: #f0c090; font-weight: 600;
    box-shadow: 0 0 6px rgba(212, 149, 106, 0.35);
}
[data-theme="dark"] .badge-pill--r8 {
    background: #d4956a; color: #fff8ee; border-color: #ffdcae; font-weight: 600;
    box-shadow: 0 0 10px rgba(212, 149, 106, 0.55);
}

[data-theme="light"] .badge-pill--r0 { background: #ece5d6; color: #7a6a54; border-color: #d8cdb8; }
[data-theme="light"] .badge-pill--r1 { background: #e2d5b8; color: #6d5c42; border-color: #cfc0a2; }
[data-theme="light"] .badge-pill--r2 { background: #d5c19a; color: #5c4a32; border-color: #c0aa7e; }
[data-theme="light"] .badge-pill--r3 { background: #c7ac7c; color: #4a3822; border-color: #ad9268; }
[data-theme="light"] .badge-pill--r4 { background: #b8975e; color: #3d2c1a; border-color: #9c7d48; }
[data-theme="light"] .badge-pill--r5 { background: #a37f45; color: #2e2011; border-color: #8a6a38; font-weight: 600; }
[data-theme="light"] .badge-pill--r6 { background: #8b5e3c; color: #fdf8f0; border-color: #6e4a2d; font-weight: 600; }
[data-theme="light"] .badge-pill--r7 {
    background: #6e4a2d; color: #fdf8f0; border-color: #523620; font-weight: 600;
    box-shadow: 0 0 6px rgba(139, 94, 60, 0.35);
}
[data-theme="light"] .badge-pill--r8 {
    background: #523620; color: #fdf8f0; border-color: #3a2513; font-weight: 600;
    box-shadow: 0 0 10px rgba(139, 94, 60, 0.5);
}

/* -- non-Classic theme styles: same ramp *shape*, but built from that theme's
   own --color-primary/--color-surface-2 via color-mix() so Forest/Cosmos/
   Ocean/Sunset each get their own tinted badge instead of inheriting
   Classic's brown. Higher specificity than the rules above (extra
   :not() attribute selector), so Classic is completely untouched — this
   only ever matches when data-theme-style is anything else. -- */
[data-theme="dark"]:not([data-theme-style="classic"]) .badge-pill--r0 { background: color-mix(in oklch, var(--color-primary) 6%, var(--color-surface-2)); color: var(--color-text-faint); border-color: var(--color-divider); }
[data-theme="dark"]:not([data-theme-style="classic"]) .badge-pill--r1 { background: color-mix(in oklch, var(--color-primary) 14%, var(--color-surface-2)); color: var(--color-text-muted); border-color: var(--color-divider); }
[data-theme="dark"]:not([data-theme-style="classic"]) .badge-pill--r2 { background: color-mix(in oklch, var(--color-primary) 24%, var(--color-surface-2)); color: var(--color-text-muted); border-color: var(--color-border); }
[data-theme="dark"]:not([data-theme-style="classic"]) .badge-pill--r3 { background: color-mix(in oklch, var(--color-primary) 36%, var(--color-surface-2)); color: var(--color-text); border-color: var(--color-border); }
[data-theme="dark"]:not([data-theme-style="classic"]) .badge-pill--r4 { background: color-mix(in oklch, var(--color-primary) 50%, var(--color-surface-2)); color: var(--color-text); border-color: var(--color-primary); }
[data-theme="dark"]:not([data-theme-style="classic"]) .badge-pill--r5 { background: color-mix(in oklch, var(--color-primary) 65%, var(--color-surface-2)); color: var(--color-text); border-color: var(--color-primary); font-weight: 600; }
[data-theme="dark"]:not([data-theme-style="classic"]) .badge-pill--r6 { background: color-mix(in oklch, var(--color-primary) 82%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-primary); font-weight: 600; }
[data-theme="dark"]:not([data-theme-style="classic"]) .badge-pill--r7 {
    background: var(--color-primary-hover); color: var(--color-text-inverse); border-color: var(--color-primary-hover); font-weight: 600;
    box-shadow: 0 0 6px color-mix(in oklch, var(--color-primary) 45%, transparent);
}
[data-theme="dark"]:not([data-theme-style="classic"]) .badge-pill--r8 {
    background: var(--color-primary-active); color: var(--color-text-inverse); border-color: var(--color-primary-active); font-weight: 600;
    box-shadow: 0 0 10px color-mix(in oklch, var(--color-primary) 65%, transparent);
}

[data-theme="light"]:not([data-theme-style="classic"]) .badge-pill--r0 { background: color-mix(in oklch, var(--color-primary) 8%, var(--color-surface-2)); color: var(--color-text-muted); border-color: var(--color-divider); }
[data-theme="light"]:not([data-theme-style="classic"]) .badge-pill--r1 { background: color-mix(in oklch, var(--color-primary) 18%, var(--color-surface-2)); color: var(--color-text-muted); border-color: var(--color-divider); }
[data-theme="light"]:not([data-theme-style="classic"]) .badge-pill--r2 { background: color-mix(in oklch, var(--color-primary) 30%, var(--color-surface-2)); color: var(--color-text); border-color: var(--color-border); }
[data-theme="light"]:not([data-theme-style="classic"]) .badge-pill--r3 { background: color-mix(in oklch, var(--color-primary) 44%, var(--color-surface-2)); color: var(--color-text); border-color: var(--color-border); }
[data-theme="light"]:not([data-theme-style="classic"]) .badge-pill--r4 { background: color-mix(in oklch, var(--color-primary) 58%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-primary); }
[data-theme="light"]:not([data-theme-style="classic"]) .badge-pill--r5 { background: color-mix(in oklch, var(--color-primary) 72%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-primary); font-weight: 600; }
[data-theme="light"]:not([data-theme-style="classic"]) .badge-pill--r6 { background: var(--color-primary); color: var(--color-text-inverse); border-color: var(--color-primary); font-weight: 600; }
[data-theme="light"]:not([data-theme-style="classic"]) .badge-pill--r7 {
    background: var(--color-primary-hover); color: var(--color-text-inverse); border-color: var(--color-primary-hover); font-weight: 600;
    box-shadow: 0 0 6px color-mix(in oklch, var(--color-primary) 45%, transparent);
}
[data-theme="light"]:not([data-theme-style="classic"]) .badge-pill--r8 {
    background: var(--color-primary-active); color: var(--color-text-inverse); border-color: var(--color-primary-active); font-weight: 600;
    box-shadow: 0 0 10px color-mix(in oklch, var(--color-primary) 60%, transparent);
}

/* =============================================================================
// ACHIEVEMENTS MODAL (TASK-122)
// ============================================================================= */
.achievements-summary-bar {
    height: 6px;
    background: var(--color-divider);
    border-radius: var(--radius-full);
    overflow: hidden;
    margin-bottom: var(--space-5);
}

.achievements-summary-fill {
    height: 100%;
    background: var(--color-primary);
    transition: width var(--transition);
}

.modal .achievements-focus-summary {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-bottom: var(--space-4);
}

/* -- focused achievements view: current/next badge card (renderFocusedAchievementsModal) -- */
.achievement-focus-card {
    background: var(--color-surface-2);
    border: 1px solid var(--color-primary-highlight);
    border-radius: var(--radius-lg);
    padding: var(--space-4);
    margin-bottom: var(--space-5);
    box-shadow: var(--shadow-sm);
}

.achievement-focus-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-3);
}

.achievement-focus-side {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
}

.achievement-focus-side--right {
    flex-direction: row-reverse;
    text-align: right;
}

.achievement-focus-icon {
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    border-radius: var(--radius-full);
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    border: 1.5px solid var(--color-primary);
    box-shadow: 0 0 8px color-mix(in oklch, var(--color-primary) 35%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
}

.achievement-focus-icon--muted {
    opacity: 0.5;
    border-style: dashed;
}

.achievement-focus-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-faint);
}

.achievement-focus-name {
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-text);
}

.achievement-focus-fraction {
    font-size: var(--text-xs);
    color: var(--color-text-faint);
    margin-top: var(--space-1);
    text-align: right;
}

.achievement-focus-progress-track {
    height: 5px;
    background: var(--color-divider);
    border-radius: var(--radius-full);
    overflow: hidden;
}

.achievement-focus-progress-fill {
    height: 100%;
    background: var(--color-primary);
    box-shadow: 0 0 6px color-mix(in oklch, var(--color-primary) 45%, transparent);
}

.achievements-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-bottom: var(--space-5);
}

.achievement-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    background: var(--color-surface-2);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-lg);
    padding: var(--space-2) var(--space-3);
}

.achievement-row--unlocked {
    border-color: var(--color-primary-highlight);
    background: var(--color-surface);
}

.achievement-row-icon {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-full);
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
}

/* -- badge icon prestige ranks (badgeIconTierClass() in achievements.js) --
   One class per badge (r0 novice .. r8 sage). Classic light/dark use the
   exact hex ramp from the approved v7 mockup (background stays in the warm
   brown family the whole way up — it never goes pale — while the icon
   itself goes from muted to bright white, which is what makes the r6-r8
   page-line/stack detail in the SVG, drawn as dark strokes for contrast
   against a *light* book, actually visible). Non-Classic theme styles
   reuse the same shape via color-mix() off that theme's own
   --color-primary, following the .badge-pill --r0..r8 precedent. The last
   3 ranks add a dashed outer ring, and the top rank (sage) a glow. Ring/
   glow color is derived from each rule's own border via currentColor so it
   doesn't need separate per-theme overrides. */
.achievement-row-icon.achievement-icon-r6,
.achievement-focus-icon.achievement-icon-r6,
.achievement-row-icon.achievement-icon-r7,
.achievement-focus-icon.achievement-icon-r7,
.achievement-row-icon.achievement-icon-r8,
.achievement-focus-icon.achievement-icon-r8 {
    position: relative;
}

.achievement-row-icon.achievement-icon-r6::before,
.achievement-focus-icon.achievement-icon-r6::before,
.achievement-row-icon.achievement-icon-r7::before,
.achievement-focus-icon.achievement-icon-r7::before,
.achievement-row-icon.achievement-icon-r8::before,
.achievement-focus-icon.achievement-icon-r8::before {
    content: '';
    position: absolute;
    inset: -4px;
    border-radius: 50%;
    border: 1px dashed color-mix(in oklch, var(--achievement-icon-ring, currentColor) 60%, transparent);
}

.achievement-row-icon.achievement-icon-r8,
.achievement-focus-icon.achievement-icon-r8 {
    box-shadow: 0 0 10px color-mix(in oklch, var(--achievement-icon-ring, currentColor) 55%, transparent);
}

[data-theme="dark"] .achievement-row-icon.achievement-icon-r0, [data-theme="dark"] .achievement-focus-icon.achievement-icon-r0 { background: #232119; color: #5a5446; border: 1px solid #3a3729; }
[data-theme="dark"] .achievement-row-icon.achievement-icon-r1, [data-theme="dark"] .achievement-focus-icon.achievement-icon-r1 { background: #26221a; color: #75695490; border: 1px solid #453f2f; }
[data-theme="dark"] .achievement-row-icon.achievement-icon-r2, [data-theme="dark"] .achievement-focus-icon.achievement-icon-r2 { background: #2c2519; color: #8a7250; border: 1px solid #4a4030; }
[data-theme="dark"] .achievement-row-icon.achievement-icon-r3, [data-theme="dark"] .achievement-focus-icon.achievement-icon-r3 { background: #332a1a; color: #a8875a; border: 1px solid #5a4830; }
[data-theme="dark"] .achievement-row-icon.achievement-icon-r4, [data-theme="dark"] .achievement-focus-icon.achievement-icon-r4 { background: #3a2d1c; color: #c8a06a; border: 1.5px solid #6e5738; }
[data-theme="dark"] .achievement-row-icon.achievement-icon-r5, [data-theme="dark"] .achievement-focus-icon.achievement-icon-r5 { background: #4a331c; color: #d4956a; border: 1.5px solid #8a6942; }
[data-theme="dark"] .achievement-row-icon.achievement-icon-r6, [data-theme="dark"] .achievement-focus-icon.achievement-icon-r6 { background: #5c3e1e; color: #f0d9c0; border: 1.5px solid #d4956a; --achievement-icon-ring: #d4956a; }
[data-theme="dark"] .achievement-row-icon.achievement-icon-r7, [data-theme="dark"] .achievement-focus-icon.achievement-icon-r7 { background: #6e4820; color: #faf4ea; border: 1.5px solid #e8a87a; --achievement-icon-ring: #e8a87a; }
[data-theme="dark"] .achievement-row-icon.achievement-icon-r8, [data-theme="dark"] .achievement-focus-icon.achievement-icon-r8 { background: #8b5e28; color: #ffffff; border: 1.5px solid #f0b888; --achievement-icon-ring: #f0b888; }

[data-theme="light"] .achievement-row-icon.achievement-icon-r0, [data-theme="light"] .achievement-focus-icon.achievement-icon-r0 { background: #ece5d6; color: #7a6a54; border: 1px solid #d8cdb8; }
[data-theme="light"] .achievement-row-icon.achievement-icon-r1, [data-theme="light"] .achievement-focus-icon.achievement-icon-r1 { background: #e2d5b8; color: #6d5c42; border: 1px solid #cfc0a2; }
[data-theme="light"] .achievement-row-icon.achievement-icon-r2, [data-theme="light"] .achievement-focus-icon.achievement-icon-r2 { background: #d5c19a; color: #5c4a32; border: 1px solid #c0aa7e; }
[data-theme="light"] .achievement-row-icon.achievement-icon-r3, [data-theme="light"] .achievement-focus-icon.achievement-icon-r3 { background: #c7ac7c; color: #4a3822; border: 1px solid #ad9268; }
[data-theme="light"] .achievement-row-icon.achievement-icon-r4, [data-theme="light"] .achievement-focus-icon.achievement-icon-r4 { background: #b8975e; color: #3d2c1a; border: 1.5px solid #9c7d48; }
[data-theme="light"] .achievement-row-icon.achievement-icon-r5, [data-theme="light"] .achievement-focus-icon.achievement-icon-r5 { background: #a37f45; color: #2e2011; border: 1.5px solid #8a6a38; }
[data-theme="light"] .achievement-row-icon.achievement-icon-r6, [data-theme="light"] .achievement-focus-icon.achievement-icon-r6 { background: #8b5e3c; color: #fdf8f0; border: 1.5px solid #6e4a2d; --achievement-icon-ring: #6e4a2d; }
[data-theme="light"] .achievement-row-icon.achievement-icon-r7, [data-theme="light"] .achievement-focus-icon.achievement-icon-r7 { background: #6e4a2d; color: #fdf8f0; border: 1.5px solid #523620; --achievement-icon-ring: #523620; }
[data-theme="light"] .achievement-row-icon.achievement-icon-r8, [data-theme="light"] .achievement-focus-icon.achievement-icon-r8 { background: #523620; color: #fdf8f0; border: 1.5px solid #3a2513; --achievement-icon-ring: #3a2513; }

[data-theme="dark"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r0, [data-theme="dark"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r0 { background: color-mix(in oklch, var(--color-primary) 6%, var(--color-surface-2)); color: var(--color-text-faint); border-color: var(--color-divider); }
[data-theme="dark"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r1, [data-theme="dark"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r1 { background: color-mix(in oklch, var(--color-primary) 14%, var(--color-surface-2)); color: var(--color-text-muted); border-color: var(--color-divider); }
[data-theme="dark"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r2, [data-theme="dark"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r2 { background: color-mix(in oklch, var(--color-primary) 22%, var(--color-surface-2)); color: var(--color-text-muted); border-color: var(--color-border); }
[data-theme="dark"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r3, [data-theme="dark"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r3 { background: color-mix(in oklch, var(--color-primary) 32%, var(--color-surface-2)); color: var(--color-text); border-color: var(--color-border); }
[data-theme="dark"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r4, [data-theme="dark"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r4 { background: color-mix(in oklch, var(--color-primary) 44%, var(--color-surface-2)); color: var(--color-text); border-color: var(--color-primary); }
[data-theme="dark"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r5, [data-theme="dark"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r5 { background: color-mix(in oklch, var(--color-primary) 56%, var(--color-surface-2)); color: var(--color-text); border-color: var(--color-primary); }
[data-theme="dark"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r6, [data-theme="dark"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r6 { background: color-mix(in oklch, var(--color-primary) 68%, var(--color-surface-2)); color: var(--color-text); border-color: var(--color-primary); --achievement-icon-ring: var(--color-primary); }
[data-theme="dark"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r7, [data-theme="dark"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r7 { background: color-mix(in oklch, var(--color-primary) 80%, var(--color-surface-2)); color: color-mix(in oklch, var(--color-text) 80%, white); border-color: var(--color-primary-hover); --achievement-icon-ring: var(--color-primary-hover); }
[data-theme="dark"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r8, [data-theme="dark"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r8 { background: color-mix(in oklch, var(--color-primary) 92%, var(--color-surface-2)); color: white; border-color: var(--color-primary-active); --achievement-icon-ring: var(--color-primary-active); }

[data-theme="light"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r0, [data-theme="light"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r0 { background: color-mix(in oklch, var(--color-primary) 8%, var(--color-surface-2)); color: var(--color-text-muted); border-color: var(--color-divider); }
[data-theme="light"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r1, [data-theme="light"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r1 { background: color-mix(in oklch, var(--color-primary) 18%, var(--color-surface-2)); color: var(--color-text-muted); border-color: var(--color-divider); }
[data-theme="light"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r2, [data-theme="light"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r2 { background: color-mix(in oklch, var(--color-primary) 30%, var(--color-surface-2)); color: var(--color-text); border-color: var(--color-border); }
[data-theme="light"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r3, [data-theme="light"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r3 { background: color-mix(in oklch, var(--color-primary) 44%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-border); }
[data-theme="light"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r4, [data-theme="light"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r4 { background: color-mix(in oklch, var(--color-primary) 58%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-primary); }
[data-theme="light"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r5, [data-theme="light"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r5 { background: color-mix(in oklch, var(--color-primary) 70%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-primary); }
[data-theme="light"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r6, [data-theme="light"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r6 { background: var(--color-primary); color: var(--color-text-inverse); border-color: var(--color-primary); --achievement-icon-ring: var(--color-primary); }
[data-theme="light"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r7, [data-theme="light"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r7 { background: var(--color-primary-hover); color: var(--color-text-inverse); border-color: var(--color-primary-hover); --achievement-icon-ring: var(--color-primary-hover); }
[data-theme="light"]:not([data-theme-style="classic"]) .achievement-row-icon.achievement-icon-r8, [data-theme="light"]:not([data-theme-style="classic"]) .achievement-focus-icon.achievement-icon-r8 { background: var(--color-primary-active); color: var(--color-text-inverse); border-color: var(--color-primary-active); --achievement-icon-ring: var(--color-primary-active); }

/* Noir light overrides r0-r5 of the generic ramp above. Noir's --color-primary
   (#26262a) is near-black, unlike the medium-lightness primaries the generic
   percentages were tuned for, so at 8-58% mix its background is already too
   dark for the book SVGs' embedded stroke="#000" detail lines (see
   ACHIEVEMENT_META icons in achievements.js) to read against a dark fill, yet
   still too pale for a light fill to have real contrast. Darker mix stops
   here keep every icon fill light (readable detail lines, and a consistent
   ink-on-paper look across the whole rank ladder) with real contrast the
   whole way up; r6-r8 already land on --color-primary/-hover/-active, which
   are dark enough in Noir without an override.  */
[data-theme="light"][data-theme-style="noir"] .achievement-row-icon.achievement-icon-r0, [data-theme="light"][data-theme-style="noir"] .achievement-focus-icon.achievement-icon-r0 { background: color-mix(in oklch, var(--color-primary) 20%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-divider); }
[data-theme="light"][data-theme-style="noir"] .achievement-row-icon.achievement-icon-r1, [data-theme="light"][data-theme-style="noir"] .achievement-focus-icon.achievement-icon-r1 { background: color-mix(in oklch, var(--color-primary) 32%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-divider); }
[data-theme="light"][data-theme-style="noir"] .achievement-row-icon.achievement-icon-r2, [data-theme="light"][data-theme-style="noir"] .achievement-focus-icon.achievement-icon-r2 { background: color-mix(in oklch, var(--color-primary) 45%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-border); }
[data-theme="light"][data-theme-style="noir"] .achievement-row-icon.achievement-icon-r3, [data-theme="light"][data-theme-style="noir"] .achievement-focus-icon.achievement-icon-r3 { background: color-mix(in oklch, var(--color-primary) 60%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-border); }
[data-theme="light"][data-theme-style="noir"] .achievement-row-icon.achievement-icon-r4, [data-theme="light"][data-theme-style="noir"] .achievement-focus-icon.achievement-icon-r4 { background: color-mix(in oklch, var(--color-primary) 72%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-primary); }
[data-theme="light"][data-theme-style="noir"] .achievement-row-icon.achievement-icon-r5, [data-theme="light"][data-theme-style="noir"] .achievement-focus-icon.achievement-icon-r5 { background: color-mix(in oklch, var(--color-primary) 85%, var(--color-surface-2)); color: var(--color-text-inverse); border-color: var(--color-primary); }

.achievement-row-body {
    flex: 1;
    min-width: 0;
}

.achievement-row-status {
    flex-shrink: 0;
    display: flex;
    align-items: center;
}

.achievement-row-title-wrap {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.achievement-row-title {
    display: block;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text);
}

/* Info icon + tooltip for achievement rows that need a disclaimer (currently just
   "Начитанность"/authors_10 — see renderAllAchievementsModal() in auth.js). Same
   click-to-toggle pattern as the public share page's badge tooltip (share.js) —
   surface/border tokens rather than a stark inversion, so it stays legible and
   theme-aware across all theme styles. */
.achievement-info-btn {
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    transition: color var(--transition), background var(--transition);
}

.achievement-info-btn:hover {
    background: var(--color-primary);
    color: var(--color-text-inverse);
}

.achievement-info-tooltip {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 5;
    width: max-content;
    max-width: 15rem;
    padding: var(--space-2) var(--space-3);
    background: var(--color-surface-2);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--text-xs);
    line-height: 1.4;
    font-weight: 400;
    text-transform: none;
    box-shadow: var(--shadow-lg);
    opacity: 0;
    transform: translateY(-4px);
    pointer-events: none;
    transition: opacity 180ms ease, transform 180ms ease;
}

.achievement-info-tooltip.visible {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.achievement-row-condition {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-top: 1px;
}

.achievement-row-fraction {
    flex-shrink: 0;
    font-size: var(--text-xs);
    color: var(--color-text-faint);
}

.achievement-row-check {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--color-primary);
    color: var(--color-text-inverse);
    display: flex;
    align-items: center;
    justify-content: center;
}

.achievement-row-progress-track {
    height: 3px;
    background: var(--color-divider);
    border-radius: var(--radius-full);
    overflow: hidden;
    margin-top: var(--space-2);
}

.achievement-row-progress-fill {
    height: 100%;
    background: var(--color-text-faint);
}

.achievement-row-apply-btn {
    flex-shrink: 0;
    background: var(--color-primary);
    color: var(--color-text-inverse);
    border: none;
    border-radius: var(--radius-md);
    padding: 4px 10px;
    font-size: var(--text-xs);
    font-weight: 500;
    cursor: pointer;
    white-space: nowrap;
}

.achievements-expand-btn {
    width: 100%;
    background: transparent;
    color: var(--color-text-muted);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: var(--space-3);
    font-size: var(--text-sm);
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition);
}

.achievements-expand-btn:hover {
    border-color: var(--color-primary);
    color: var(--color-text);
}

/* -- unlock celebration modal (checkForNewAchievements() -> showAchievementUnlockModal()) --
   Selectors below are prefixed with .modal so their specificity (2 classes)
   beats the shared ".modal p" rule (1 class + 1 element — same specificity
   tier as 2 classes gets compared class-tier first, and .modal p's element
   tier only matters as a tiebreaker, so plain ".achievement-unlock-title"
   alone was actually losing to ".modal p"'s own margin-bottom). */
.modal .achievement-unlock-heading {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    text-align: center;
    margin-bottom: var(--space-4);
}

.achievement-unlock-icon-wrap {
    position: relative;
    width: 88px;
    height: 88px;
    margin: 0 auto var(--space-4);
    display: flex;
    align-items: center;
    justify-content: center;
}

.achievement-unlock-icon-wrap::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: radial-gradient(circle, color-mix(in oklch, var(--color-primary) 35%, transparent) 0%, transparent 72%);
}

.achievement-unlock-icon {
    position: relative;
    width: 64px;
    height: 64px;
    border-radius: var(--radius-full);
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    border: 1.5px solid var(--color-primary);
    box-shadow: 0 0 16px color-mix(in oklch, var(--color-primary) 50%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
}

.modal .achievement-unlock-title {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text);
    text-align: center;
    margin-bottom: var(--space-1);
}

.modal .achievement-unlock-desc {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    text-align: center;
    margin-bottom: var(--space-4);
}

.achievement-unlock-reward-box {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    width: fit-content;
    margin: 0 auto;
    background: var(--color-primary-highlight);
    border: 1px solid var(--color-primary);
    border-radius: var(--radius-full);
    padding: var(--space-2) var(--space-4);
    color: var(--color-primary);
    font-size: var(--text-sm);
    font-weight: 500;
}

/* -- quotes-visibility picker (TASK-129) --
   Each option states its consequence, not just its name: the setting ships
   switched on for every account, so the first encounter has to explain what it
   already does rather than leave "favourites only" to interpretation. */
/* Settings-row icon mirrors the chosen visibility (set in renderQuotesVisibilityRow).
   Constrained to 15px so it matches the other export-btn icons, since the shared
   VISIBILITY_ICONS are authored at 17px for the modal. */
.settings-visibility-icon {
    display: inline-flex;
    flex-shrink: 0;
}

.settings-visibility-icon svg {
    width: 15px;
    height: 15px;
}

.visibility-options {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.visibility-option {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-3);
    border: none;
    border-radius: var(--radius-lg);
    background: transparent;
    font-family: var(--font-body);
    text-align: left;
    cursor: pointer;
    transition: background var(--transition);
}

.visibility-option:hover {
    background: var(--color-surface-offset);
}

/* A neutral step lighter than the modal (which is itself surface-2), matching
   the mockup — a warm accent tint here read as too heavy. The accent stays on
   the icon, which is enough to mark the choice. */
.visibility-option--selected {
    background: var(--color-surface-dynamic);
}

.visibility-option-icon {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--color-surface-2);
    color: var(--color-text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background var(--transition), color var(--transition);
}

.visibility-option--selected .visibility-option-icon {
    background: var(--color-primary);
    color: var(--color-text-inverse);
}

.visibility-option-text {
    flex: 1;
    min-width: 0;
}

.visibility-option-name {
    display: block;
    font-size: var(--text-sm);
    color: var(--color-text);
}

.visibility-option-desc {
    display: block;
    margin-top: 2px;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    line-height: 1.4;
}

/* -- pending friend requests: header dot + menu count (TASK-129) --
   The avatar only says "something is waiting"; the number lives on the Friends
   row of the menu the dot leads to. Anchored on .account-menu (already
   position:relative) rather than inside the avatar button, whose innerHTML
   updateHeaderAccount() rewrites on every render. */
.account-badge-dot {
    position: absolute;
    top: -1px;
    right: -1px;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--color-primary);
    /* Ring in the page colour, not a border — without it the dot merges into
       the avatar's edge, badly in light themes. */
    box-shadow: 0 0 0 2px var(--color-bg);
    pointer-events: none;
}

.account-menu-count {
    margin-left: auto;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: var(--radius-full);
    background: var(--color-primary);
    color: var(--color-text-inverse);
    font-size: var(--text-xs);
    font-weight: 500;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* =============================================================================
// FRIENDS (TASK-129)
// The friends screen itself stays in the *viewer's* theme — only an individual
// friend's profile page is painted in that friend's theme. Rows reuse the
// surface/divider tokens so they read as siblings of the settings cards.
// ============================================================================= */
/* Same page container as .list-section / .add-section / .settings-section —
   every screen shares one width and gutter, so Friends must not be full-bleed. */
.friends-section {
    padding: var(--space-8) var(--space-6);
    max-width: var(--content-default);
    margin: 0 auto;
}

/* =========================================================================
   STATS (TASK-136) — collection statistics screen
   Header, Overview tiles, hero cards, favorites ring, 12-month activity chart,
   top authors/tags, "interesting" facts strip, and the empty state.
   ========================================================================= */
.stats-section {
    padding: var(--space-8) var(--space-6);
    max-width: var(--content-default);
    margin: 0 auto;
}

/* Plain <div>, not <header> — a bare <header> would inherit the app's sticky top-bar rule
   (background panel, border-bottom, blur, sticky). Title left, subtitle right on one baseline. */
.stats-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    margin-bottom: var(--space-6);
}

.stats-header h2 {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 500;
}

.stats-subtitle {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

.stats-section-label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-text-faint);
    font-weight: 600;
    margin: var(--space-6) 0 var(--space-3);
}

/* ── Overview tiles ─────────────────────────────────────────────────────── */
.stats-tiles {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-3);
}

.stats-tile {
    background: var(--color-surface);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-lg);
    padding: var(--space-4);
}

.stats-tile-num {
    font-size: var(--text-lg);
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.1;
}

.stats-tile-lbl {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-top: var(--space-1);
}

.stats-tile-delta {
    font-size: var(--text-xs);
    color: var(--color-primary);
    margin-top: var(--space-2);
    min-height: 1.1em;
}

/* ── Hero cards ─────────────────────────────────────────────────────────── */
.stats-hero-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.stats-hero {
    background: var(--color-surface);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-xl);
    padding: var(--space-4);
    position: relative;
    overflow: hidden;
}

.stats-hero-glyph {
    position: absolute;
    right: var(--space-4);
    font-family: Georgia, 'Times New Roman', serif;
    line-height: 1;
    color: var(--color-primary);
    opacity: 0.1;
    pointer-events: none;
    user-select: none;
}

/* The quote mark and the hash have very different ink footprints in a serif font, so each is
   sized/placed on its own to end up looking visually matched in the corner. */
.stats-hero-glyph--quote {
    font-size: 5.5rem;
    top: 0.15em; /* the quote mark's ink sits high in the em box; push down to match the hash */
}

.stats-hero-glyph--hash {
    font-size: 2.75rem;
    top: 0.25em;
}

.stats-hero-cap,
.stats-hero-big,
.stats-hero-meta {
    position: relative; /* keep text above the decorative glyph */
}

.stats-hero-cap {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-faint);
    font-weight: 600;
}

.stats-hero-big {
    font-size: var(--text-base);
    font-weight: 700;
    margin-top: var(--space-2);
    word-break: break-word;
}

.stats-hero-meta {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-top: var(--space-1);
}

/* ── Favorites ring ─────────────────────────────────────────────────────── */
.stats-card {
    background: var(--color-surface);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-xl);
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
}

.stats-ring-row {
    margin-top: var(--space-3);
}

.stats-ring-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.stats-ring {
    position: relative;
    width: 140px;
    height: 140px;
}

.stats-ring svg {
    width: 100%;
    height: 100%;
    display: block;
}

.stats-ring-center {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.stats-ring-pct {
    font-size: var(--text-lg);
    font-weight: 700;
    line-height: 1.1;
}

.stats-ring-pl {
    font-size: 0.72rem;
    color: var(--color-text-muted);
    line-height: 1.2;
    max-width: 96px;
}

.stats-ring-legend {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-1);
    margin-top: var(--space-4);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.stats-dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: var(--radius-sm);
    margin-right: var(--space-1);
    vertical-align: middle;
}

/* Favorites use --color-primary — the same accent as the QOD "В избранном" button — so the
   favorite colour is consistent app-wide and reads as native in every theme (not gold, which
   clashed with e.g. Sunset / Cosmos / Classic). */
.stats-dot-fav { background: var(--color-primary); }
.stats-dot-plain { background: var(--color-surface-dynamic); }

.stats-ring-track { stroke: var(--color-surface-dynamic); }
.stats-ring-arc {
    stroke: var(--color-primary);
    transition: stroke-dashoffset 0.7s ease;
}

/* ── Row 2: ring + activity chart ───────────────────────────────────────── */
.stats-row2 {
    display: grid;
    grid-template-columns: 230px 1fr;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.stats-chart-card {
    display: flex;
    flex-direction: column;
}

.stats-chart-head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
    margin-bottom: var(--space-4);
}

.stats-chart-title {
    font-size: var(--text-sm);
    font-weight: 600;
}

.stats-chart-peak {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    white-space: nowrap;
}

.stats-bars {
    display: flex;
    align-items: flex-end;
    gap: var(--space-2);
    flex: 1;
    min-height: 120px;
}

.stats-barcol {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    height: 120px;
    justify-content: flex-end;
}

/* .stats-actbar (not .stats-bar) — .stats-bar is already the "Мои цитаты" count bar. */
.stats-actbar {
    width: 100%;
    max-width: 26px;
    background: var(--color-surface-dynamic);
    border-radius: var(--radius-sm) var(--radius-sm) 2px 2px;
    transition: height 0.5s ease;
}

.stats-actbar-peak { background: var(--color-primary); }

.stats-actbar-val {
    font-size: 0.65rem;
    color: var(--color-text-muted);
    min-height: 0.9em;
}

.stats-actbar-m {
    font-size: 0.65rem;
    color: var(--color-text-faint);
}

/* ── Row 3: top authors + top tags ──────────────────────────────────────── */
.stats-row3 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.stats-rank-list {
    margin-top: var(--space-3);
}

.stats-rank {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin: var(--space-3) 0;
}

.stats-rank-rk {
    width: 18px;
    text-align: center;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--color-text-faint);
}

.stats-rank-nm {
    flex: 0 0 120px;
    font-size: var(--text-xs);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.stats-rank-track {
    flex: 1;
    height: 8px;
    background: var(--color-surface-offset);
    border-radius: var(--radius-full);
    overflow: hidden;
}

.stats-rank-fill {
    display: block;
    height: 100%;
    background: var(--color-accent);
    border-radius: var(--radius-full);
    transition: width 0.6s ease;
}

.stats-rank-ct {
    width: 28px;
    text-align: right;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.stats-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-3);
}

.stats-chip {
    background: var(--color-primary-highlight);
    color: var(--color-primary-hover);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    padding: var(--space-1) var(--space-3);
    font-size: var(--text-xs);
}

.stats-chip b {
    color: var(--color-text);
    margin-left: var(--space-1);
    font-weight: 600;
}

.stats-nodata {
    margin-top: var(--space-3);
    font-size: var(--text-xs);
    color: var(--color-text-faint);
}

/* Inline empty state inside a card (top authors / top tags with no data yet). */
.stats-card-empty {
    flex: 1; /* fill the card's stretched height so icon + text sit dead-centre */
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: var(--space-2);
    min-height: 120px;
    padding: var(--space-4) 0;
}

.stats-card-empty-icon {
    color: var(--color-text-faint);
    opacity: 0.7;
}

.stats-card-empty-icon svg {
    width: 30px;
    height: 30px;
    display: block;
}

.stats-card-empty-text {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    max-width: 220px;
}

/* ── "Interesting" facts ────────────────────────────────────────────────── */
.stats-facts {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-3);
}

.stats-fact {
    background: var(--color-surface-offset);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-lg);
    padding: var(--space-4);
}

.stats-fact-icon {
    font-size: var(--text-base);
    margin-bottom: var(--space-1);
    opacity: 0.8;
}

.stats-fact-val {
    font-size: var(--text-base);
    font-weight: 700;
}

.stats-fact-lbl {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-top: var(--space-1);
}

/* ── Metric-card grid (registry cards, free + Plus) ──────────────────────── */
.stats-metric-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

.stats-card-sub {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin: 2px 0 var(--space-4);
}

/* ── Growth area chart ──────────────────────────────────────────────────── */
.stats-growth-svg {
    width: 100%;
    height: 96px;
    display: block;
    margin-top: auto;
}

.stats-growth-fill { fill: var(--color-primary); fill-opacity: 0.14; }
.stats-growth-line { fill: none; stroke: var(--color-primary); stroke-width: 2; }

/* ── Length histogram ───────────────────────────────────────────────────── */
.stats-hbars {
    display: flex;
    align-items: flex-end;
    gap: var(--space-4);
    height: 110px;
    padding: 0 var(--space-2);
    margin-top: auto;
}

.stats-hbar-col {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
    height: 100%;
}

.stats-hbar {
    width: 100%;
    max-width: 46px;
    background: var(--color-primary);
    border-radius: var(--radius-sm) var(--radius-sm) 2px 2px;
    min-height: 2px;
}

.stats-hbar-val { font-size: var(--text-xs); color: var(--color-text-muted); }
.stats-hbar-lbl { font-size: var(--text-xs); color: var(--color-text-faint); }

/* ── Card header with an action (used by the clickable "book" card) ─────── */
.stats-card-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
}

.stats-book-cycle {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-full);
    background: var(--color-surface-2);
    border: 1px solid var(--color-border);
    color: var(--color-text-muted);
    cursor: pointer;
    transition: color var(--transition), border-color var(--transition);
}

.stats-book-cycle:hover { color: var(--color-primary); border-color: var(--color-text-faint); }

/* ── Collection as a book ───────────────────────────────────────────────── */
.stats-book {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    margin-top: var(--space-4);
}

.stats-book--clickable {
    cursor: pointer;
    border-radius: var(--radius-lg);
    padding: var(--space-2);
    margin-left: calc(var(--space-2) * -1);
    transition: background 0.22s ease;
}

.stats-book--clickable:hover { background: var(--color-surface-2); }

/* Plays on cycle (class added in cycleStatsBook) — a quick fade+lift so the swap is felt. */
.stats-book-anim { animation: statsBookSwap 0.32s ease; }

@keyframes statsBookSwap {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

.stats-book-ic { font-size: var(--text-2xl); opacity: 0.8; }
.stats-book-val { font-size: var(--text-lg); font-weight: 700; line-height: 1.1; }
.stats-book-sub { font-size: var(--text-xs); color: var(--color-text-muted); margin-top: var(--space-1); }

/* ── Language stacked bar ───────────────────────────────────────────────── */
.stats-langbar {
    display: flex;
    height: 14px;
    border-radius: var(--radius-full);
    overflow: hidden;
    margin-top: auto;
}

.stats-langbar > span { display: block; }

/* Shared colour classes for both bar segments and legend dots — warm palette, no gold. */
.stats-langc-ru { background: var(--color-primary); }
.stats-langc-en { background: color-mix(in oklab, var(--color-primary) 42%, var(--color-surface-dynamic)); }
.stats-langc-other { background: var(--color-text-muted); }

.stats-lang-legend {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    font-size: var(--text-sm);
    margin-top: var(--space-4);
}

.stats-lang-row { display: flex; align-items: center; gap: var(--space-2); }
.stats-lang-name { color: var(--color-text-muted); }
.stats-lang-pct { margin-left: auto; font-weight: 700; }
.stats-lang-count { width: 40px; text-align: right; font-size: var(--text-xs); color: var(--color-text-faint); }

/* ── Hall of fame ───────────────────────────────────────────────────────── */
.stats-hall { display: flex; flex-direction: column; gap: var(--space-3); }

.stats-hall-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-size: var(--text-sm);
}

.stats-hall-ic { font-size: var(--text-base); width: 22px; text-align: center; }
.stats-hall-lbl { color: var(--color-text-muted); }
.stats-hall-val { margin-left: auto; font-weight: 600; text-align: right; }

/* ── Tempo (this vs last quarter) ───────────────────────────────────────── */
.stats-tempo {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: var(--space-5);
    height: 120px;
    margin-top: auto;
}

.stats-tempo-col {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
    height: 100%;
}

.stats-tempo-bar {
    width: 44px;
    border-radius: var(--radius-sm) var(--radius-sm) 2px 2px;
    min-height: 2px;
}

.stats-tempo-bar--prev { background: var(--color-surface-dynamic); }
.stats-tempo-bar--cur { background: var(--color-primary); }
.stats-tempo-n { font-size: var(--text-xs); color: var(--color-text-muted); }
.stats-tempo-lbl { font-size: var(--text-xs); color: var(--color-text-faint); }

.stats-tempo-delta {
    align-self: center;
    margin-bottom: var(--space-6);
    font-size: var(--text-lg);
    font-weight: 700;
    color: var(--color-primary);
}

.stats-tempo-delta.is-flat { color: var(--color-text-muted); }

/* ── Epigraph Plus section ──────────────────────────────────────────────── */
.stats-plus-label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--color-plus);
}

.stats-plus-teaser {
    position: relative;
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-xl);
    overflow: hidden;
    min-height: 250px;
    margin-top: var(--space-3);
}

.stats-plus-teaser-preview {
    padding: var(--space-5);
    filter: blur(3px);
    opacity: 0.6;
    pointer-events: none;
}

.stats-teaser-heat {
    display: grid;
    grid-template-rows: repeat(7, 1fr);
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 3px;
    height: 200px;
}

/* 5 intensity levels, dark base → warm accent, theme-aware (nod to a real contribution graph). */
.stats-teaser-heat span {
    aspect-ratio: 1;
    border-radius: 2px;
    background: var(--color-surface-dynamic);
}
.stats-teaser-heat span.l1 { background: color-mix(in oklab, var(--color-primary) 25%, var(--color-surface-dynamic)); }
.stats-teaser-heat span.l2 { background: color-mix(in oklab, var(--color-primary) 50%, var(--color-surface-dynamic)); }
.stats-teaser-heat span.l3 { background: color-mix(in oklab, var(--color-primary) 75%, var(--color-surface-dynamic)); }
.stats-teaser-heat span.l4 { background: var(--color-primary); }

.stats-plus-teaser-over {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: var(--space-2);
    padding: var(--space-6);
    background: linear-gradient(180deg,
        oklch(from var(--color-bg) l c h / 0.35),
        oklch(from var(--color-bg) l c h / 0.78));
}

.stats-plus-lock {
    flex: none; /* column-flex item mustn't shrink vertically — keeps the badge a circle, not a pill */
    width: 46px;
    height: 46px;
    border-radius: var(--radius-full);
    background: var(--color-plus);
    color: var(--color-plus-ink);
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: var(--space-1);
}

.stats-plus-teaser-title {
    font-size: var(--text-base);
    font-weight: 700;
}

.stats-plus-teaser-text {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    max-width: 380px;
}

.stats-plus-teaser-cta {
    margin-top: var(--space-3);
    background: var(--color-surface-dynamic);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    font: inherit;
    font-weight: 700;
    font-size: var(--text-sm);
    padding: var(--space-3) var(--space-6);
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition);
}

.stats-plus-teaser-cta:hover {
    background: var(--color-surface-offset);
    border-color: var(--color-text-faint);
}

/* ── Empty state ────────────────────────────────────────────────────────── */
.stats-empty {
    text-align: center;
    padding: var(--space-16) var(--space-6);
}

.stats-empty-glyph {
    color: var(--color-text-faint);
    opacity: 0.7;
}

.stats-empty-title {
    font-size: var(--text-lg);
    font-weight: 700;
    margin-top: var(--space-4);
}

.stats-empty-text {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-top: var(--space-2);
    max-width: 340px;
    margin-left: auto;
    margin-right: auto;
}

.stats-empty-btn {
    margin-top: var(--space-5);
    background: var(--color-primary);
    color: var(--color-text-inverse);
    border: none;
    font: inherit;
    font-weight: 600;
    font-size: var(--text-sm);
    padding: var(--space-3) var(--space-6);
    border-radius: var(--radius-full);
    cursor: pointer;
}

.stats-empty-btn:hover { background: var(--color-primary-hover); }

/* ── Responsive ─────────────────────────────────────────────────────────── */
@media (max-width: 640px) {
    .stats-tiles { grid-template-columns: repeat(2, 1fr); }
    .stats-hero-row,
    .stats-row2,
    .stats-row3,
    .stats-metric-grid,
    .stats-plus-teaser-preview { grid-template-columns: 1fr; }
    .stats-facts { grid-template-columns: repeat(2, 1fr); }
    .stats-rank-nm { flex-basis: 90px; }
}

.friends-section h2 {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 500;
    margin-bottom: var(--space-8);
}

.friends-search {
    position: relative;
    margin-bottom: var(--space-5);
}

.friends-search-icon {
    position: absolute;
    left: var(--space-3);
    top: 50%;
    transform: translateY(-50%);
    color: var(--color-text-faint);
    pointer-events: none;
}

.friends-search input {
    width: 100%;
    padding: var(--space-3) var(--space-3) var(--space-3) calc(var(--space-3) * 2 + 16px);
    background: var(--color-surface-2);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-lg);
    color: var(--color-text);
    font-family: var(--font-body);
    /* Never below 1rem: iOS Safari zooms the page in when a focused input's
       font-size is under 16px. Same max() guard as .search-input on the quotes
       list — var(--text-sm) alone clamps down to 0.875rem on narrow screens. */
    font-size: max(var(--text-sm), 1rem);
    transition: border-color var(--transition);
}

.friends-search input:focus {
    outline: none;
    border-color: var(--color-primary);
}

.friends-block {
    margin-bottom: var(--space-8);
}

.friends-block-title {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin-bottom: var(--space-3);
}

.friends-empty {
    font-size: var(--text-sm);
    color: var(--color-text-faint);
    padding: var(--space-4) 0;
}

.friend-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    background: var(--color-surface-2);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-lg);
    padding: var(--space-2) var(--space-3);
    margin-bottom: var(--space-2);
}

/* The row's clickable area (opens the profile). A bare <button> so it's
   keyboard-reachable, stripped back to a flex row — the browser default would
   otherwise break the layout and paint a chrome button inside the card. The
   action buttons sit outside it, so clicking "Add" never navigates. */
.friend-row-main {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.friend-row-main:hover .friend-row-name {
    color: var(--color-primary);
}

.friend-row-avatar {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-full);
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
}

.friend-row-body {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.friend-row-name {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text);
}

.friend-row-actions {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.friend-action-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: transparent;
    color: var(--color-text-muted);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 6px 12px;
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition),
                color var(--transition), transform 90ms ease;
}

.friend-action-btn:hover {
    border-color: var(--color-primary);
    color: var(--color-text);
}

.friend-action-btn:active {
    transform: scale(0.96);
}

/* The button is re-rendered (not mutated) after every action, so it re-enters
   rather than transitions — a short fade-in keeps the state change from
   snapping, now that the "request sent" label no longer shifts the layout. */
.friend-row-actions .friend-action-btn,
.friend-profile-action .friend-action-btn {
    animation: friendActionIn 200ms cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes friendActionIn {
    from { opacity: 0; transform: translateY(-2px); }
    to   { opacity: 1; transform: translateY(0); }
}

.friend-action-btn--primary {
    background: var(--color-primary);
    color: var(--color-text-inverse);
    border-color: var(--color-primary);
}

.friend-action-btn--primary:hover {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
    color: var(--color-text-inverse);
}

/* -- friend profile: immersive page --
   The whole screen belongs to the friend while their page is open, so the
   global header (logo, nav tabs, theme toggle, account menu) is hidden — all of
   it acts on the *viewer's* own session and reads as noise on someone else's
   page, and the theme toggle in particular would be confusing while the app is
   painted in that friend's theme. The back arrow is the only way out, which is
   why it must never be hidden alongside the rest. */
body.friend-immersive header {
    display: none;
}

/* Same page container as every other screen — the friend's page is immersive in
   *theme*, not in layout, so it keeps the app's width and gutters. */
.friend-profile-section {
    padding: var(--space-8) var(--space-6);
    max-width: var(--content-default);
    margin: 0 auto;
}

.friend-profile-topbar {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-bottom: var(--space-6);
}

.friend-profile-back {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-full);
    background: var(--color-surface-2);
    border: 1px solid var(--color-divider);
    color: var(--color-text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition);
}

.friend-profile-back:hover {
    border-color: var(--color-primary);
    color: var(--color-text);
}

.friend-profile-card {
    background: var(--color-surface);
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-xl);
    padding: var(--space-5);
}

.friend-profile-head {
    display: flex;
    align-items: center;
    gap: var(--space-4);
}

.friend-profile-avatar {
    flex-shrink: 0;
    width: 60px;
    height: 60px;
    border-radius: var(--radius-full);
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    border: 1.5px solid var(--color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
}

.friend-profile-ident {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
    min-width: 0;
}

.friend-profile-name-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.friend-profile-name {
    font-size: var(--text-lg);
    font-weight: 500;
    color: var(--color-text);
}

/* Epigraph Plus marker on someone else's page. Uses the same --color-plus pair
   as the account card's plus strip, so Plus reads identically everywhere. */
.friend-profile-plus {
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    background: var(--color-plus);
    color: var(--color-plus-ink);
    border-radius: var(--radius-full);
    padding: 2px 8px;
}

.friend-profile-meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-top: var(--space-4);
}

.friend-profile-meta-item {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.friend-profile-block {
    margin-top: var(--space-5);
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-divider);
}

.friend-profile-block-title {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin-bottom: var(--space-3);
}

.friend-profile-ach-strip {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* Each icon carries a hover/focus tooltip naming the achievement. Reuses the
   achievements modal's .achievement-info-tooltip look, but revealed by CSS
   rather than that modal's click-to-toggle JS: :focus-within covers a tap on
   touch and keyboard focus, so hover isn't the only way in. */
.friend-profile-ach-item {
    position: relative;
    display: inline-flex;
}

.friend-profile-ach-item:hover .achievement-info-tooltip,
.friend-profile-ach-item:focus-within .achievement-info-tooltip {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

/* The icon dims on the same trigger that reveals its tooltip, so the pointed-at
   badge and its label light up as one gesture. */
.friend-profile-ach-item:hover .friend-profile-ach,
.friend-profile-ach-item:focus-within .friend-profile-ach {
    opacity: 0.6;
}

.friend-profile-ach {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-full);
    background: var(--color-primary-highlight);
    color: var(--color-primary);
    border: 1px solid var(--color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    font: inherit;
    cursor: default;
    transition: opacity var(--transition);
}

.friend-profile-ach-name {
    display: block;
    font-weight: 500;
}

.friend-profile-ach-desc {
    display: block;
    margin-top: 2px;
    color: var(--color-text-muted);
}

.friend-profile-action {
    margin-top: var(--space-5);
}

.friend-profile-action .friend-action-btn {
    width: 100%;
    justify-content: center;
    padding: var(--space-3);
    font-size: var(--text-sm);
}

/* Quotes / notice sit below the profile card; the card owns no bottom margin,
   so the breathing room lives here (TASK-129). */
#friend-profile-quotes {
    margin-top: var(--space-6);
}

.friend-profile-locked {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-6) var(--space-4);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius-xl);
    color: var(--color-text-faint);
    font-size: var(--text-sm);
    text-align: center;
}

.settings-account-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-top: 6px;
    line-height: 1.2;
}

.settings-account-meta-item {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 12px;
    color: var(--color-text-faint);
}

.settings-account-meta-item--stats {
    color: var(--color-text-muted);
}

.settings-account-meta-item svg {
    color: var(--color-primary);
    flex-shrink: 0;
}

.account-edit-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    border: none;
    border-radius: var(--radius-full);
    background: none;
    color: var(--color-text-faint);
    cursor: pointer;
    transition: color var(--transition), background var(--transition), transform 90ms ease;
}

.account-edit-btn:hover {
    color: var(--color-primary);
    background: var(--color-primary-highlight);
}

.account-edit-btn:active {
    transform: scale(0.94);
}

.settings-version-badge {
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text-faint);
    background: var(--color-surface-offset);
    border-radius: var(--radius-full);
    padding: 2px var(--space-3);
    white-space: nowrap;
    flex-shrink: 0;
}

.export-btn {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-5);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    font-size: var(--text-sm);
    color: var(--color-text);
    background: var(--color-surface);
    white-space: nowrap;
    transition: transform 90ms ease;
}

.export-btn:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

.export-btn:active {
    transform: scale(0.94);
}

/* =============================================================================
// TOGGLE SWITCH  (notifications settings)
// ============================================================================= */
.toggle-switch {
    position: relative;
    display: inline-block;
    width: 44px;
    height: 24px;
    flex-shrink: 0;
}

.toggle-switch input {
    opacity: 0;
    width: 0;
    height: 0;
    position: absolute;
}

.toggle-slider {
    position: absolute;
    cursor: pointer;
    inset: 0;
    background: var(--color-border);
    border-radius: 24px;
    transition: background .25s;
}

.toggle-slider::before {
    content: '';
    position: absolute;
    width: 18px;
    height: 18px;
    left: 3px;
    top: 3px;
    background: white;
    border-radius: 50%;
    transition: transform .25s;
    box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
}

.toggle-switch input:checked + .toggle-slider {
    background: var(--color-primary);
}

.toggle-switch input:checked + .toggle-slider::before {
    transform: translateX(20px);
}

/* =============================================================================
// TOAST
// Transient notification messages displayed in the bottom-right corner.
// ============================================================================= */
.toast-wrap {
    position: fixed;
    bottom: var(--space-6);
    right: var(--space-6);
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--space-2);
    z-index: 999;
    pointer-events: none;
}

.toast {
    padding: var(--space-3) var(--space-5);
    background: var(--color-text);
    color: var(--color-bg);
    border-radius: var(--radius-full);
    font-size: var(--text-sm);
    font-weight: 500;
    box-shadow: var(--shadow-lg);
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.2s ease, transform 0.42s cubic-bezier(0.34, 1.56, 0.64, 1);
    max-width: calc(100vw - 2 * var(--space-6));
    word-break: break-word;
}

.toast.show {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

/* =============================================================================
// SCROLL TO TOP
// Floating button shown on the "Мои цитаты" list view once the user has
// scrolled down past a threshold — see scrollListToTop()/updateScrollTopBtn()
// in ui.js. Sits above .toast-wrap's offset so the two don't overlap if a
// toast fires while it's visible.
// ============================================================================= */
.scroll-top-btn {
    position: fixed;
    bottom: calc(var(--space-6) + 56px);
    right: var(--space-6);
    width: 44px;
    height: 44px;
    border-radius: var(--radius-full);
    background: oklch(from var(--color-surface) l c h / 0.75);
    backdrop-filter: blur(8px);
    border: 1px solid var(--color-border);
    color: var(--color-text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--shadow-md);
    z-index: 90;
    opacity: 0;
    transform: translateY(14px) scale(0.9);
    pointer-events: none;
    /* Deliberately much slower than --transition (180ms, tuned for hover micro-interactions) —
       this is a standalone appear/disappear, not a hover reaction, and reads as considerably
       calmer at this pace. */
    transition: opacity 480ms cubic-bezier(0.16, 1, 0.3, 1),
                transform 480ms cubic-bezier(0.16, 1, 0.3, 1),
                background var(--transition), color var(--transition);
}

.scroll-top-btn.visible {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
}

.scroll-top-btn:hover {
    background: var(--color-surface-offset);
    color: var(--color-primary);
}

.scroll-top-btn:active {
    transform: scale(0.94);
}

/* =============================================================================
// MODAL
// Overlay dialog used for confirmations and detail views.
// ============================================================================= */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: oklch(0.1 0 0 / 0.5);
    backdrop-filter: blur(4px);
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s;
}

.modal-overlay.open {
    opacity: 1;
    pointer-events: auto;
}

.modal {
    background: var(--color-surface-2);
    border-radius: var(--radius-xl);
    padding: var(--space-8);
    max-width: 480px;
    width: 100%;
    box-shadow: var(--shadow-lg);
    transform: scale(0.96);
    transition: transform 0.2s, max-width 0.2s;
    max-height: 90dvh;
    overflow-y: auto;
}

.modal--wide {
    max-width: 700px;
}

.modal-overlay.open .modal {
    transform: scale(1);
}

.modal h3 {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 500;
    margin-bottom: var(--space-2);
}

.modal p {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-bottom: var(--space-6);
    line-height: 1.7;
}

/* #modal-body is itself a <p> (see index.html), so ".modal p" above always
   gave it a trailing margin — harmless when .modal-actions follows with
   buttons (reads as the gap before them), but for actionless modals (avatar
   picker, achievements list) that margin became dead space stacked on top
   of the modal's own bottom padding, making the bottom edge visibly taller
   than the top. Move the gap onto .modal-actions instead, which only takes
   up room when it actually has buttons in it. */
#modal-body {
    margin-bottom: 0;
}

.modal-actions {
    display: flex;
    gap: var(--space-3);
    justify-content: flex-end;
}

.modal-actions:not(:empty) {
    margin-top: var(--space-6);
}

.modal--centered .modal-actions {
    justify-content: center;
}

.modal .btn-primary {
    background: var(--color-primary);
    color: var(--color-text-inverse);
}

.modal-quote-text {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--text-lg);
    line-height: 1.6;
    color: var(--color-text);
    background: var(--color-surface-offset);
    border-radius: var(--radius-md);
    padding: var(--space-5);
    margin-bottom: var(--space-4);
    max-height: 160px;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--color-border) transparent;
}

.modal-quote-author {
    font-size: var(--text-sm);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-primary);
    margin-bottom: var(--space-6);
}

.import-preview-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    max-height: 320px;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--color-border) transparent;
    margin-bottom: var(--space-4);
}

.import-preview-row {
    background: var(--color-surface-offset);
    border: 1px solid var(--color-border);
    border-left: 3px solid var(--color-primary);
    border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
}

.import-preview-row .import-preview-text {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--color-text);
    margin: 0 0 var(--space-1);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.import-preview-row .import-preview-meta {
    margin: 0;
}

.import-preview-meta-sep {
    color: var(--color-text-faint);
}

.import-preview-row .import-preview-reason {
    font-size: var(--text-xs);
    color: #c0392b;
    margin: var(--space-2) 0 0;
}

.import-preview-more {
    width: fit-content;
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-primary);
    background: var(--color-primary-highlight);
    border-radius: var(--radius-full);
    padding: var(--space-2) var(--space-4);
    margin: 0 auto var(--space-6);
}

/* Confirmation phrase input inside destructive modals */
.modal-confirm-input {
    width: 100%;
    margin-top: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface-offset);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text);
    font-size: 16px; /* Prevents iOS auto-zoom on focus (requires min 16px) */
    font-family: var(--font-body);
    outline: none;
    transition: border-color 0.15s;
    box-sizing: border-box;
}

.modal-confirm-input::placeholder {
    color: var(--color-text-muted);
}

.modal-confirm-input:focus {
    border-color: var(--color-accent);
}

/* =============================================================================
// EDIT MODAL
// Form rendered inside the shared modal for editing an existing quote.
// ============================================================================= */
.edit-form-group {
    margin-bottom: var(--space-4);
}

.edit-form-group label {
    display: flex;
    align-items: baseline;
    gap: var(--space-1);
    flex-wrap: nowrap;
    white-space: nowrap;
    font-size: var(--text-sm);
    font-weight: 500;
    margin-bottom: var(--space-2);
    color: var(--color-text);
}

.edit-form-group label span {
    color: var(--color-text-faint);
    font-weight: 400;
}

.edit-textarea {
    width: 100%;
    padding: var(--space-3) var(--space-4);
    padding-bottom: calc(var(--space-4) + 1.2rem);
    background: var(--color-surface-offset);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--text-lg);
    color: var(--color-text);
    font-family: var(--font-display);
    font-style: italic;
    min-height: 120px;
    max-height: 300px;
    resize: vertical;
    line-height: 1.6;
    transition: border-color var(--transition), box-shadow var(--transition);
}

.edit-input {
    width: 100%;
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface-offset);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: var(--text-base);
    color: var(--color-text);
    font-family: var(--font-body);
    transition: border-color var(--transition), box-shadow var(--transition);
}

.edit-textarea:focus, .edit-input:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px oklch(from var(--color-primary) l c h / 0.15);
}

.edit-textarea::placeholder, .edit-input::placeholder {
    color: var(--color-text-faint);
    font-style: italic;
}

.edit-form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
}

@media (max-width: 760px) {
    .edit-form-row {
        grid-template-columns: 1fr;
    }
}

/* =============================================================================
// RESPONSIVE
// Mobile / small-viewport overrides.
// ============================================================================= */
@media (max-width: 640px) {
    header {
        padding: var(--space-3) var(--space-4);
        gap: var(--space-2);
        flex-wrap: wrap;
    }

    .nav-tabs {
        order: 3;
        flex: 1 0 100%;
        justify-content: flex-start;
        overflow-x: auto;
        scrollbar-width: none;
        padding: var(--space-1);
    }

    .nav-tabs::-webkit-scrollbar {
        display: none;
    }

    .logo {
        font-size: var(--text-base);
    }

    .qod-card {
        padding: var(--space-6) var(--space-6);
    }

    .form-row {
        grid-template-columns:1fr;
    }

    .qod-actions {
        flex-wrap: wrap;
    }

    .list-header {
        flex-direction: column;
        align-items: stretch;
    }

    .search-wrap {
        max-width: 100%;
    }

    .toast-wrap {
        right: 50%;
        transform: translateX(50%);
        align-items: center;
    }

    .sort-dropdown {
        margin-left: 0;
    }

    .tag-input, .tag-add-btn {
        font-size: max(var(--text-xs), 16px);
    }
}

@media (max-width: 380px) {
    .nav-tab {
        padding: var(--space-1) var(--space-2);
        font-size: 0.75rem;
        min-height: 44px;
    }
}

/* =============================================================================
// AUTH
// Login / register screen shown when click Login the main app.
// ============================================================================= */
.app-blur-overlay {
    display: none;
    position: fixed;
    inset: 0;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    background: rgba(0, 0, 0, 0.25);
    z-index: 999;
}

.app-blur-overlay.visible {
    display: block;
}

.auth-screen {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1000;
    align-items: center;
    justify-content: center;
    padding: var(--space-6);
}

.auth-screen.visible {
    display: flex;
}

.auth-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-8);
    width: 100%;
    max-width: 400px;
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
    position: relative;
    z-index: 1001;
    box-shadow: 0 8px 40px rgba(0, 0, 0, 0.12);
}

.auth-title {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 500;
    text-align: center;
    color: var(--color-text);
}

.auth-subtitle {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    text-align: center;
    margin-top: var(--space-4);
}

.auth-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.auth-field label {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.auth-field input {
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface-2);
    color: var(--color-text);
    font-size: var(--text-base);
    font-family: var(--font-body);
    transition: border-color 0.15s;
}

.auth-field input:focus {
    outline: none;
    border-color: var(--color-primary);
}

.auth-error {
    font-size: var(--text-sm);
    color: #c0392b;
    text-align: center;
    min-height: 0;
    overflow: hidden;
    max-height: 0;
    transition: max-height 0.2s ease, opacity 0.2s ease;
    opacity: 0;
}

.auth-error:not(:empty) {
    max-height: 4em;
    opacity: 1;
}

.auth-field-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
}

.auth-field-header label {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.auth-forgot-link {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    font-family: var(--font-body);
    transition: color 0.15s;
}

.auth-forgot-link:hover {
    color: var(--color-text);
}

.auth-switch {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    text-align: center;
}

.auth-switch button {
    background: none;
    border: none;
    color: var(--color-primary);
    cursor: pointer;
    font-size: inherit;
    font-family: inherit;
    padding: 0;
    text-decoration: underline;
}

.auth-divider {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    color: var(--color-text-faint);
    font-size: var(--text-sm);
}

.auth-divider::before,
.auth-divider::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--color-divider);
}

/* Login mode: compact card with branding header */
.auth-login-header {
    margin: calc(-1 * var(--space-8)) calc(-1 * var(--space-8)) 0;
    padding: var(--space-5) var(--space-8);
    background: var(--color-surface-offset);
    border-bottom: 1px solid var(--color-border);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    text-align: center;
}

.auth-login-header-logo {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 600;
    color: var(--color-text);
    margin-bottom: var(--space-1);
}

.auth-login-header-logo svg {
    color: var(--color-primary);
    flex-shrink: 0;
}

.auth-login-tagline {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    line-height: 1.5;
}

/* Register mode: wide two-column card */
.auth-card--register {
    max-width: 780px;
    flex-direction: row;
    padding: 0;
    overflow: hidden;
    gap: 0;
}

/* Left decorative panel */
.auth-register-panel {
    display: none;
    flex-direction: column;
    justify-content: space-between;
    width: 300px;
    flex-shrink: 0;
    background: var(--color-surface-offset);
    border-right: 1px solid var(--color-border);
    padding: var(--space-8);
    border-radius: var(--radius-lg) 0 0 var(--radius-lg);
}

.auth-card--register .auth-register-panel {
    display: flex;
}

.auth-register-panel-logo {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-family: var(--font-display);
    font-size: var(--text-base);
    font-weight: 600;
    color: var(--color-text);
}

.auth-register-panel-logo svg {
    color: var(--color-primary);
    flex-shrink: 0;
}

.auth-register-panel-quotes {
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
    flex: 1;
    justify-content: center;
    padding: var(--space-8) 0;
}

.auth-register-panel-quote {
    border-left: 2px solid var(--color-primary);
    padding-left: var(--space-4);
}

.auth-register-panel-quote p {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--text-sm);
    color: var(--color-text);
    line-height: 1.6;
    margin-bottom: var(--space-1);
    max-width: none;
}

.auth-register-panel-quote cite {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    font-style: normal;
}

.auth-register-panel-tagline {
    font-size: var(--text-xs);
    color: var(--color-text-faint);
}

/* Right form column */
.auth-register-form-col {
    display: none;
    flex-direction: column;
    gap: var(--space-5);
    flex: 1;
    padding: var(--space-8);
    min-width: 0;
}

.auth-card--register .auth-register-form-col {
    display: flex;
}

/* Hide top branding header in register mode (it's in left panel) */
.auth-card--register .auth-login-header {
    display: none !important;
}

/* Register top heading inside form col */
.auth-register-top {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.auth-register-heading {
    font-family: var(--font-display);
    font-size: var(--text-xl);
    font-weight: 500;
    color: var(--color-text);
}

.auth-register-sub {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

/* Hide login-mode elements directly in the card when in register mode */
.auth-card--register > .auth-subtitle,
.auth-card--register > .auth-field,
.auth-card--register > .auth-error,
.auth-card--register > #auth-submit-btn,
.auth-card--register > .auth-divider,
.auth-card--register > .btn-google,
.auth-card--register > .btn-yandex,
.auth-card--register > .auth-switch {
    display: none !important;
}

/* ─── Mobile: registration page ─── */
@media (max-width: 639px) {

    /* Center the overlay and reduce padding */
    .auth-screen {
        padding: var(--space-3);
        align-items: center;
        justify-content: center;
    }

    /* Switch register card back to single-column layout */
    .auth-card--register {
        flex-direction: column;
        max-width: 100%;
        padding: 0;
        width: 100%;
    }

    /* Hide the decorative left panel with quotes on mobile */
    .auth-card--register .auth-register-panel {
        display: none !important;
    }

    /* Form column takes full width */
    .auth-register-form-col {
        padding: var(--space-6) !important;
        gap: var(--space-4) !important;
    }

    /* Show the top branding header again (since left panel is hidden) */
    .auth-card--register .auth-login-header {
        display: block !important;
        margin: 0;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
        padding: var(--space-4) var(--space-6);
    }

    /* Slightly smaller heading on mobile */
    .auth-register-heading {
        font-size: var(--text-lg);
    }

    /* Center heading and subtitle on mobile */
    .auth-register-top {
        text-align: center;
    }

    /* OAuth buttons centered */
    .btn-google,
    .btn-yandex {
        justify-content: center;
    }
}

.btn-google {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface-2);
    color: var(--color-text);
    font-size: var(--text-sm);
    font-family: var(--font-body);
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, transform 90ms ease;
}

.btn-google:hover {
    background: var(--color-surface-offset);
    border-color: var(--color-primary);
}

.btn-google:active {
    transform: scale(0.96);
}

/* Yandex OAuth button — mirrors .btn-google */
.btn-yandex {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface-2);
    color: var(--color-text);
    font-size: var(--text-sm);
    font-family: var(--font-body);
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, transform 90ms ease;
}

.btn-yandex:hover {
    background: var(--color-surface-offset);
    border-color: var(--color-primary);
}

.btn-yandex:active {
    transform: scale(0.96);
}

/* Inactive tabs fro guest */
.nav-tab.guest-locked {
    opacity: 0.45;
    cursor: default;
}

.btn-secondary.guest-locked {
    opacity: 0.45;
    cursor: not-allowed;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

/* App loading overlay — shown on startup, hidden once data is ready */
.app-loading-overlay {
    position: fixed;
    inset: 0;
    z-index: 9998;
    background: var(--color-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 0.5s ease, visibility 0.5s ease;
}

.app-loading-overlay.hidden {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}

.app-loading-spinner {
    width: 36px;
    height: 36px;
    border: 2.5px solid var(--color-border);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.75s linear infinite;
}

/* ── Announcement Banner ───────────────────────────────────────────── */
.announcement-banner {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-6);
    background: color-mix(in oklab, var(--color-gold) 8%, var(--color-surface));
    border-bottom: 1px solid color-mix(in oklab, var(--color-gold) 15%, var(--color-border));
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    animation: banner-slide-in 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes banner-slide-in {
    from { opacity: 0; transform: translateY(-8px); }
    to   { opacity: 1; transform: translateY(0); }
}

.announcement-banner__text {
    flex: unset;
    max-width: var(--content-default);
    line-height: 1.4;
    text-align: center;
}

.announcement-banner__close {
    position: absolute;
    right: var(--space-4);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-sm);
    color: var(--color-text-muted);
    transition: color var(--transition), background var(--transition);
}

.announcement-banner__close:hover {
    color: var(--color-text);
    background: color-mix(in oklab, var(--color-gold) 16%, var(--color-surface-offset));
}

/* =============================================================================
   UTILITY CLASSES — extracted from inline styles in auth.js and quotes.js
   ============================================================================= */

/* Spinner icon inside submit buttons */
.btn-spinner-icon {
    animation: spin 0.7s linear infinite;
    flex-shrink: 0;
}

/* "Back" button in auth panels (verify-code, forgot-password) */
.auth-back-btn {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    transition: color 0.15s, transform 90ms ease;
}

.auth-back-btn:hover {
    color: var(--color-text);
}

.auth-back-btn:active {
    transform: scale(0.94);
}

/* Modifier: verify-code screen back button needs extra spacing */
.auth-back-btn--inset {
    margin-bottom: var(--space-1);
    align-self: flex-start;
}

/* Verify-code input field */
.verify-code-input {
    letter-spacing: 0.3em;
    font-size: var(--text-lg);
    text-align: center;
    padding-left: 0.3em;
}

/* Auth panel title (forgot-password heading) */
.auth-panel-title {
    font-size: var(--text-lg);
    font-weight: 600;
    margin-bottom: var(--space-1);
}

/* Auth panel description text */
.auth-panel-desc {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

/* Change-password form field modifiers */
.auth-field--spaced {
    margin-bottom: var(--space-3);
}

.auth-field--flush {
    margin-bottom: 0;
}

/* Change-password inputs — tighter top margin than .modal-confirm-input default */
.cp-input {
    margin-top: var(--space-1);
}

/* Change-password error text */
.cp-error {
    margin-top: var(--space-3);
    font-size: var(--text-sm);
    color: #c0392b;
    min-height: 1.2em;
}

/* Confirm-modal hint text (delete-all, delete-account) */
.modal-confirm-hint {
    margin-top: var(--space-4);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}
