/* ==========================================================================
   Our Memory Book — Design System
   Aesthetic: "Intimate Warmth" — literary elegance meets personal warmth
   ========================================================================== */

/* ---------- Fonts ---------- */
/* Font loading moved to <head> in base.html for faster preconnect */

/* ---------- Design Tokens ---------- */
:root {
    /* Typography */
    --font-display: 'Cormorant Garamond', 'Georgia', serif;
    --font-body: 'Outfit', system-ui, sans-serif;
    --font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
    /* The two steps below body (DESIGN.md §3 ▸ The Two-Steps-Below-Body Rule) */
    --text-sm: 0.875rem; /* meta, captions, secondary UI copy */
    --text-xs: 0.8rem;   /* badges, timestamps, fine print */

    /* Palette — warm, grounded, intimate */
    --color-bg: #F8F5F0;
    --color-bg-warm: #F3EDE5;
    --color-bg-card: #FFFCF8;
    --color-bg-card-hover: #FFF9F2;
    --color-surface: #EDE8E0;
    --color-surface-alt: #E8E3DA;

    --color-text: #1A1614;
    --color-text-secondary: #5C524A;
    /* #6A5F54 keeps the warm tone but clears WCAG AA (4.5:1) at 12-14px against --color-bg-card */
    --color-text-muted: #6A5F54;

    /* #B65B37 clears WCAG AA (4.52:1) against #FFFCF8 — verified 2026-04-28; deepened two steps from #B85C38 */
    --color-primary: #B65B37;
    --color-primary-hover: #9E4D2E;
    /* 2026-08 critique fix — referenced 14x across CSS sources (link
       color, pricing badges, page CTAs) but never defined; links fell
       back to inherited ink (WCAG 1.4.1 failure). #9E4D2E clears WCAG AA:
       5.78:1 on --color-bg-card (#FFFCF8), 5.43:1 on --color-bg (#F8F5F0)
       — verified via a relative-luminance script. */
    --color-primary-deep: #9E4D2E;
    /* 2026-08 critique fix (Task 2) — dark-scoped text-safe alias for
       --color-primary. In light mode it's identical to --color-primary-deep
       (same 5.78:1 / 5.43:1 clearance already verified above); dark.css
       re-points it to a lifted terracotta that clears AA against both dark
       surfaces, where the raw --color-primary text/hover use case (e.g.
       .draft-discard:hover in components.css) only hit 3.66:1 / 3.22:1. */
    --color-primary-text: var(--color-primary-deep);
    /* 2026-08 critique fix (Task 2 review fix) — dedicated hover variant for
       --color-primary-text. --color-primary-hover (#9E4D2E) is byte-identical
       to --color-primary-deep in light mode, so the 7 rest/hover pairs
       re-pointed to --color-primary-text lost their hover affordance (rest
       == hover). #8B4328 is a further-deepened step of the same hue: 7.00:1
       on --color-bg-card, 6.59:1 on --color-bg — both clear AA, visibly
       darker than the rest color. Scoped to text/hover only — do not use
       for backgrounds (--color-primary-hover is unaffected and stays as-is
       for its many other, unrelated background/border uses). */
    --color-primary-text-hover: #8B4328;
    --color-primary-light: #D4A574;
    --color-primary-glow: rgba(184, 92, 56, 0.12);

    --color-text-on-primary: #FFFCF8;

    --color-accent: #7D8471;
    --color-accent-light: #A8B09E;
    /* sage as TEXT: ≥4.5:1 on bg/card/surface — #5C6352 measures 5.74:1 on
       --color-bg (#F8F5F0), 6.11:1 on --color-bg-card (#FFFCF8), 5.37:1 on
       --color-surface (#F3EDE5); verified via a relative-luminance script
       (2026-09-04 audit P1, WCAG 1.4.3). --color-accent itself (3.57:1) stays
       fill/border-only (badges, borders, confirmation surfaces). */
    --color-accent-text: #5C6352;

    --color-border: #DDD5CB;
    --color-border-light: #EAE4DC;
    /* The focus indicator is a PAIR: a border-colour change plus the
       decorative --shadow-glow ring. Only the border carries measurable
       contrast (the 12% glow measures ~1.16:1 against the field it sits on,
       and would need roughly 80% alpha to clear 3:1 on its own -- a solid
       terracotta slab on every input, and a direct contradiction of DESIGN.md's
       "3px terracotta at 12%" rule). So the border is what must clear WCAG
       1.4.11, and it was doing so with about 6% headroom. --color-primary-deep
       measures ~5.5:1 on parchment where --color-primary measures ~4.4:1, which
       moves the indicator off the floor without touching the glow or shifting
       layout. Design critique 2026-09-08. */
    --color-border-focus: var(--color-primary-deep);

    /* Decorative — sealed book, occasion gradients, export previews */
    --color-leather-dark: #3D352F;
    --color-leather: #5C524A;
    --color-leather-spine: #4A423B;
    --color-clasp: #A0794F;
    --color-parchment: #F5F0E8;
    --color-parchment-warm: #FAF8F5;
    --color-ink-warm: #3D3428;
    --color-ink-soft: #4A4035;
    --color-ink-gold: #C4B598;
    --color-ink-muted: #8A7D6B;
    --color-ink-sage: #9A8E7F;
    --color-ink-deep: #6B5D4A;
    --color-storybook-gold: #C4A265;
    --color-storybook-ink: #3A2E1F;
    --color-storybook-muted: #9A8A6F;
    --color-storybook-border: #D5C9B1;
    --color-modern-ink: #2D2A26;
    --color-modern-card: #F5F2ED;
    --color-modern-green: #4A6741;
    --color-occasion-rose: #C87B6B;
    --color-occasion-rose-light: #F5E6E0;
    /* --color-occasion-sky removed 2026-05-18: cool-blue tokens violated the
       No Cool Surfaces rule and were unreferenced everywhere outside their
       own definition + dark override. Same discipline applied earlier to
       --color-info. Restore as a warm-neutral if a future occasion needs it. */
    --color-occasion-stone: #9B9590;
    --color-occasion-stone-light: #E8E6E3;
    --color-occasion-cream: #E8E4D9;
    --color-occasion-sand: #F0E8DC;
    --color-memorial: #7A6F66;
    --color-memorial-hover: #6A6058;
    --color-memorial-light: #B5ADA5;
    --color-memorial-glow: rgba(122, 111, 102, 0.12);
    --color-memorial-bg: #F5F3F0;

    --color-success: #5E8B65;
    --color-error: #C0503E;
    --color-warning: #C49333;
    /* Warm slate-mauve, replaces cool-blue Notice Info per 2026-05-18 critique.
       Reads as quiet/informational; sits next to terracotta/walnut without cooling the palette.
       4.72:1 on parchment-card (was 3.66:1 with the prior #5B7FA0 — both warmer AND higher contrast). */
    --color-info: #7A6B66;

    /* Semantic state backgrounds */
    --color-bg-success: #f0f7f1;
    --color-bg-error: #fdf2f0;
    --color-bg-warning: #fdf6ec;
    --color-bg-info: #F4F0EE;
    --color-bg-error-subtle: #fdf8f7;

    /* Badge backgrounds */
    --color-badge-success: rgba(94, 139, 101, 0.12);
    --color-badge-warning: rgba(196, 147, 51, 0.12);
    --color-badge-warning-subtle: rgba(196, 147, 51, 0.06);
    --color-badge-warning-strong: rgba(196, 147, 51, 0.15);
    --color-badge-info: rgba(122, 107, 102, 0.12);
    --color-badge-error: rgba(192, 80, 62, 0.12);
    --color-badge-muted: rgba(138, 127, 118, 0.12);

    /* Badge text — darker than semantic colors to clear WCAG AA at 12px on tinted pill backgrounds. */
    --color-badge-text-success: #406B47;
    --color-badge-text-warning: #8A6522;
    --color-badge-text-info: #4E433F;
    --color-badge-text-error: #8E3525;
    --color-badge-text-muted: #5C524A;
    --color-error-hover: #a8412f;
    --color-error-active: #a0403a;
    --color-success-hover: #4d7a54;
    /* Solid success FILL behind light text (approve button, success icon).
       --color-success (#5E8B65) is tuned as a tint/border and only hits
       3.83:1 with --color-text-on-primary; this deeper green clears AA
       (4.86:1). Dark mode inherits it (dark.css does not re-point it) —
       #4d7a54 on the dark surface keeps light-text contrast. Audit 2026-06-22. */
    --color-success-strong: #4d7a54;

    /* Status TEXT on a tinted/light surface (alerts, inline form errors, failed-state
       labels, moderation diff ins/del). The saturated --color-* brand values are tuned
       as fills/borders and fail WCAG AA (4.5:1) at body size as text on the light
       --color-bg-* tints (warning was 2.59:1, success 3.60, error 4.29). These darker
       variants clear AA on every light surface (tint, parchment, card: 4.55-8.44:1).
       Dark mode re-points them to the lighter status colors (which already clear AA on
       the dark surface) in dark.css. NEVER use --color-{success,error,warning,info}
       directly as text on a light bg — use these. Audit 2026-06-06. */
    --color-text-on-bg-success: #406B47;
    --color-text-on-bg-error: #8E3525;
    --color-text-on-bg-warning: #8A6522;
    --color-text-on-bg-info: #4E433F;

    /* Spacing */
    --space-xs: 0.25rem;
    --space-sm: 0.5rem;
    --space-md: 1rem;
    --space-lg: 1.5rem;
    --space-xl: 2.5rem;
    --space-2xl: 4rem;
    --space-3xl: 6rem;

    /* Page-shell width tiers. Two values cover every marketing surface
       so future pages don't keep inventing new widths.
       - Narrative: long-form prose, manifestos, founder pages, single-
         column reading. About, how-it-works, promise, faq, and the
         homepage's read-y bands all use this. Wraps a ~58-65ch
         reading column with breathing room on both sides.
       - Grid: 3-column dashboards and the homepage's wide visual
         bands. Pricing, help center, the homepage hero / promise
         strip / pricing teaser all use this. */
    --width-narrative: 880px;
    --width-grid: 1100px;

    /* Radius */
    --radius-sm: 4px;
    --radius-md: 8px;
    --radius-lg: 12px;
    --radius-xl: 20px;

    /* Shadows — warm-tinted */
    --shadow-sm: 0 1px 3px rgba(26, 22, 20, 0.06);
    --shadow-md: 0 4px 12px rgba(26, 22, 20, 0.08);
    --shadow-lg: 0 8px 30px rgba(26, 22, 20, 0.10);
    --shadow-glow: 0 0 0 3px var(--color-primary-glow);

    /* Transitions */
    --ease-out: cubic-bezier(0.22, 1, 0.36, 1); /* single easing voice — --ease-emphasis removed 2026-04-28 */
    --duration-fast: 150ms;
    --duration-normal: 300ms;
    --duration-slow: 500ms;
}
/* ---------- Reset & Base ---------- */
*,
*::before,
*::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    font-size: 16px;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    scroll-behavior: smooth;
}

body {
    font-family: var(--font-body);
    font-weight: 400;
    color: var(--color-text);
    background-color: var(--color-bg);
    line-height: 1.65;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    position: relative;
}

/* Subtle grain overlay for tactile depth */
body::before {
    content: '';
    position: fixed;
    inset: 0;
    background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.03'/%3E%3C/svg%3E");
    background-repeat: repeat;
    background-size: 256px 256px;
    pointer-events: none;
    z-index: 1;
}

/* ---------- Typography ---------- */
h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-display);
    font-weight: 600;
    line-height: 1.2;
    color: var(--color-text);
    letter-spacing: -0.01em;
}

h1 {
    font-size: clamp(2.2rem, 5vw, 3.2rem);
    font-weight: 700;
}

h2 {
    font-size: clamp(1.6rem, 3.5vw, 2.2rem);
}

h3 {
    font-size: clamp(1.2rem, 2.5vw, 1.6rem);
}

/* Standardized heading scale */
.heading-hero { font-size: clamp(2.5rem, 6vw, 3.5rem); }
.heading-page { font-size: clamp(2rem, 4vw, 2.8rem); }
.heading-section { font-size: clamp(1.3rem, 3vw, 1.6rem); }

/* Skip to content — screen reader / keyboard accessibility */
.skip-link {
    position: fixed;
    top: var(--space-sm);
    left: var(--space-md);
    padding: var(--space-sm) var(--space-md);
    background: var(--color-primary);
    color: var(--color-text-on-primary);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 500;
    z-index: 200;
    transform: translateY(-200%);
    transition: transform var(--duration-fast) var(--ease-out);
}

.skip-link:focus {
    transform: translateY(0);
    color: var(--color-text-on-primary);
}

/* Copy button success state */
.copy-btn {
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
    min-width: 5.5rem;
}

.copy-btn--success {
    background: var(--color-success);
    color: var(--color-text-on-primary);
    border-color: var(--color-success);
    animation: copyPulse 0.3s var(--ease-out);
}

@keyframes copyPulse {
    0% { transform: scale(1); }
    40% { transform: scale(1.05); }
    100% { transform: scale(1); }
}

p {
    max-width: 60ch;
}

a {
    /* Use the deep terracotta for inline links so they clear WCAG AA
       (4.5:1) against parchment backgrounds. --color-primary at #B65B37
       computes ~4.4:1 against #FFFCF8 — just under threshold. The deep
       variant #9E4D2E clears at ~5.5:1. Buttons keep --color-primary
       since they pair it with cream text on terracotta background
       (high contrast in the inverse direction). */
    color: var(--color-primary-deep);
    text-decoration: none;
    transition: color var(--duration-fast) var(--ease-out);
}

a:hover {
    color: var(--color-primary-text-hover);
}

/* ---------- Reduced Motion ---------- */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
    /* Preserve brief opacity fades for functional state feedback */
    .btn,
    .messages .message,
    .theme-toggle,
    [data-theme] img {
        transition-duration: 150ms !important;
        transition-property: opacity, color, background-color !important;
    }
}
/* ---------- Layout ---------- */
.container {
    width: 100%;
    max-width: 1100px;
    margin: 0 auto;
    padding: 0 var(--space-lg);
}

main {
    flex: 1;
    padding: var(--space-2xl) 0;
}

/* ---------- Utilities ---------- */
.text-center { text-align: center; }
.text-muted { color: var(--color-text-muted); }
.text-sm { font-size: var(--text-sm); }
.text-error { color: var(--color-error); }
.mt-sm { margin-top: var(--space-sm); }
.mt-md { margin-top: var(--space-md); }
.mt-lg { margin-top: var(--space-lg); }
.mt-xl { margin-top: var(--space-xl); }
.mb-sm { margin-bottom: var(--space-sm); }
.m-0 { margin: 0; }

/* ==========================================================================
   Interior Pages — Component Library
   ========================================================================== */

/* ---------- Page Layout ---------- */
.page-header {
    max-width: 1100px;
    margin: 0 auto var(--space-xl);
    padding: 0 var(--space-lg);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
    position: relative;
    z-index: 10;
}

.page-header h1 {
    margin-bottom: var(--space-sm);
    overflow-wrap: break-word;
    word-break: break-word;
}

.page-header p {
    color: var(--color-text-secondary);
    font-size: 1.05rem;
    line-height: 1.7;
}

.page-header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-md);
}

.page-content {
    max-width: 1100px;
    margin: 0 auto;
    padding: 0 var(--space-lg);
    animation: fadeUp var(--duration-slow) var(--ease-out) 100ms both;
}

/* Constrained form column within page-content — keeps content aligned
   under the nav while preventing forms from stretching to full width. */
.page-content-form {
    max-width: 680px;
}

.page-content-form h1 {
    margin-bottom: var(--space-xs);
}

.page-content-form .form-card-subtitle {
    text-align: left;
    margin-bottom: var(--space-lg);
}

.page-content-form .form-fieldset {
    margin-bottom: var(--space-xl);
}

.page-content-form .form-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    margin-top: var(--space-xl);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border-light);
}

.page-content-form .form-footer a {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.page-actions {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
}

/* ---------- Dashboard More Menu ---------- */
.dashboard-more {
    position: relative;
}

.dashboard-more > summary {
    cursor: pointer;
    list-style: none;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
}

.dashboard-more > summary::-webkit-details-marker {
    display: none;
}

.dashboard-more__menu {
    position: absolute;
    top: calc(100% + var(--space-xs));
    right: 0;
    z-index: 50;
    min-width: 180px;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    padding: var(--space-xs) 0;
    animation: fadeUp var(--duration-fast) var(--ease-out) both;
}

.dashboard-more__menu a {
    display: block;
    padding: var(--space-sm) var(--space-lg);
    font-size: 0.88rem;
    color: var(--color-text-secondary);
    text-decoration: none;
    transition: background var(--duration-fast) var(--ease-out);
}

.dashboard-more__menu a:hover,
.dashboard-more__menu a:focus-visible {
    background: var(--color-primary-glow);
    color: var(--color-text);
    outline: none;
}

/* --color-primary-glow is a 12%-alpha tint: it reads as hover, not as focus,
   and measures nowhere near the 3:1 WCAG 1.4.11 asks of a focus indicator. The
   keyboard state gets a real ring on top of the tint. */
.dashboard-more__menu a:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: -2px;
}

.dashboard-more__locked {
    opacity: 0.65;
}

.dashboard-more__danger {
    color: var(--color-text-on-bg-error) !important;
    border-top: 1px solid var(--color-border-light);
    margin-top: var(--space-xs);
    padding-top: var(--space-sm);
}

.dashboard-more__danger:hover {
    background: rgba(192, 80, 62, 0.08) !important;
}

/* ---------- Book Sub-Navigation ---------- */
.book-nav {
    max-width: 1100px;
    margin: 0 auto var(--space-xl);
    padding: 0 var(--space-lg);
}

.book-nav__track {
    display: flex;
    gap: var(--space-xs);
    border-bottom: 1px solid var(--color-border-light);
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}

.book-nav__track::-webkit-scrollbar {
    display: none;
}

.book-nav__item {
    display: inline-flex;
    align-items: center;
    padding: var(--space-sm) var(--space-md);
    font-family: var(--font-body);
    font-size: 0.88rem;
    font-weight: 500;
    color: var(--color-text-muted);
    text-decoration: none;
    white-space: nowrap;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    min-height: 44px;
    transition: color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}

.book-nav__item:hover {
    color: var(--color-text-secondary);
}

.book-nav__item--active {
    color: var(--color-primary-text);
    border-bottom-color: var(--color-primary);
    font-weight: 600;
}

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

/* ---------- Dashboard Zones ---------- */
.dashboard-urgent {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-lg) var(--space-xl);
    margin-bottom: var(--space-xl);
    box-shadow: var(--shadow-sm);
}

.dashboard-urgent .stats-row {
    margin-bottom: var(--space-md);
}

.dashboard-primary {
    margin-bottom: var(--space-xl);
}

.dashboard-primary .share-link {
    margin-bottom: var(--space-md);
}

.dashboard-actions {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
}

/* Tools list: text-first, two-column. No card chrome — the Tools surface is a
   reference list of supporting actions, not a hero. WCAG 2.5.8 (44px target)
   is met via vertical padding on each row, not card padding. */
.dashboard-tools {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-xs) var(--space-xl);
    margin-bottom: var(--space-xl);
}

@media (max-width: 540px) {
    .dashboard-tools {
        grid-template-columns: 1fr;
    }
}

.dashboard-tool {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: var(--space-sm) 0;
    min-height: 44px;
    text-decoration: none;
    color: var(--color-text);
    border-radius: var(--radius-sm);
    transition: color var(--duration-fast) var(--ease-out);
}

.dashboard-tool:hover .dashboard-tool__label,
.dashboard-tool:focus-visible .dashboard-tool__label {
    color: var(--color-primary-text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.dashboard-tool:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 4px;
}

.dashboard-tool__label {
    font-family: var(--font-body);
    font-weight: 500;
    font-size: 0.95rem;
    transition: color var(--duration-fast) var(--ease-out);
}

.dashboard-tool__desc {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    line-height: 1.4;
}

.dashboard-tool--locked {
    opacity: 0.6;
}

.dashboard-tool--locked:hover {
    opacity: 1;
}

/* Grouped section beneath the live tools — visually demoted but easy to find. */
.dashboard-tools__locked-group {
    margin-top: var(--space-lg);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border-light);
}

.dashboard-tools__locked-heading {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text-muted);
    margin: 0 0 var(--space-md);
}

.dashboard-tools__locked-icon {
    width: 14px;
    height: 14px;
}

.dashboard-tools--locked {
    margin-bottom: 0;
}

.page-section {
    margin-top: var(--space-xl);
}

.page-section:last-child {
    margin-bottom: var(--space-xl);
}

.page-section h2 {
    font-size: 1.3rem;
    margin-bottom: var(--space-md);
    color: var(--color-text);
}

/* ---------- Dashboard Callout ---------- */
.dashboard-callout {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-lg);
    padding: var(--space-lg);
    border-radius: var(--radius-lg);
    margin-bottom: var(--space-xl);
}

/* Fallback rgba() declarations precede color-mix() for pre-2023 browsers.
   See CLAUDE.md "CSS browser support policy". */
.dashboard-callout--pending {
    background: var(--color-bg-warning);
    border: 1px solid rgba(196, 147, 51, 0.25);
    border: 1px solid color-mix(in srgb, var(--color-warning) 25%, transparent);
}

.dashboard-callout--share {
    background: var(--color-bg-info);
    border: 1px solid rgba(122, 107, 102, 0.25);
    border: 1px solid color-mix(in srgb, var(--color-info) 25%, transparent);
}

.dashboard-callout--calm {
    background: var(--color-bg-success);
    border: 1px solid rgba(94, 139, 101, 0.25);
    border: 1px solid color-mix(in srgb, var(--color-success) 25%, transparent);
}

.dashboard-callout__content {
    flex: 1;
    min-width: 0;
}

.dashboard-callout__title {
    font-family: var(--font-display);
    font-size: clamp(1.2rem, 2.5vw, 1.5rem);
    margin: 0;
    color: var(--color-text);
}

.dashboard-callout__subtitle {
    color: var(--color-text-muted);
    margin: var(--space-xs) 0 0;
    font-size: var(--text-sm);
}

.dashboard-callout .btn {
    flex-shrink: 0;
}

/* Variant: callout absorbs the contributor link + secondary actions inline.
   Used in the empty/sparse state to collapse "what next?" + "do it" into one card. */
.dashboard-callout--with-link {
    align-items: flex-start;
}

.dashboard-callout--with-link .dashboard-callout__content {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

.share-link--inline {
    margin-top: var(--space-xs);
    background: var(--color-bg);
    border-radius: var(--radius-md);
    padding: var(--space-xs);
    border: 1px solid color-mix(in srgb, var(--color-info) 18%, transparent);
}

.dashboard-callout__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-md) var(--space-lg);
    margin-top: var(--space-xs);
}

.callout-action {
    color: var(--color-text);
    font-size: 0.88rem;
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-color: color-mix(in srgb, var(--color-text) 30%, transparent);
}

.callout-action:hover,
.callout-action:focus-visible {
    color: var(--color-primary-text);
    text-decoration-color: currentColor;
}

@media (max-width: 600px) {
    .dashboard-callout {
        flex-direction: column;
        align-items: stretch;
        text-align: center;
    }

    .dashboard-callout .btn {
        align-self: center;
    }

    .dashboard-callout--with-link {
        text-align: left;
    }

    .dashboard-callout--with-link .dashboard-callout__title {
        text-align: left;
    }

    .dashboard-callout__actions {
        justify-content: flex-start;
    }
}

/* ---------- Dashboard Meta Line ---------- */
.dashboard-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-xs) var(--space-sm);
    margin-top: var(--space-xs);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

.plan-badge--small {
    font-size: 0.7rem;
    padding: 0.12em 0.45em;
}

.status-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

.status-dot--live {
    background: var(--color-success);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-success) 20%, transparent);
}

/* ---------- Dashboard Tools Collapsible ---------- */
.dashboard-tools-section {
    margin-top: var(--space-xl);
}

.dashboard-tools-section__toggle {
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-sm) 0;
}

.dashboard-tools-section__toggle::-webkit-details-marker {
    display: none;
}

.dashboard-tools-section__toggle::before {
    content: "\25B8";
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    transition: transform var(--duration-fast) var(--ease-out);
}

.dashboard-tools-section[open] > .dashboard-tools-section__toggle::before {
    transform: rotate(90deg);
}

.dashboard-tools-section__label {
    font-family: var(--font-display);
    font-size: 1.3rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--color-text);
    letter-spacing: -0.01em;
}

/* ---------- Dashboard Admin Collapsible ---------- */
.dashboard-admin {
    margin-top: var(--space-xl);
    border-top: 1px solid var(--color-border-light);
    padding-top: var(--space-lg);
}

.dashboard-admin__toggle {
    font-family: var(--font-body);
    font-size: 0.88rem;
    color: var(--color-text-muted);
    cursor: pointer;
    padding: var(--space-sm) 0;
    list-style: none;
}

.dashboard-admin__toggle::-webkit-details-marker {
    display: none;
}

.dashboard-admin__toggle::before {
    content: "\25B8";
    display: inline-block;
    margin-right: var(--space-xs);
    font-size: 0.7rem;
    color: var(--color-text-muted);
    transition: transform var(--duration-fast) var(--ease-out);
}

.dashboard-admin[open] > .dashboard-admin__toggle::before {
    transform: rotate(90deg);
}

/* ---------- Dashboard Meta — Published Status Pill ---------- */
.dashboard-meta__status {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: 0.18em 0.55em;
    border-radius: 100px;
    background: color-mix(in srgb, var(--color-success) 10%, transparent);
    color: color-mix(in srgb, var(--color-success) 75%, var(--color-text));
    font-size: var(--text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.dashboard-meta__status .status-dot--live {
    width: 6px;
    height: 6px;
    box-shadow: none;
}

/* ---------- Stats Summary (used inside .dashboard-urgent) ---------- */
.stats-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-xs) var(--space-sm);
    font-size: 0.95rem;
}

.stats-summary__item {
    color: var(--color-text-secondary);
    text-decoration: none;
    transition: color var(--duration-fast) var(--ease-out);
}

.stats-summary__item strong {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 700;
    color: var(--color-text);
    margin-right: 0.25em;
    font-variant-numeric: tabular-nums;
}

.stats-summary__item:hover,
.stats-summary__item:focus-visible {
    color: var(--color-primary-text);
}

.stats-summary__item--alert strong {
    color: var(--color-text-on-bg-warning);
}

.stats-summary__item--muted,
.stats-summary__item--muted strong {
    color: var(--color-text-muted);
}

.stats-summary__sep {
    color: var(--color-border);
    font-size: var(--text-sm);
    user-select: none;
}

.stats-summary__all {
    margin-left: auto;
    font-size: var(--text-sm);
    color: var(--color-primary-text);
    text-decoration: none;
}

.stats-summary__all:hover,
.stats-summary__all:focus-visible {
    color: var(--color-primary-text-hover);
    text-decoration: underline;
}

@media (max-width: 600px) {
    .stats-summary__all {
        margin-left: 0;
        flex-basis: 100%;
    }
}

/* ---------- Book Billing Status Card ---------- */
.book-billing-status {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    padding: var(--space-lg);
    box-shadow: var(--shadow-sm);
}

.book-billing-status h2 {
    font-size: 1.1rem;
    margin: 0 0 var(--space-sm);
    color: var(--color-text);
}

.book-billing-status__plan {
    margin: 0;
    font-size: 1rem;
    color: var(--color-text);
}

.book-billing-status__plan strong {
    font-weight: 600;
}

.book-billing-status__mode {
    margin: var(--space-xs) 0 0;
    font-size: 0.88rem;
    color: var(--color-text-secondary);
}

.book-billing-status__toggle {
    margin: var(--space-md) 0 0;
}

/* ---------- Danger Zone ---------- */
.danger-zone {
    margin-top: var(--space-2xl);
    padding: var(--space-lg);
    border: 1px solid color-mix(in srgb, var(--color-error) 25%, var(--color-border-light));
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--color-error) 3%, var(--color-bg-card));
}

.danger-zone__heading {
    font-family: var(--font-body);
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-text-on-bg-error);
    margin: 0 0 var(--space-sm);
}

.danger-zone__desc {
    font-size: 0.92rem;
    color: var(--color-text-secondary);
    line-height: 1.6;
    margin: 0 0 var(--space-md);
    max-width: 60ch;
}

.danger-zone__action {
    margin: 0;
}
/* ---------- Header / Navigation ----------
   Scope to body's direct-child <header> so HTML5 inner <header>
   elements (e.g. .pricing-page__header, an article's <header>)
   don't accidentally inherit the sticky-nav treatment. The previous
   `header { ... }` rule was matching every <header> on the page
   and any nested one stuck below the global nav at the same z-index,
   trapping the Use Cases dropdown menu beneath it on /pricing/. */
body > header {
    position: sticky;
    top: 0;
    z-index: 100;
    /* Was color-mix() + backdrop-filter glassmorphism; replaced with
       an opaque warm-tint so there's no banned decorative blur.
       95% opacity keeps the sticky-header contrast without requiring
       backdrop-filter (which also has a render-cost on scroll). */
    background: color-mix(in srgb, var(--color-bg) 96%, transparent);
    border-bottom: 1px solid var(--color-border-light);
}

body > header nav {
    max-width: 1100px;
    margin: 0 auto;
    padding: var(--space-md) var(--space-lg);
    display: flex;
    align-items: center;
    gap: var(--space-lg);
}

.nav-brand {
    font-family: var(--font-display);
    font-size: 1.35rem;
    font-weight: 700;
    color: var(--color-text);
    letter-spacing: -0.02em;
    text-decoration: none;
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    transition: opacity var(--duration-fast) var(--ease-out);
}

.nav-brand:hover {
    opacity: 0.8;
    color: var(--color-text);
}

.nav-brand-icon {
    width: 28px;
    height: 28px;
    object-fit: contain;
}

.nav-spacer {
    flex: 1;
}

.nav-links {
    display: flex;
    align-items: center;
    gap: var(--space-md);
}

.nav-links a {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-secondary);
    padding: var(--space-xs) var(--space-sm);
    border-radius: var(--radius-sm);
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.nav-links a:hover {
    color: var(--color-text);
    background: var(--color-primary-glow);
}

.nav-links a.btn-primary {
    color: var(--color-text-on-primary);
    background: var(--color-primary);
    padding: 0.45rem 1rem;
    font-weight: 600;
}

.nav-links a.btn-primary:hover {
    color: var(--color-text-on-primary);
    background: var(--color-primary-hover);
    /* box-shadow intentionally omitted: the global .btn-primary:hover rule
       (components.css) owns it, tokenised via color-mix on --color-primary. */
}

.nav-user {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    font-weight: 400;
}

.nav-separator {
    width: 1px;
    height: 20px;
    background: var(--color-border);
}

.nav-logout-form {
    display: inline;
    margin: 0;
    padding: 0;
}

.nav-logout-btn {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-secondary);
    padding: var(--space-xs) var(--space-sm);
    border-radius: var(--radius-sm);
    background: none;
    border: none;
    cursor: pointer;
    transition: color var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out);
}

.nav-logout-btn:hover {
    color: var(--color-text);
    background: var(--color-primary-glow);
}

/* Quick-nav hint pill — desktop-only entry point to the Cmd+K palette.
   Hidden on touch / narrow viewports where keyboard shortcuts are irrelevant. */
.cmd-hint {
    display: none;
    align-items: center;
    gap: var(--space-xs);
    padding: 4px 8px 4px 8px;
    margin-right: var(--space-xs);
    background: transparent;
    border: 1px solid var(--color-border-light);
    border-radius: 99px;
    color: var(--color-text-muted);
    font-size: 0.78rem;
    line-height: 1;
    cursor: pointer;
    /* 44px minimum touch target — verified 2026-04-28 */
    min-height: 44px;
    transition: color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out);
}

.cmd-hint:hover,
.cmd-hint:focus-visible {
    color: var(--color-text);
    border-color: var(--color-border);
    background: var(--color-bg-warm);
}

.cmd-hint__label {
    margin-right: 2px;
}

.cmd-hint__kbd {
    display: inline-flex;
    align-items: center;
    gap: 1px;
    padding: 2px 5px;
    background: var(--color-bg-warm);
    border: 1px solid var(--color-border-light);
    border-radius: 4px;
    font-family: var(--font-mono, ui-monospace, "SF Mono", Menlo, monospace);
    font-size: 0.7rem;
    color: var(--color-text-secondary);
}

@media (min-width: 769px) {
    .cmd-hint {
        display: inline-flex;
    }
}

/* Theme toggle — 44×44 minimum touch target met by min-width/min-height below */
.theme-toggle {
    background: none;
    border: none;
    color: var(--color-text-secondary);
    cursor: pointer;
    padding: var(--space-xs);
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    min-width: 44px; /* 44×44 minimum touch target — verified 2026-04-28 */
    min-height: 44px;
    justify-content: center;
    transition: color var(--duration-fast) var(--ease-out);
}

.theme-toggle:hover {
    color: var(--color-primary-text);
}

.nav-toggle {
    display: none;
    flex-direction: column;
    gap: 4px;
    padding: 12px;
    background: none;
    border: none;
    cursor: pointer;
    min-width: 44px;
    min-height: 44px;
    align-items: center;
    justify-content: center;
}

.nav-toggle span {
    display: block;
    width: 20px;
    height: 2px;
    background: var(--color-text);
    border-radius: 1px;
    transition: transform var(--duration-normal) var(--ease-out),
                opacity var(--duration-fast) var(--ease-out);
}

/* Mobile hamburger — a real <button> (2026-09-04 HIG critique P1: the
   checkbox+label hack was not keyboard/VoiceOver-openable). Open state is
   `header.nav-open`, set by base-ui.js. */
.nav-toggle:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    box-shadow: var(--shadow-glow);
    border-radius: var(--radius-md);
}
header.nav-open .nav-links {
    display: flex;
}
header.nav-open .nav-toggle span:nth-child(1) {
    transform: rotate(45deg) translate(5px, 5px);
}
header.nav-open .nav-toggle span:nth-child(2) {
    opacity: 0;
}
header.nav-open .nav-toggle span:nth-child(3) {
    transform: rotate(-45deg) translate(5px, -5px);
}

/* ── F-08: Mobile hamburger trims duplicate items ──────────────────
   At <=768px, authenticated users get Books/Create/Settings from the
   bottom nav. The top hamburger dropdown drops those duplicates so
   the two surfaces split cleanly — the hamburger keeps only user
   display name + Log out. Anonymous users are unaffected (no bottom
   nav, so their full link list stays). */
@media (max-width: 768px) {
    .nav-links__mobile-hide {
        display: none !important;
    }
}

/* ---------- Footer ---------- */
footer {
    border-top: 1px solid var(--color-border-light);
    padding: var(--space-xl) var(--space-lg);
    text-align: center;
}

footer p {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    max-width: none;
    font-weight: 400;
    letter-spacing: 0.02em;
}

/* ---------- Mobile Bottom Navigation ---------- */
.bottom-nav {
    display: none;
}

.bottom-nav__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-height: 44px;
    min-width: 44px;
    padding: var(--space-sm) var(--space-md);
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: 0.7rem;
    font-weight: 500;
    transition: color var(--duration-fast) var(--ease-out);
}

.bottom-nav__item--active {
    color: var(--color-primary-text);
}

.bottom-nav__item:hover {
    color: var(--color-text);
}

.bottom-nav__item svg {
    stroke: currentColor;
}
/* ============================================================================
   Focus-visible convention (2026-05-02; REPLACED 2026-09-10)

   THE INDICATOR IS AN OUTLINE. Every interactive element shows keyboard focus
   with:

       outline: 2px solid var(--color-border-focus);
       outline-offset: 2px;      (-2px for a full-width row inside a menu
                                  or dialog, so the ring sits on the row)

   CSS comments do not nest: that parenthetical was once an inner comment, and
   its closing token ended THIS block early, so everything below became part of
   the `.btn` selector and the browser dropped the whole rule (2026-09-12).

   `--color-border-focus` measures 5.43:1 against --color-bg light and 3.66:1
   dark, clearing the 3:1 WCAG 1.4.11 asks of a non-text indicator. Modern
   browsers follow border-radius, so the ring fits rounded controls.

   `box-shadow: var(--shadow-glow)` and a border-colour shift MAY accompany it
   as decoration. Neither is an indicator on its own: the glow is a 12%-alpha
   tint of the primary, measuring ~1.16:1, and the border also changes on
   :hover, so it does not distinguish keyboard focus from a pointer.

   WHAT THIS REPLACED, and why it is written out rather than deleted: the old
   convention here instructed `outline: none` plus the glow, and it was followed
   correctly by 31 controls -- every form input, the hub buttons, the reaction
   buttons, the nav toggle, the story player. They were not 31 mistakes; the
   instruction was the defect, and each control was then invisible to a keyboard
   user. Anyone reading a diff that puts an outline back needs to know it is
   deliberate. See issues/05-focus-convention-relies-on-a-decorative-glow.md.

   Programmatically-focused containers (`tabindex="-1"` aria-live regions and
   role=alert error summaries) are the ONE exception: they are not tabbable, and
   a ring on a paragraph nobody tabbed to is noise. They keep `outline: none`
   and are individually reasoned in FOCUS_OUTLINE_EXEMPTIONS.

   Enforced, not code-review convention: `apps/quality/tests/test_css_invariants.py`
   fails any selector that suppresses its outline without a compensating ring
   (collected per selector across all rules, so splitting the two apart does not
   escape it), and separately measures the indicator tokens against both themes.
   ============================================================================ */

/* ---------- Buttons ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    font-family: var(--font-body);
    font-size: 0.95rem;
    font-weight: 500;
    padding: 0.7rem 1.5rem;
    /* WCAG 2.5.8 (Target Size Minimum): 44px enforced at the base so every
       .btn — primary, secondary, sm, block — clears the touch target floor.
       The box stretches around the existing padding/type; do not lower this
       value to shrink a button. .btn-lg is naturally taller and unaffected. */
    min-height: 44px;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background-color var(--duration-normal) var(--ease-out),
                color var(--duration-normal) var(--ease-out),
                box-shadow var(--duration-normal) var(--ease-out),
                transform var(--duration-normal) var(--ease-out),
                border-color var(--duration-normal) var(--ease-out);
    text-decoration: none;
    line-height: 1;
}

.btn-primary {
    background: var(--color-primary);
    color: var(--color-text-on-primary);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--color-primary) 20%, transparent);
}

.btn-primary:hover {
    background: var(--color-primary-hover);
    color: var(--color-text-on-primary);
    box-shadow: 0 4px 16px color-mix(in srgb, var(--color-primary) 30%, transparent);
    transform: translateY(-1px);
}

.btn-primary:active {
    transform: translateY(0);
    box-shadow: 0 1px 4px color-mix(in srgb, var(--color-primary) 20%, transparent);
}

.btn-secondary {
    background: transparent;
    color: var(--color-text);
    border: 1.5px solid var(--color-border);
}

.btn-secondary:hover {
    border-color: var(--color-primary-light);
    background: var(--color-primary-glow);
    color: var(--color-primary-text);
}

.btn-lg {
    padding: 0.85rem 2rem;
    font-size: 1.05rem;
    border-radius: var(--radius-lg);
}

.btn-sm {
    padding: 0.45rem 1rem;
    font-size: var(--text-sm);
    min-height: 2.75rem;
}

.btn-block {
    width: 100%;
}

/* Focus styles — keyboard accessibility */
.btn:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

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

input:focus-visible,
textarea:focus-visible,
select:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-border-focus);
    box-shadow: var(--shadow-glow);
}

/* ---------- Form Select ---------- */
.form-select {
    display: block;
    font-family: var(--font-body);
    font-size: 1rem;
    min-height: 44px;
    padding: 0.6rem 2rem 0.6rem 0.75rem;
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-md);
    background-color: var(--color-bg-card);
    color: var(--color-text);
    cursor: pointer;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%238A7F76' d='M1.41 0L6 4.58 10.59 0 12 1.41l-6 6-6-6z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.form-select:hover {
    border-color: var(--color-primary-light);
}

.form-select:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-border-focus);
    box-shadow: var(--shadow-glow);
}

/* Button secondary hover consistency */
.btn-secondary:hover {
    transform: translateY(-1px);
}

.btn-secondary:active {
    transform: translateY(0);
}

/* Disabled button state */
.btn:disabled,
.btn[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
    transform: none !important;
    box-shadow: none !important;
}

/* Plan-locked state — visible but clearly gated */
.btn-locked {
    opacity: 0.55;
    border-style: dashed;
    position: relative;
    gap: var(--space-xs);
}

.btn-locked:hover {
    border-color: var(--color-primary-light);
    opacity: 0.75;
    background: var(--color-primary-glow);
}

.btn-locked .btn-locked__badge {
    font-size: 0.7em;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-primary-text);
    opacity: 0.85;
}

/* Dashboard-tool variant: same "Upgrade" pill on the locked tool tile,
   but the parent class is `.dashboard-tool--locked`, not `.btn-locked`,
   so it needs its own scope. Recovered from 3d3fc16b. */
.dashboard-tool--locked .btn-locked__badge {
    display: inline-block;
    margin-left: var(--space-xs);
    padding: 0.1em 0.5em;
    font-size: 0.65rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-primary-text);
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
    border-radius: 100px;
    vertical-align: 1px;
}

/* Loading state — prepends a spinner; preserves the button label. */
.btn--loading {
    opacity: 0.75;
    cursor: wait;
    pointer-events: none;
}
.btn--loading::before {
    content: "";
    display: inline-block;
    width: 0.85em;
    height: 0.85em;
    margin-right: 0.55em;
    margin-left: -0.15em;
    vertical-align: -0.12em;
    border-radius: 50%;
    border: 1.5px solid currentColor;
    border-top-color: transparent;
    animation: btn-spin 0.7s linear infinite;
}
@keyframes btn-spin {
    to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
    .btn--loading::before { animation-duration: 1.6s; }
}

/* ---------- Cards ---------- */
.card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-xl);
    box-shadow: var(--shadow-sm);
    transition: box-shadow var(--duration-normal) var(--ease-out),
                border-color var(--duration-normal) var(--ease-out);
}

.card:hover {
    box-shadow: var(--shadow-md);
    border-color: var(--color-border);
}

/* ---------- Forms ---------- */
.form-group {
    margin-bottom: var(--space-lg);
}

/* Form input mobile-compliance contract:
   - font-size MUST be ≥ 16px (1rem). iOS Safari zooms the layout on focus
     when an input's computed font-size is below 16px; 0.95rem is the
     classic regression. NEVER use 0.95rem on a real input.
   - min-height 44px satisfies WCAG 2.5.8 (Target Size Minimum) without
     stretching the typography.
   Templates: set `autocomplete` (e.g. `email`, `name`, `current-password`,
   `one-time-code`) and `inputmode` (e.g. `email`, `tel`, `numeric`,
   `decimal`) on individual <input> elements where appropriate — those
   attributes are per-field semantics, not stylable here. */
.form-group input[type="text"],
.form-group input[type="email"],
.form-group input[type="password"],
.form-group input[type="url"],
.form-group input[type="tel"],
.form-group input[type="number"],
.form-group textarea,
.form-group select {
    width: 100%;
    padding: 0.7rem 0.9rem;
    font-family: var(--font-body);
    font-size: 1rem;
    min-height: 44px;
    color: var(--color-text);
    background: var(--color-bg);
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-md);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out),
                background-color var(--duration-fast) var(--ease-out);
}

.form-group input:focus-visible,
.form-group textarea:focus-visible,
.form-group select:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-border-focus);
    box-shadow: var(--shadow-glow);
    background: var(--color-bg-card);
}

.form-group input::placeholder,
.form-group textarea::placeholder {
    color: var(--color-text-muted);
}

.form-group .helptext {
    display: block;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-top: var(--space-xs);
    line-height: 1.5;
}

.form-group .helptext ul {
    list-style: none;
    padding: 0;
}

.form-group .helptext li {
    padding: var(--space-xs) 0;
}

.form-group .helptext li::before {
    content: '·';
    margin-right: var(--space-sm);
    color: var(--color-primary-light);
    font-weight: 700;
}

.form-group .errorlist {
    list-style: none;
    padding: 0;
    margin-top: var(--space-xs);
}

.form-group .errorlist li {
    font-size: var(--text-xs);
    color: var(--color-text-on-bg-error);
    padding: var(--space-xs) 0;
}

.form-group--error {
    padding: var(--space-sm);
    border-radius: var(--radius-md);
    background: rgba(192, 57, 43, 0.04);
}

.form-group--error input,
.form-group--error textarea,
.form-group--error select {
    border-color: var(--color-error);
}

.form-group--error input:focus-visible,
.form-group--error textarea:focus-visible,
.form-group--error select:focus-visible {
    box-shadow: 0 0 0 3px rgba(192, 57, 43, 0.1);
}

/* ---------- Messages / Alerts ---------- */
.messages {
    max-width: 1100px;
    margin: 0 auto var(--space-lg);
    padding: 0 var(--space-lg);
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.message {
    padding: var(--space-md) var(--space-lg);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    font-weight: 500;
    animation: slideDown var(--duration-normal) var(--ease-out) both;
}

.message.success {
    background: var(--color-bg-success);
    color: var(--color-text-on-bg-success);
    border-color: var(--color-success);
}

.message.error {
    background: var(--color-bg-error);
    color: var(--color-text-on-bg-error);
    border-color: var(--color-error);
}

.message.warning {
    background: var(--color-bg-warning);
    color: var(--color-text-on-bg-warning);
    border-color: var(--color-warning);
}

.message.info {
    background: var(--color-bg-info);
    color: var(--color-text-on-bg-info);
    border-color: var(--color-info);
}

.message {
    position: relative;
    padding-right: var(--space-2xl);
}

/* Inline, non-dismissible notice (e.g. members/invite access-control note).
   Distinct from .message (which is a dismissible flash with an animation +
   close button). Theme-aware via the bg/text-on-bg/info token trio. */
.banner {
    padding: var(--space-md) var(--space-lg);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    line-height: 1.5;
}

.banner--info {
    background: var(--color-bg-info);
    color: var(--color-text-on-bg-info);
    border-color: color-mix(in srgb, var(--color-info) 25%, transparent);
}

/* Inline callout box — heavier than .banner, used on confirmation screens
   (book delete) + help pages. --warm = caution (amber), --cool = info
   (slate). The bare base was undefined, so callouts rendered as plain
   paragraphs. Audit 2026-06-22. (.callout-action styles the inner link.) */
.callout {
    padding: var(--space-md) var(--space-lg);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    line-height: 1.5;
}

.callout--warm {
    background: var(--color-bg-warning);
    color: var(--color-text-on-bg-warning);
    border-color: color-mix(in srgb, var(--color-warning) 25%, transparent);
}

.callout--cool {
    background: var(--color-bg-info);
    color: var(--color-text-on-bg-info);
    border-color: color-mix(in srgb, var(--color-info) 25%, transparent);
}

.message-close {
    position: absolute;
    top: 50%;
    right: var(--space-md);
    transform: translateY(-50%);
    background: none;
    border: none;
    font-size: 1.2rem;
    cursor: pointer;
    opacity: 0.5;
    transition: opacity var(--duration-fast);
    color: inherit;
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.message-close:hover {
    opacity: 1;
}

.message-close:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 2px;
    opacity: 1;
}

@keyframes messageFadeOut {
    to { opacity: 0; transform: translateY(-10px); }
}

.message--dismissing {
    animation: messageFadeOut var(--duration-normal) var(--ease-out) forwards;
}

/* ---------- Animations ---------- */
@keyframes fadeUp {
    from {
        opacity: 0;
        transform: translateY(16px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

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

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

/* ---------- Form Pages ---------- */
.form-page {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    min-height: calc(100vh - 300px);
    padding: var(--space-xl) var(--space-lg);
}

.form-card {
    width: 100%;
    max-width: 580px;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-xl);
    padding: var(--space-2xl);
    box-shadow: var(--shadow-lg);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
}

.form-card h1 {
    text-align: center;
    margin-bottom: var(--space-xs);
    font-size: clamp(1.5rem, 1.15rem + 1.75vw, 2rem);
}

.honeypot-field {
    position: absolute;
    left: -9999px;
    top: auto;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.form-card-warmth {
    text-align: center;
    margin-bottom: var(--space-xl);
    padding-bottom: var(--space-lg);
    border-bottom: 1px solid var(--color-border-light);
}

.form-card-subtitle {
    text-align: center;
    color: var(--color-text-secondary);
    font-size: 0.95rem;
    margin-bottom: var(--space-sm);
    max-width: none;
}

.form-card-subtitle strong {
    color: var(--color-text);
    font-weight: 600;
}

.form-card-context {
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.88rem;
    font-style: italic;
    max-width: 40ch;
    margin: 0 auto;
    line-height: 1.6;
}

.form-card-back {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    gap: 0.4rem;
    margin-top: var(--space-md);
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
    text-decoration: none;
}

.form-card-back svg {
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
}

.form-card-back:hover {
    color: var(--color-primary-text);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.form-card-back:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 2px;
}

.form-card .form-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    margin-top: var(--space-lg);
}

.form-card .form-footer a {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

/* ---------- Draft & Inline Validation ---------- */
.form-draft-status {
    text-align: center;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    min-height: 1.2em;
    margin-bottom: var(--space-sm);
    transition: opacity var(--duration-fast) var(--ease-out);
}

/* Inline Discard control rendered by restoreDraft() (submit.html).
   Quiet underline; Hearth Terracotta on hover. No card chrome, so the
   status row stays quiet.
   Moved from apps/submissions/templates/submissions/submit.html
   <style> (2026-08 critique-color-fixes Task 4). */
.form-draft-status .draft-discard {
    background: none;
    border: 0;
    padding: 0;
    margin-left: 0.5rem;
    font: inherit;
    color: var(--color-text-muted);
    text-decoration: underline;
    text-underline-offset: 2px;
    cursor: pointer;
}
.form-draft-status .draft-discard:hover {
    color: var(--color-primary-text);
}
.form-draft-status .draft-discard:focus-visible {
    color: var(--color-primary-text);
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 2px;
}

/* ---------- Unsaved-changes affordance (form-guard.js) ----------
   Quiet pill that sits next to the primary submit button when the
   form has been edited. Single accent (terracotta), no shadow, no
   bouncy motion. Hidden by default via [hidden]; reveals on dirty. */
.form-guard-indicator {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: 0.35rem 0.75rem;
    border-radius: 999px;
    background: var(--color-primary-glow);
    color: var(--color-primary-text);
    font-size: var(--text-xs);
    font-weight: 500;
    line-height: 1;
    margin-right: var(--space-sm);
    animation: fadeUp var(--duration-fast) var(--ease-out) both;
}

.form-guard-indicator[hidden] {
    display: none;
}

.form-guard-indicator__dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: var(--color-primary);
    flex-shrink: 0;
}

@media (prefers-reduced-motion: reduce) {
    .form-guard-indicator {
        animation: none;
    }
}

.field-inline-error {
    font-size: var(--text-xs);
    color: var(--color-text-on-bg-error);
    margin-top: var(--space-xs);
    animation: fadeUp var(--duration-fast) var(--ease-out) both;
}

.input--error {
    border-color: var(--color-error) !important;
}

/* ---------- Form Fields ---------- */

.form-label {
    display: block;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text);
    margin-bottom: var(--space-xs);
    letter-spacing: 0.02em;
}

/* Unclassed labels anywhere inside a form-group match .form-label typography
   so a hand-rendered field cannot drift from the include-rendered ones. */
.form-group label:not(.form-label):not(.form-check) {
    display: block;
    margin-bottom: var(--space-xs);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text);
    letter-spacing: 0.02em;
}

.form-required {
    color: var(--color-primary-text);
}

.form-group textarea {
    min-height: 120px;
    resize: vertical;
    line-height: 1.6;
}

/*
 * Hearth-tinted chevron for every in-app dropdown. Default browser
 * chrome shows the native OS chevron, which on macOS is a stacked
 * double-arrow that reads as system-modal rather than parchment-page.
 * .form-select uses the same SVG; this rule applies it to every
 * .form-group select and .settings-select so the lead-tier dropdowns
 * and the "More settings" / accounts dropdowns share one register.
 * Padding-right reserves room so option text never overlaps the chevron.
 */
.form-group select,
.settings-select {
    appearance: none;
    padding-right: 2rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%238A7F76' d='M1.41 0L6 4.58 10.59 0 12 1.41l-6 6-6-6z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
}

.form-group input[type="checkbox"] {
    width: auto;
    margin-right: var(--space-xs);
}

/* Checkbox rows are label-after: the box leads, the words follow, and the
   whole row is the 44px target (WCAG 2.5.8). Markup: partials/_form_field.html. */
.form-check {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    min-height: 44px;
    cursor: pointer;
    font-weight: 500;
    color: var(--color-text);
}

.form-check input[type="checkbox"] {
    width: 24px;
    height: 24px;
    margin: 0.1rem 0 0;
    flex: none;
    accent-color: var(--color-primary);
}

.form-group input[type="file"] {
    width: 100%;
    padding: var(--space-sm);
    font-size: var(--text-sm);
    border: 1.5px dashed var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg);
    cursor: pointer;
}

.form-help {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-top: var(--space-xs);
}

/* Formatting hint (collapsible, below textarea) */
.formatting-hint {
    margin-top: calc(-1 * var(--space-sm));
    margin-bottom: var(--space-lg);
}

.formatting-hint summary {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    cursor: pointer;
    letter-spacing: 0.02em;
    min-height: 44px;
    display: flex;
    align-items: center;
}

.formatting-hint__intro {
    margin-top: var(--space-sm);
    margin-bottom: 0;
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    line-height: 1.5;
}

.formatting-hint-grid {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.3rem 0.75rem;
    margin-top: var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    background: var(--color-bg);
    border-radius: var(--radius-md);
    font-size: var(--text-xs);
    color: var(--color-text-secondary);
}

.formatting-hint-grid code {
    font-family: 'SFMono-Regular', 'Menlo', monospace;
    font-size: var(--text-xs);
    color: var(--color-primary-text);
    background: var(--color-primary-glow);
    padding: 0.1rem 0.35rem;
    border-radius: var(--radius-sm);
    max-width: none;
}

.form-error {
    font-size: var(--text-xs);
    color: var(--color-text-on-bg-error);
    margin-top: var(--space-xs);
    max-width: none;
}

.form-fieldset {
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    padding: var(--space-lg);
    margin-bottom: var(--space-lg);
}

/* Collapsible fieldset content — uses grid row transition for smooth reveal */
.form-fieldset__collapsible {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--duration-normal, 250ms) var(--ease-out, ease-out),
                opacity var(--duration-normal, 250ms) var(--ease-out, ease-out);
    opacity: 0;
}

.form-fieldset__collapsible.is-expanded {
    grid-template-rows: 1fr;
    opacity: 1;
}

.form-fieldset__collapsible > div {
    overflow: hidden;
}

.form-fieldset__legend {
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 600;
    padding: 0 var(--space-sm);
    color: var(--color-text);
}

/* Subgroup heading inside a fieldset (e.g. Notifications → "How often").
   Sentence-case (not eyebrow-caps) — heading text is phrase-length and
   DESIGN.md reserves all-caps for labels under 5 chars or button text.
   Semantically an <h3> so the outline reads correctly. */
.form-subgroup-heading {
    margin: var(--space-md) 0 var(--space-xs);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-text-secondary);
}

.form-subgroup-heading:first-child {
    margin-top: 0;
}

/* Micro-label inside a form-group that distinguishes parallel fields
   (e.g. "For you" vs "For subscribers"). Sits between the subgroup
   heading and the dropdown's own form-label. */
.form-subgroup-micro {
    margin: 0 0 var(--space-xs);
    color: var(--color-text-muted);
    font-size: 0.8125rem;
    font-weight: 500;
}

/* Secondary disclosure inside a fieldset — collapses advanced/edge controls
   (e.g. Notifications → delivery channels + subscriber options) so the
   primary choices stay ≤4 visible. Mirrors the settings-more +/en-dash glyph. */
.form-disclosure {
    margin-top: var(--space-md);
    border-top: 1px solid var(--color-border-light);
    padding-top: var(--space-xs);
}

.form-disclosure > summary {
    cursor: pointer;
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    min-height: 44px;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-primary-text);
}

.form-disclosure > summary::-webkit-details-marker {
    display: none;
}

.form-disclosure > summary::before {
    content: "+";
    width: 1em;
    text-align: center;
    font-weight: 600;
}

.form-disclosure[open] > summary::before {
    content: "\2013"; /* en-dash */
}

.form-checkbox {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    cursor: pointer;
    font-weight: 500;
}

.form-checkbox input[type="checkbox"] {
    margin: 0;
}

/* Long-form consent (e.g. TCPA SMS opt-in): checkbox alongside a
   multi-line paragraph of terms. Top-aligns the box with the first
   line instead of vertically centering it against the whole block. */
.form-consent > label {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    cursor: pointer;
    font-weight: 400;
    line-height: 1.5;
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
}

.form-consent > label > input[type="checkbox"] {
    margin: 0.25rem 0 0 0;
    flex-shrink: 0;
}

.form-consent a {
    color: var(--color-primary-text);
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

.form-sub-option {
    margin-top: var(--space-sm);
    /* No decorative left stripe — banned pattern. Indent alone signals
       the sub-relationship; the parent checkbox's context already
       makes the nesting clear. */
    margin-left: calc(var(--space-sm) + 18px);
    padding-left: var(--space-md);
    transition: opacity var(--duration-fast) var(--ease-out);
}

.form-group--error input,
.form-group--error textarea,
.form-group--error select {
    border-color: var(--color-error);
}

.form-errors {
    background: var(--color-bg-error, #fdf2f0);
    border: 1px solid var(--color-error, #C0503E);
    border-radius: var(--radius-md);
    padding: var(--space-md);
    margin-bottom: var(--space-lg);
    font-size: var(--text-sm);
    color: var(--color-text-on-bg-error);
}

.form-errors__heading {
    font-weight: 600;
    margin: 0 0 var(--space-xs);
}

.form-errors:focus {
    outline: none;
}

/* Utility classes for inline styles cleanup */
.text-center-wide {
    max-width: none;
    margin-bottom: var(--space-xl);
}

.text-error {
    color: var(--color-text-on-bg-error);
}

.btn-danger {
    background: var(--color-error);
    color: var(--color-text-on-primary);
    border-color: var(--color-error);
}

.btn-danger:hover {
    opacity: 0.9;
}

/* Secondary danger — the settings-page entry into delete. The act is
   serious but two-step (this just navigates to the confirm screen), so
   the visual weight is restrained: outlined in error color, never
   filled. Reserve the filled .btn-danger for the typed-confirm submit. */
.btn-danger-secondary {
    background: transparent;
    color: var(--color-text-on-bg-error);
    border: 1.5px solid var(--color-error);
    border-radius: var(--radius-md);
    padding: 0.6rem 1.25rem;
    font-size: 0.95rem;
    font-weight: 500;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.btn-danger-secondary:hover {
    background: var(--color-error);
    color: var(--color-text-on-primary);
    text-decoration: none;
}

.btn-danger-secondary:focus-visible {
    outline: 2px solid var(--color-error);
    outline-offset: 2px;
}

.flex-center {
    justify-content: center;
}

/* ---------- Danger Card (Delete) ---------- */
.danger-card {
    width: 100%;
    max-width: 500px;
    background: var(--color-bg-error);
    border: 1.5px solid rgba(192, 80, 62, 0.25);
    border-radius: var(--radius-xl);
    padding: var(--space-2xl);
    box-shadow: var(--shadow-lg);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
    text-align: center;
}

.danger-card h1 {
    color: var(--color-text-on-bg-error);
    margin-bottom: var(--space-md);
    font-size: 1.8rem;
}

.danger-card p {
    color: var(--color-text-secondary);
    max-width: none;
    margin-bottom: var(--space-lg);
}

.danger-card .btn-danger {
    background: var(--color-error);
    color: var(--color-text-on-primary);
    box-shadow: 0 2px 8px rgba(192, 80, 62, 0.2);
}

.danger-card .btn-danger:hover {
    background: var(--color-error-hover);
    color: var(--color-text-on-primary);
    box-shadow: 0 4px 16px rgba(192, 80, 62, 0.3);
    transform: translateY(-1px);
}

.danger-card .form-footer {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-lg);
    margin-top: var(--space-lg);
}

/* Typed-title confirmation: input recolors as the user types, and the
   submit/cancel pair share equal visual weight so the page never nudges
   toward delete. Cancel is rendered as a plain text link (not a btn-
   secondary outline) to keep the danger-card calm. */
.danger-confirm__match {
    border-color: var(--color-success);
}

.danger-confirm__actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-lg);
    margin-top: var(--space-lg);
    flex-wrap: wrap;
}

.danger-confirm__actions .btn-danger:disabled,
.danger-confirm__actions .btn-danger[disabled] {
    opacity: 0.55;
    cursor: not-allowed;
    box-shadow: none;
    transform: none;
}

.danger-confirm__cancel {
    font-size: 0.95rem;
    color: var(--color-text);
    text-decoration: underline;
    text-underline-offset: 0.2em;
    padding: 0.7rem 0;
}

.danger-confirm__promise {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    padding: var(--space-md);
    margin: var(--space-md) 0 var(--space-lg);
    font-size: 0.88rem;
    color: var(--color-text-secondary);
    text-align: left;
}

.danger-confirm__promise a {
    color: var(--color-primary-text);
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

/* Contributor self-delete affordance on the edit page — a permanent
   data-loss link, so it carries destructive (error) text styling.
   Text on a light surface uses --color-text-on-bg-error (the saturated
   --color-error fails WCAG AA as body text); hover deepens via the
   error-hover token. */
.edit-delete-affordance {
    margin-top: 1.5rem;
    text-align: center;
}

.text-danger {
    color: var(--color-text-on-bg-error);
}

.text-danger:hover {
    color: var(--color-error-hover);
}

/* ---------- Success Card ---------- */
.success-card {
    position: relative;
    width: 100%;
    max-width: 500px;
    background: var(--color-bg-card);
    border: 1.5px solid rgba(94, 139, 101, 0.25);
    border-radius: var(--radius-xl);
    padding: var(--space-2xl);
    box-shadow: var(--shadow-lg);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
    text-align: center;
    overflow: hidden;
}

.success-card h1 {
    color: var(--color-text-on-bg-success);
    margin-bottom: var(--space-sm);
}

.success-card p {
    color: var(--color-text-secondary);
    max-width: none;
    margin-bottom: var(--space-md);
}

.success-tagline {
    font-size: 1.05rem;
    margin-bottom: var(--space-lg);
}

.success-tagline strong {
    color: var(--color-text);
    font-weight: 600;
}

.success-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 52px;
    height: 52px;
    border-radius: 50%;
    background: var(--color-success-strong);
    color: var(--color-text-on-primary);
    font-size: 1.5rem;
    margin-bottom: var(--space-md);
    animation: successPop 0.5s var(--ease-out) 0.3s both;
}

@keyframes successPop {
    0% { transform: scale(0); opacity: 0; }
    100% { transform: scale(1); opacity: 1; }
}

.success-next {
    background: var(--color-bg-warm);
    border-radius: var(--radius-md);
    padding: var(--space-lg);
    margin-bottom: var(--space-lg);
    text-align: left;
}

.success-next__label {
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin-bottom: var(--space-sm);
}

.success-next__detail {
    font-size: 0.92rem;
    line-height: 1.65;
    color: var(--color-text-secondary);
    margin-bottom: 0;
}

.success-preview {
    width: 100%;
    margin: var(--space-lg) 0;
    text-align: left;
}

.success-actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    width: 100%;
}

.success-actions .btn {
    width: 100%;
    text-align: center;
}

/* Peak-end reduction (2026-05-16): submit_success.html now ends on
   two CTAs (View the book / Write another) plus an optional quiet
   "Edit your submission" link. The prior share-prompt and acquisition
   upsell were removed — confirmations stay quiet (PRODUCT.md warm
   restraint). `.success-secondary-link` keeps the edit link low-weight
   so it reads as a tool, not a CTA. */
.success-secondary-link {
    color: var(--color-text-muted);
}

.success-secondary-link a,
.success-secondary-link .link-button {
    color: var(--color-text-muted);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}

/* H-4: success page "Edit" affordance is now a <button> inside a POST <form>
   (the bearer EditToken was leaking via URL). Reset native button chrome so
   it reads as a link, not a button. */
.success-secondary-link .link-button {
    background: none;
    border-top: none;
    border-left: none;
    border-right: none;
    padding: 0;
    font: inherit;
    cursor: pointer;
}

.success-secondary-link.inline-edit-form {
    margin: var(--space-md) 0 0;
}

.success-secondary-link a:hover,
.success-secondary-link a:focus-visible,
.success-secondary-link .link-button:hover,
.success-secondary-link .link-button:focus-visible {
    color: var(--color-primary-text);
    border-bottom-color: var(--color-primary);
}

/* ---------- Verification Card ---------- */
.verify-card {
    width: 100%;
    max-width: 500px;
    border-radius: var(--radius-xl);
    padding: var(--space-2xl);
    box-shadow: var(--shadow-lg);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
    text-align: center;
}

.verify-card.verify-success {
    background: var(--color-bg-success);
    border: 1.5px solid rgba(94, 139, 101, 0.25);
}

.verify-card.verify-success h1 {
    color: var(--color-text-on-bg-success);
}

.verify-card.verify-error {
    background: var(--color-bg-error);
    border: 1.5px solid rgba(192, 80, 62, 0.25);
}

.verify-card.verify-error h1 {
    color: var(--color-text-on-bg-error);
}

.verify-card p {
    color: var(--color-text-secondary);
    max-width: none;
    margin-top: var(--space-md);
}

/* ---------- Onboarding Checklist ---------- */
.onboarding {
    max-width: 1100px;
    margin: 0 auto var(--space-lg);
    padding: var(--space-xl);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
}

.onboarding__title {
    font-size: 1.1rem;
    margin-bottom: var(--space-md);
    color: var(--color-text);
}

.onboarding__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.onboarding__item {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    font-size: 0.92rem;
    color: var(--color-text-secondary);
}

.onboarding__item--done {
    color: var(--color-text-muted);
    text-decoration: line-through;
}

.onboarding__check {
    width: 1.2em;
    text-align: center;
    flex-shrink: 0;
    font-size: var(--text-sm);
}

.onboarding__item--done .onboarding__check {
    color: var(--color-text-on-bg-success);
}

.onboarding__item a {
    color: var(--color-primary-text);
    text-decoration: none;
    font-weight: 500;
}

.onboarding__item a:hover {
    text-decoration: underline;
}

.onboarding__dismiss-form {
    margin-top: var(--space-md);
}

.onboarding__dismiss {
    background: none;
    border: none;
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    cursor: pointer;
    padding: var(--space-sm) var(--space-md);
    min-height: 44px;
    display: inline-flex;
    align-items: center;
}

.onboarding__dismiss:hover {
    color: var(--color-text-secondary);
    text-decoration: underline;
}

/* ---------- Digest Discovery Prompt ---------- */
.digest-prompt {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    background: var(--color-bg-warm);
    border: 1px solid var(--color-border);
    padding: var(--space-md) var(--space-lg);
    border-radius: var(--radius-md);
    margin-top: var(--space-lg);
    font-size: 0.88rem;
    color: var(--color-text-secondary);
    animation: fadeUp var(--duration-normal) var(--ease-out) both;
}

.digest-prompt p {
    margin: 0;
    max-width: none;
}

.digest-prompt a {
    font-weight: 500;
}

.digest-prompt__dismiss {
    background: none;
    border: none;
    color: var(--color-text-muted);
    font-size: 1.2rem;
    cursor: pointer;
    padding: var(--space-sm);
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
    flex-shrink: 0;
}

.digest-prompt__dismiss:hover {
    color: var(--color-text);
}

/* ---------- Empty State ---------- */
/* ==========================================================================
   Command Palette (Cmd+K)
   ========================================================================== */
.cmd-palette {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 200;
    align-items: flex-start;
    justify-content: center;
    padding-top: 20vh;
}

.cmd-palette--open {
    display: flex;
}

.cmd-palette__backdrop {
    position: fixed;
    inset: 0;
    background: rgba(26, 22, 20, 0.4);
    animation: fadeIn var(--duration-fast) var(--ease-out) both;
}

.cmd-palette__panel {
    position: relative;
    width: 100%;
    max-width: 480px;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    animation: fadeUp var(--duration-fast) var(--ease-out) both;
}

.cmd-palette__input {
    width: 100%;
    padding: var(--space-lg);
    border: none;
    border-bottom: 1px solid var(--color-border-light);
    background: transparent;
    font-family: var(--font-body);
    font-size: 1rem;
    color: var(--color-text);
    outline: none;
}

.cmd-palette__input:focus-visible {
    border-bottom-color: var(--color-border-focus);
    box-shadow: 0 1px 0 0 var(--color-border-focus);
}

.cmd-palette__input::placeholder {
    color: var(--color-text-muted);
}

.cmd-palette__list {
    list-style: none;
    margin: 0;
    padding: var(--space-xs) 0;
    max-height: 300px;
    overflow-y: auto;
}

.cmd-palette__list li {
    margin: 0;
}

.cmd-palette__list a {
    display: block;
    padding: var(--space-sm) var(--space-lg);
    color: var(--color-text-secondary);
    text-decoration: none;
    font-size: 0.92rem;
    transition: background var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.cmd-palette__list a:hover,
.cmd-palette__item--active a {
    background: var(--color-primary-glow);
    color: var(--color-text);
}

/* ==========================================================================
   Empty States
   ========================================================================== */
.empty-state {
    text-align: center;
    padding: var(--space-3xl) var(--space-lg);
    color: var(--color-text-muted);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
}

.empty-state-icon {
    font-size: 2.5rem;
    margin-bottom: var(--space-md);
    display: block;
    opacity: 0.6;
    animation: emptyStateFloat 3s ease-in-out infinite;
}

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

.empty-state h3 {
    font-size: 1.3rem;
    color: var(--color-text-secondary);
    margin-bottom: var(--space-sm);
}

.empty-state p {
    max-width: 40ch;
    margin: 0 auto var(--space-lg);
    font-size: 0.95rem;
}

/* Owner welcome message rendered inside the empty-state on the public page —
   gives a real human voice instead of generic "every memory matters" copy. */
.empty-state__welcome {
    max-width: 48ch;
    margin: 0 auto var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    background: var(--color-primary-glow);
    border-radius: var(--radius-sm);
    font-family: var(--font-display);
    font-size: 1.15rem;
    line-height: 1.5;
    color: var(--color-text);
    font-style: italic;
    text-align: left;
}

.empty-state__owner {
    max-width: 48ch;
    margin: 0 auto var(--space-lg);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    text-align: left;
    padding-left: var(--space-md);
}

/* ---------- Info Row (export status, digest info) ---------- */
.info-row {
    display: flex;
    gap: var(--space-lg);
    flex-wrap: wrap;
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-md);
}

.info-row strong {
    color: var(--color-text);
}

/* ---------- Settings Card & Grid ---------- */
.settings-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-2xl);
    box-shadow: var(--shadow-sm);
    margin-bottom: var(--space-lg);
}

.settings-card h2 {
    font-size: 1.3rem;
    margin-bottom: var(--space-md);
    color: var(--color-text);
}

.settings-card p {
    color: var(--color-text-secondary);
    font-size: 0.95rem;
    line-height: 1.6;
}

.settings-card--danger {
    background: var(--color-bg-error-subtle);
    border-color: rgba(192, 80, 62, 0.15);
}

.settings-grid {
    margin-top: var(--space-sm);
}

.settings-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--space-md) 0;
    border-bottom: 1px solid var(--color-border-light);
}

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

.settings-row--readonly {
    opacity: 0.85;
}

.settings-label {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    flex-shrink: 0;
    min-width: 120px;
}

.settings-value {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text);
    text-align: right;
}

.settings-value--muted {
    font-weight: 400;
    color: var(--color-text-muted);
}

.settings-input {
    font-family: var(--font-body);
    font-size: 1rem;
    min-height: 44px;
    color: var(--color-text);
    background: var(--color-bg);
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 0.45rem 0.7rem;
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.settings-input:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-border-focus);
    box-shadow: var(--shadow-glow);
    background: var(--color-bg-card);
}

.settings-select {
    min-width: 200px;
}

.settings-actions {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin-top: var(--space-lg);
}

.settings-link {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    text-decoration: none;
    transition: color var(--duration-fast) var(--ease-out);
}

.settings-link:hover {
    color: var(--color-primary-text);
}

/* ---------- Export List ---------- */
.export-list {
    margin-top: var(--space-lg);
    border-top: 1px solid var(--color-border);
}

.export-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--color-border-light, rgba(26, 22, 20, 0.06));
}

.export-item-info {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    min-width: 0;
    flex: 1;
}

.export-item-format {
    font-weight: 600;
    font-size: var(--text-sm);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text);
}

.export-item-meta {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.btn-delete {
    color: var(--color-text-on-bg-error);
    background: none;
    border: 1px solid var(--color-error);
}

.btn-delete:hover {
    background: var(--color-error);
    color: var(--color-text-on-primary);
}

.export-delete-form {
    display: inline;
}

.badge-failed {
    font-size: var(--text-xs);
    color: var(--color-error, #C0503E);
}

/* ---------- Progress Bar ---------- */
.progress-bar {
    width: 100%;
    height: 6px;
    background: var(--color-border-light);
    border-radius: 3px;
    overflow: hidden;
}

.progress-bar-fill {
    height: 100%;
    width: 100%;
    background: var(--color-primary);
    border-radius: 3px;
    transform: scaleX(0.3);
    transform-origin: left;
    transition: transform var(--duration-slow);
    will-change: transform;
}

.progress-bar-fill--active {
    transform: scaleX(0.7);
    animation: progressPulse 2s ease-in-out infinite;
}

@keyframes progressPulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}

/* ---------- Upload Preview ---------- */
.upload-preview {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-top: var(--space-sm);
}

.upload-preview-item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-sm);
}

.upload-preview-img {
    display: block;
    width: auto;
    max-width: min(100%, 240px);
    height: auto;
    max-height: 240px;
    object-fit: contain;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border-light);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
}

.upload-preview-tag {
    padding: var(--space-xs) var(--space-sm);
    background: var(--color-bg-warm);
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
    color: var(--color-text-secondary);
}

/* ---------- Color Picker ---------- */
.color-input {
    width: 60px;
    height: 36px;
    padding: 2px;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.color-picker-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
}

.color-hex-value {
    font-family: 'SFMono-Regular', 'Menlo', monospace;
    font-size: var(--text-xs);
    color: var(--color-text-secondary);
    background: var(--color-bg);
    padding: 0.15rem 0.4rem;
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border-light);
}

/* ---------- Branding Page ---------- */
.branding-image-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    align-items: center;
}

.branding-unsplash-panel {
    margin-top: var(--space-sm);
}

.branding-unsplash-panel[hidden] {
    display: none;
}

/* Collapsible fieldset toggle */
.form-fieldset__collapsible-wrap {
    cursor: default;
}

.form-fieldset__toggle {
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    user-select: none;
}

.form-fieldset__chevron {
    display: inline-block;
    width: 6px;
    height: 6px;
    border-top: 1.5px solid var(--color-text-muted);
    border-right: 1.5px solid var(--color-text-muted);
    transform: rotate(45deg);
    transition: transform var(--duration-fast) var(--ease-out);
}

.form-fieldset__toggle[aria-expanded="true"] .form-fieldset__chevron {
    transform: rotate(135deg);
}

.form-fieldset__gate-hint {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-top: var(--space-xs);
    margin-bottom: 0;
}

.form-fieldset__gate-hint a {
    color: var(--color-primary-text);
}

.form-fieldset--gated .form-fieldset__toggle {
    color: var(--color-text-muted);
}

/* ---------- Image Preview Widget ---------- */
.image-preview-widget__current {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-sm);
    margin-bottom: var(--space-sm);
}

.image-preview-widget__thumb {
    display: block;
    max-width: 100%;
    max-height: 240px;
    width: auto;
    height: auto;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border-light);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
}

.image-preview-widget__checkbox {
    margin-right: var(--space-xs);
}

/* ---------- Notification Channel Pills ---------- */
.form-checkbox-group ul {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    list-style: none;
    padding: 0;
    margin: 0;
}

.form-checkbox-group li {
    list-style: none;
}

.form-checkbox-group label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-xs) var(--space-md);
    border: 1px solid var(--color-border);
    border-radius: 100px;
    cursor: pointer;
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-secondary);
    background: var(--color-bg-card);
    transition: border-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                background-color var(--duration-fast) var(--ease-out);
    user-select: none;
}

.form-checkbox-group label:hover {
    border-color: var(--color-primary);
    color: var(--color-primary-text);
}

.form-checkbox-group input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.form-checkbox-group label:has(input:checked) {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-text-on-primary);
}

.form-checkbox-group label:has(input:checked):hover {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
}

/* ---------- Notification Details Collapse ---------- */
#notifications-details {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--duration-normal) var(--ease-out),
                opacity var(--duration-fast) var(--ease-out);
}

#notifications-details > * {
    overflow: hidden;
}

#notifications-details[open],
#notifications-details.is-open {
    grid-template-rows: 1fr;
}

/* ---------- Cover Upload ---------- */
.cover-upload {
    margin-bottom: var(--space-md);
}

.cover-upload__dropzone {
    position: relative;
    border: 2px dashed var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-xl) var(--space-lg);
    text-align: center;
    cursor: pointer;
    transition: border-color var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out);
    background: var(--color-bg);
    min-height: 140px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.cover-upload__dropzone:hover,
.cover-upload__dropzone--active {
    border-color: var(--color-primary);
    background: var(--color-primary-glow);
}

.cover-upload__input {
    position: absolute;
    inset: 0;
    opacity: 0;
    cursor: pointer;
    z-index: -1;
}

.cover-upload__prompt {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-xs);
    pointer-events: none;
}

.cover-upload__icon {
    font-size: 2rem;
    color: var(--color-text-muted);
    opacity: 0.5;
    line-height: 1;
}

.cover-upload__text {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
}

.cover-upload__text strong {
    color: var(--color-primary-text);
}

.cover-upload__hint {
    font-size: 0.78rem;
    color: var(--color-text-muted);
}

.cover-upload__preview {
    display: none;
    position: relative;
    width: 100%;
}

.cover-upload__preview--active {
    display: block;
}

.cover-upload__prompt--hidden {
    display: none;
}

.cover-upload__preview img {
    width: 100%;
    max-height: 220px;
    object-fit: cover;
    border-radius: var(--radius-md);
}

.cover-upload__clear {
    position: absolute;
    top: var(--space-sm);
    right: var(--space-sm);
    width: 36px;
    height: 36px;
    min-width: 44px;
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(26, 22, 20, 0.65);
    color: var(--color-text-on-primary);
    border: none;
    border-radius: 50%;
    font-size: 1.1rem;
    cursor: pointer;
    line-height: 1;
    transition: background var(--duration-fast);
}

.cover-upload__clear:hover {
    background: rgba(26, 22, 20, 0.85);
}

/* ---------- Cover Divider ---------- */
.cover-divider {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin: var(--space-lg) 0;
}

.cover-divider__line {
    flex: 1;
    height: 1px;
    background: var(--color-border-light);
}

.cover-divider__text {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    white-space: nowrap;
    letter-spacing: 0.02em;
}

/* Unsplash Picker */
.unsplash-picker {
    margin-top: 0.5rem;
}

.unsplash-picker__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.5rem;
}

.unsplash-powered {
    font-size: var(--text-xs);
    color: var(--color-text-muted, #6A5F54);
}

.unsplash-picker__search {
    margin-bottom: 0.75rem;
}

.unsplash-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.unsplash-thumb {
    position: relative;
    aspect-ratio: 1;
    border: 2px solid transparent;
    border-radius: 0.375rem;
    overflow: hidden;
    cursor: pointer;
    padding: 0;
    background: none;
}

.unsplash-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.unsplash-thumb.selected {
    border-color: var(--color-primary, #B65B37);
}

.unsplash-credit {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 0.25rem;
    font-size: var(--text-xs);
    color: var(--color-text-on-primary);
    /* 75% ink under the credit band: white text clears 4.5:1 over the darkest
       photo tone it is likely to sit on; 60% did not. */
    background: linear-gradient(transparent, color-mix(in srgb, var(--color-text) 75%, transparent));
    text-align: left;
}

.unsplash-selected {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.5rem;
    padding: 0.5rem;
    background: var(--color-surface, #EDE8E0);
    border-radius: 0.375rem;
    font-size: var(--text-sm);
}

.unsplash-load-more {
    text-align: center;
    margin-top: 0.5rem;
}

.unsplash-error,
.unsplash-empty {
    padding: 1rem;
    text-align: center;
    color: var(--color-text-muted, #6A5F54);
    font-size: var(--text-sm);
}

/* Page-end credits block for hero/cover image attributions
   (Unsplash license requires visible photographer + platform credit;
    placing it near the footer keeps the hero serene). */
.public-credits {
    margin: var(--space-xl) auto var(--space-md);
    padding: 0 var(--space-md);
    max-width: 60rem;
    text-align: center;
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    line-height: 1.5;
}

.public-credits__line {
    margin: 0;
}

.public-credits__line + .public-credits__line {
    margin-top: 0.125rem;
}

.public-credits a {
    color: inherit;
    text-decoration: underline;
}

@media (max-width: 640px) {
    .unsplash-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 360px) {
    .unsplash-grid {
        grid-template-columns: 1fr;
        gap: 0.25rem;
    }
}

/* ---------- Outreach ---------- */
.outreach-stats {
    display: flex;
    gap: var(--space-lg);
    margin-bottom: var(--space-xl);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
}

.outreach-stat {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.outreach-stat-number {
    font-family: var(--font-display);
    font-size: 1.8rem;
    font-weight: 700;
    color: var(--color-primary-text);
    line-height: 1;
}

.outreach-stat-label {
    font-size: 0.78rem;
    font-weight: 500;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.outreach-send-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

.outreach-send-row {
    display: flex;
    gap: var(--space-md);
    align-items: flex-start;
}

.outreach-send-row .form-group {
    margin-bottom: 0;
}

.outreach-contact-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
}

.outreach-chip {
    display: inline-flex;
    align-items: center;
    cursor: pointer;
}

.outreach-chip input[type="checkbox"] {
    display: none;
}

.outreach-chip-label {
    display: inline-block;
    padding: 0.35rem 0.75rem;
    border: 1.5px solid var(--color-border);
    border-radius: 100px;
    font-size: var(--text-xs);
    color: var(--color-text-secondary);
    transition: border-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out),
                background-color var(--duration-fast) var(--ease-out);
    user-select: none;
}

.outreach-chip input:checked + .outreach-chip-label {
    border-color: var(--color-primary);
    background: var(--color-primary-glow);
    color: var(--color-primary-text);
    font-weight: 500;
}

.outreach-chip-label:hover {
    border-color: var(--color-primary-light);
}

.outreach-oneoff {
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    padding: var(--space-sm) var(--space-md);
}

.outreach-oneoff-toggle {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    cursor: pointer;
    padding: var(--space-xs) 0;
}

.outreach-oneoff-fields {
    margin-top: var(--space-md);
}

.outreach-oneoff-save {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
}

.outreach-oneoff-save input[type="text"] {
    max-width: 200px;
}

/* Template cards */
.outreach-template-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}

.outreach-template-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
}

.outreach-template-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    margin-bottom: var(--space-sm);
}

.outreach-template-header h3 {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    font-size: 1rem;
    margin: 0;
}

.outreach-template-preview {
    font-size: 0.88rem;
    color: var(--color-text-muted);
    line-height: 1.5;
    max-width: none;
}

.outreach-template-edit {
    margin-top: var(--space-md);
    border-top: 1px solid var(--color-border-light);
    padding-top: var(--space-md);
}

.outreach-template-edit summary {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    cursor: pointer;
    margin-bottom: var(--space-md);
    min-height: 44px;
    display: flex;
    align-items: center;
}

/* Responded badge — distinct from Sent */
.badge-responded {
    background: rgba(94, 139, 101, 0.18);
    color: var(--color-text-on-bg-success);
    font-weight: 700;
}

/* Send footer */
.outreach-send-footer {
    padding-top: var(--space-md);
    border-top: 1px solid var(--color-border-light);
}

/* Selected count */
.outreach-selected-count {
    font-family: var(--font-body);
    font-size: 0.78rem;
    font-weight: 500;
    color: var(--color-primary-text);
    margin-left: var(--space-sm);
}

/* Opted-out indicator on chips */
.outreach-chip-opted-out {
    color: var(--color-text-on-bg-error);
    font-weight: 700;
    margin-left: 0.2rem;
}

/* ---------- Crop Modal ---------- */
dialog.crop-modal {
    position: fixed;
    inset: 0;
    z-index: 9999;
    width: 100vw;
    height: 100vh;
    max-width: none;
    max-height: none;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
}
dialog.crop-modal:not([open]) { display: none; }
dialog.crop-modal::backdrop {
    background: rgba(26, 22, 20, 0.8);
}

.crop-modal__container {
    position: relative;
    z-index: 1;
    background: var(--color-bg);
    border-radius: var(--radius-lg);
    color: var(--color-text);
    max-width: 90vw;
    max-height: 90vh;
    width: 640px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: var(--shadow-lg);
}

.crop-modal__body {
    flex: 1;
    min-height: 300px;
    max-height: 60vh;
    overflow: hidden;
    background: var(--color-surface);
}

.crop-modal__canvas {
    width: 100%;
    height: 100%;
}

.crop-modal__canvas img {
    display: block;
    max-width: 100%;
}

.crop-modal__toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    justify-content: center;
    border-top: 1px solid var(--color-border-light);
}

.crop-modal__group {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    align-items: center;
}

.crop-modal__btn {
    min-height: 44px;
    padding: 0 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text);
    font-size: var(--text-sm);
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}

.crop-modal__btn:hover {
    background: var(--color-primary-glow);
}

.crop-modal__btn:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.crop-modal__btn--active {
    background: var(--color-primary-glow);
    border-color: var(--color-primary);
}

.crop-modal__btn--cancel {
    padding: 8px 20px;
    min-height: 44px;
}

.crop-modal__btn--apply {
    padding: 8px 20px;
    min-height: 44px;
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-text-on-primary);
    font-weight: 600;
}

.crop-modal__btn--apply:hover {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
}

.crop-modal__actions {
    display: flex;
    justify-content: space-between;
    padding: var(--space-sm) var(--space-md);
    border-top: 1px solid var(--color-border-light);
}

.crop-modal__slider-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--color-text-muted);
}

.crop-modal__slider {
    /* Pointer target floor (WCAG 2.5.8): the thumb is small, so the control
       needs both the height and enough travel to be usable with a thumb. */
    width: 140px;
    min-height: 44px;
    accent-color: var(--color-primary);
}

@media (max-width: 480px) {
    .crop-modal__container {
        width: 100vw;
        max-width: 100vw;
        border-radius: 0;
        max-height: 100vh;
    }

    .crop-modal__toolbar {
        flex-direction: column;
        align-items: stretch;
        padding: var(--space-sm);
        gap: var(--space-sm);
    }

    .crop-modal__group {
        justify-content: center;
        flex-wrap: wrap;
    }

    .crop-modal__btn {
        padding: 10px 12px;
        font-size: 12px;
        min-height: 44px;
    }
}

/* Contact form layout */
.outreach-add-contact-form {
    max-width: 600px;
}

.outreach-contact-row {
    display: flex;
    gap: var(--space-md);
}

.outreach-contact-row .form-group {
    flex: 1;
}

.outreach-contact-extras {
    margin-bottom: var(--space-md);
}

.outreach-contact-extras summary {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    cursor: pointer;
    margin-bottom: var(--space-md);
    min-height: 44px;
    display: flex;
    align-items: center;
}

@media (max-width: 640px) {
    .outreach-stats {
        gap: var(--space-md);
    }

    .outreach-stat-number {
        font-size: 1.4rem;
    }

    .outreach-contact-row {
        flex-direction: column;
    }
}

/* ── Markdown rendered content ────────────────────────────── */
.public-welcome p,
.memory-card-text p,
.permalink-text p { margin-bottom: 0.5em; }

.public-welcome p:last-child,
.memory-card-text p:last-child,
.permalink-text p:last-child { margin-bottom: 0; }

.public-welcome strong,
.memory-card-text strong,
.permalink-text strong { font-weight: 600; }

.public-welcome em,
.memory-card-text em,
.permalink-text em { font-style: italic; }

.public-welcome ul,
.memory-card-text ul,
.permalink-text ul,
.public-welcome ol,
.memory-card-text ol,
.permalink-text ol {
    padding-left: 1.5em;
    margin-bottom: 0.5em;
}

.public-welcome blockquote,
.memory-card-text blockquote,
.permalink-text blockquote {
    position: relative;
    padding: 0.5em 0 0.5em 2em;
    margin: 0.75em 0;
    color: var(--color-text-secondary);
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.05em;
    line-height: 1.55;
    max-width: 60ch;
}

.public-welcome blockquote::before,
.memory-card-text blockquote::before,
.permalink-text blockquote::before {
    content: "\201C";
    position: absolute;
    left: 0;
    top: -0.1em;
    font-family: var(--font-display);
    font-size: 2.5em;
    line-height: 1;
    color: var(--color-primary-text);
    opacity: 0.35;
    pointer-events: none;
}

.public-welcome a,
.memory-card-text a,
.permalink-text a {
    /* --color-primary-text passes contrast in both themes (unlike the
       undefined-fallback --color-primary, ~3.22:1 in dark mode). Accent
       tracking is live (2026-08 accent-text-followups Task 1): a branded
       book's --color-primary-text/-text-hover are overridden per-theme by
       apps/books/templates/books/partials/_branding_style.html, so these
       links pick up the owner's accent (darkened/lightened to clear
       WCAG AA) rather than the house terracotta. */
    color: var(--color-primary-text);
    text-decoration: underline;
}

.public-welcome code,
.memory-card-text code,
.permalink-text code {
    background: var(--color-surface, #F8F5F0);
    padding: 0.1em 0.3em;
    border-radius: 3px;
    font-size: 0.9em;
}

.public-welcome pre,
.memory-card-text pre,
.permalink-text pre {
    background: var(--color-surface, #F8F5F0);
    padding: 0.75em 1em;
    border-radius: 6px;
    overflow-x: auto;
    margin: 0.5em 0;
}

.public-welcome h2,
.memory-card-text h2,
.permalink-text h2 {
    font-size: 1.25em;
    margin: 0.75em 0 0.25em;
}

.public-welcome h3,
.memory-card-text h3,
.permalink-text h3 {
    font-size: 1.1em;
    margin: 0.5em 0 0.25em;
}

.public-welcome hr,
.memory-card-text hr,
.permalink-text hr {
    border: none;
    border-top: 1px solid var(--color-border, #DDD5CB);
    margin: 1em 0;
}


/* ---------- Attach component (photo / audio / video) ----------
   One structure, one state machine. State lives on data-state; children show
   and hide by state. No inline display toggling. Behaviour: media-attach.js. */
.attach {
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    padding: var(--space-lg);
    margin-bottom: var(--space-lg);
}

.attach--compact {
    border: 0;
    padding: 0;
    margin-bottom: var(--space-md);
}

.attach__legend {
    font-family: var(--font-display);
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--color-text);
    margin-bottom: var(--space-xs);
}

.attach__limit {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin: 0 0 var(--space-md);
}

.attach__controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
}

.attach__pick {
    position: relative;
    overflow: hidden;
    cursor: pointer;
}

.attach__input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
    font-size: 1rem;
}

.attach__pick:focus-within {
    box-shadow: var(--shadow-glow);
    border-color: var(--color-primary);
}

.attach__dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--color-error);
    margin-right: 0.5em;
}

.attach__stop {
    background: var(--color-error);
    color: var(--color-text-on-primary);
    border-color: var(--color-error);
}

.attach__stop:hover {
    background: var(--color-error-active);
    color: var(--color-text-on-primary);
}

.attach__timer {
    font-size: 0.95rem;
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
}

.attach__timer--warning {
    color: var(--color-text-on-bg-error);
    font-weight: 600;
}

.attach__camera {
    min-height: 44px;
    padding: 0.4rem 0.6rem;
    font-family: var(--font-body);
    font-size: 1rem;
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-card);
    color: var(--color-text);
}

.attach__camera:focus {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-border-focus);
    box-shadow: var(--shadow-glow);
}

.attach__preview {
    margin-top: var(--space-sm);
}

.attach__thumb,
.attach__player,
.attach__live,
.attach__waveform {
    display: none;
    width: 100%;
    max-width: 100%;
    border-radius: var(--radius-md);
    background: var(--color-surface-alt);
    opacity: 0;
    transition: opacity var(--duration-normal) var(--ease-out);
}

.attach__thumb {
    max-width: 240px;
    height: auto;
}

.attach__waveform {
    height: 60px;
}

.attach__status {
    font-size: 0.95rem;
    color: var(--color-text-secondary);
    margin: var(--space-xs) 0 0;
    min-height: 1.4em;
}

.attach__status:focus {
    outline: none;
}

.attach__remove {
    display: none;
    margin-top: var(--space-xs);
}

/* Crop lives inside the component: crop.js's own .upload-preview would be
   appended into .attach__pick, which the attached state hides. */
.attach__crop {
    display: none;
    margin-top: var(--space-xs);
}

/* Crop / Reset crop for media already on the submission (edit form). */
.attach__crop-actions {
    display: none;
    flex-wrap: wrap;
    gap: var(--space-sm);
    margin-top: var(--space-xs);
}

.attach__error {
    display: none;
    background: var(--color-bg-error);
    border: 1px solid var(--color-error);
    border-radius: var(--radius-md);
    color: var(--color-text);
    padding: var(--space-sm) var(--space-md);
    margin: var(--space-sm) 0 0;
}

/* State machine */
.attach[data-state="empty"] .attach__stop,
.attach[data-state="empty"] .attach__timer,
.attach[data-state="empty"] .attach__camera { display: none; }

.attach[data-state="requesting"] .attach__record { opacity: 0.6; pointer-events: none; }
.attach[data-state="requesting"] .attach__stop,
.attach[data-state="requesting"] .attach__timer { display: none; }

.attach[data-state="recording"] .attach__record,
.attach[data-state="recording"] .attach__pick { display: none; }
.attach[data-state="recording"] .attach__dot { animation: attach-pulse 1s var(--ease-out) infinite; }
.attach[data-state="recording"] .attach__live,
.attach[data-state="recording"] .attach__waveform { display: block; opacity: 1; }

.attach[data-state="attached"] .attach__record,
.attach[data-state="attached"] .attach__pick,
.attach[data-state="attached"] .attach__stop,
.attach[data-state="attached"] .attach__timer,
.attach[data-state="attached"] .attach__camera { display: none; }
.attach[data-state="attached"] .attach__thumb[src],
.attach[data-state="attached"] .attach__player[src] { display: block; opacity: 1; }
.attach[data-state="attached"] .attach__remove { display: inline-flex; }
.attach[data-state="attached"] .attach__crop { display: inline-flex; }
.attach[data-state="attached"] .attach__crop-actions,
.attach[data-state="removed"] .attach__crop-actions { display: flex; }

.attach[data-state="error"] .attach__error { display: block; }
.attach[data-state="error"] .attach__stop,
.attach[data-state="error"] .attach__timer { display: none; }

/* `removed` is the edit-form Undo state: the media is still on screen, dimmed,
   with Undo beside it. It must hide the recording cluster like every other
   non-recording state, or Remove exposes a live Stop next to Undo. The dim is
   applied ONCE, on the wrapper; the children re-assert opacity 1 so the two
   values do not multiply to 0.16. */
.attach[data-state="removed"] .attach__stop,
.attach[data-state="removed"] .attach__timer,
.attach[data-state="removed"] .attach__camera { display: none; }
.attach[data-state="removed"] .attach__preview { opacity: 0.4; }
.attach[data-state="removed"] .attach__remove { display: inline-flex; }
.attach[data-state="removed"] .attach__thumb[src],
.attach[data-state="removed"] .attach__player[src] { display: block; opacity: 1; }

/* Progressive enhancement for Remove. The checkbox is the real control and is
   visible until media-attach.js adds .attach--js; only then does the button
   take over. These two rules MUST stay after the state machine above: the
   no-JS rule ties it on specificity and wins on source order. */
.attach--js .attach__remove-check {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
}

.attach[data-existing-id]:not(.attach--js) .attach__remove { display: none; }

@keyframes attach-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.3; }
}

/* Disclosure that holds the secondary attach kinds + the private note */
.form-more {
    margin-bottom: var(--space-lg);
}

.form-more > summary {
    cursor: pointer;
    min-height: 44px;
    display: flex;
    align-items: center;
    font-family: var(--font-body);
    font-weight: 500;
    color: var(--color-primary-text);
}

.form-more > summary:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    box-shadow: var(--shadow-glow);
    border-radius: var(--radius-sm);
}

.form-more[open] > summary {
    margin-bottom: var(--space-md);
}

/* ── Interview Chat ──────────────────────────────────────────── */

.interview-card {
    width: 100%;
    max-width: 640px;
    margin: 0 auto;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-xl);
    padding: var(--space-2xl);
    box-shadow: var(--shadow-lg);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
}

.interview-card h1 {
    text-align: center;
    margin-bottom: var(--space-xs);
    font-size: 2rem;
}

.interview-intro {
    text-align: center;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    margin-bottom: var(--space-lg);
    line-height: 1.6;
}

.interview-chat {
    margin: var(--space-md) 0;
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    background: var(--color-bg);
    overflow: hidden;
}

.interview-messages {
    max-height: 420px;
    overflow-y: auto;
    padding: var(--space-lg) var(--space-md);
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    scroll-behavior: smooth;
}

/* Scrollbar styling for chat */
.interview-messages::-webkit-scrollbar {
    width: 6px;
}

.interview-messages::-webkit-scrollbar-track {
    background: transparent;
}

.interview-messages::-webkit-scrollbar-thumb {
    background: var(--color-border);
    border-radius: 3px;
}

.interview-bubble {
    max-width: 82%;
    padding: var(--space-sm) var(--space-md);
    line-height: 1.6;
    word-wrap: break-word;
    animation: bubbleIn var(--duration-normal) var(--ease-out) both;
    position: relative;
}

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

.interview-bubble--interviewer {
    align-self: flex-start;
    background: var(--color-bg-card);
    color: var(--color-text);
    border-radius: var(--radius-lg) var(--radius-lg) var(--radius-lg) var(--radius-sm);
    border: 1px solid var(--color-border-light);
    box-shadow: var(--shadow-sm);
}

.interview-bubble--interviewer::before {
    content: "Interviewer";
    display: block;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-accent-text);
    margin-bottom: 2px;
}

.interview-bubble--contributor {
    align-self: flex-end;
    background: var(--color-primary);
    color: var(--color-text-on-primary);
    border-radius: var(--radius-lg) var(--radius-lg) var(--radius-sm) var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

.interview-bubble--contributor::before {
    content: "You";
    display: block;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: color-mix(in srgb, var(--color-text-on-primary) 70%, transparent);
    margin-bottom: 2px;
}

.interview-input-row {
    display: flex;
    gap: var(--space-sm);
    align-items: flex-end;
    padding: var(--space-md);
    border-top: 1px solid var(--color-border-light);
    background: var(--color-bg-card);
}

.interview-input-row textarea {
    flex: 1;
    resize: none;
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    font-family: var(--font-body);
    font-size: 0.95rem;
    line-height: 1.5;
    background: var(--color-bg);
    color: var(--color-text);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.interview-input-row textarea:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-primary);
    box-shadow: var(--shadow-glow);
}

.interview-input-row textarea::placeholder {
    color: var(--color-text-muted);
}

.interview-input-row .btn {
    flex-shrink: 0;
    border-radius: var(--radius-lg);
    padding: var(--space-sm) var(--space-lg);
}

.interview-input-row .btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Typing indicator */
.typing-indicator {
    display: inline-flex;
    align-self: flex-start;
    gap: 5px;
    padding: var(--space-sm) var(--space-md);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg) var(--radius-lg) var(--radius-lg) var(--radius-sm);
    box-shadow: var(--shadow-sm);
    animation: bubbleIn var(--duration-normal) var(--ease-out) both;
}

.typing-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--color-text-muted);
    animation: typing-pulse 1.4s ease-in-out infinite;
}

.typing-dot:nth-child(2) { animation-delay: 0.2s; }
.typing-dot:nth-child(3) { animation-delay: 0.4s; }

@keyframes typing-pulse {
    0%, 80%, 100% { transform: translateY(0); opacity: 0.4; }
    40% { transform: translateY(-5px); opacity: 1; }
}

.interview-actions {
    margin-top: var(--space-md);
    text-align: center;
    padding-top: var(--space-sm);
}

.interview-actions .btn {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    border: none;
    background: none;
    text-decoration: underline;
    cursor: pointer;
    padding: var(--space-xs) var(--space-sm);
}

.interview-actions .btn:hover {
    color: var(--color-text-secondary);
}

.interview-confirm {
    text-align: center;
    padding: var(--space-md);
    background: var(--color-bg-warm);
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border-light);
    animation: fadeUp var(--duration-normal) var(--ease-out) both;
}

.interview-confirm__text {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-md);
    line-height: 1.5;
}

.interview-confirm__actions {
    display: flex;
    gap: var(--space-sm);
    justify-content: center;
}

.interview-complete {
    text-align: center;
    padding: var(--space-xl) var(--space-lg);
    animation: bubbleIn var(--duration-slow) var(--ease-out) both;
}

.interview-complete p {
    margin-bottom: var(--space-md);
    color: var(--color-text-secondary);
    font-size: 1.05rem;
}

.interview-complete .btn {
    margin-top: var(--space-sm);
}

/* ── Interview — Responsive ──── */

@media (max-width: 640px) {
    .interview-card {
        padding: var(--space-lg) var(--space-md);
        border-radius: var(--radius-lg);
    }

    .interview-card h1 {
        font-size: 1.5rem;
    }

    .interview-messages {
        max-height: 55vh;
        padding: var(--space-md) var(--space-sm);
    }

    .interview-bubble {
        max-width: 90%;
        font-size: 0.95rem;
    }

    .interview-input-row {
        padding: var(--space-sm);
    }

    .interview-input-row textarea {
        font-size: 1rem; /* Prevent iOS zoom */
    }

    .interview-input-row .btn {
        padding: var(--space-sm) var(--space-md);
    }
}

/* ==========================================================================
   Contribution Hub — mode chooser between Write / Record / Interview / Video
   ========================================================================== */

.hub {
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: var(--space-xl) var(--space-lg) var(--space-2xl);
}

.hub-header {
    text-align: center;
    max-width: 520px;
    margin-bottom: var(--space-xl);
    animation: fadeUp 0.6s var(--ease-out) both;
}

.hub-header__back {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    text-decoration: none;
    margin-bottom: var(--space-lg);
    transition: color var(--duration-fast) var(--ease-out);
}

.hub-header__back:hover {
    color: var(--color-primary-text);
}

.hub-header__back svg {
    width: 14px;
    height: 14px;
}

.hub-header h1 {
    font-family: var(--font-display);
    font-size: clamp(1.75rem, 4vw, 2.25rem);
    font-weight: 500;
    letter-spacing: -0.01em;
    line-height: 1.2;
    margin-bottom: var(--space-sm);
}

.hub-header__book {
    font-size: 0.95rem;
    color: var(--color-text-secondary);
}

/* ---------- Contribute Context Strip ----------
   Persistent header on /contribute/ that shows the book the visitor is
   contributing to: cover thumbnail + title + "Invited by [owner]". Sticky
   on scroll so the context never falls off the screen. */
.contribute-context {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    width: 100%;
    max-width: 640px;
    margin: 0 auto var(--space-xl);
    padding: var(--space-sm) var(--space-md);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}

.contribute-context__cover {
    flex-shrink: 0;
    width: 56px;
    height: 56px;
    border-radius: var(--radius-md);
    object-fit: cover;
    background: var(--color-bg-warm);
}

.contribute-context__cover--placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-primary-glow);
    color: var(--color-primary-text);
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 600;
    text-transform: uppercase;
}

.contribute-context__text {
    flex: 1;
    min-width: 0;
}

.contribute-context__title {
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 500;
    color: var(--color-text);
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.contribute-context__owner {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-top: 2px;
}

.contribute-context__back {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-xs) var(--space-sm);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    text-decoration: none;
    border-radius: var(--radius-sm);
    transition: color var(--duration-fast) var(--ease-out),
                background-color var(--duration-fast) var(--ease-out);
}

.contribute-context__back:hover,
.contribute-context__back:focus-visible {
    color: var(--color-primary-text);
    background: var(--color-primary-glow);
}

.contribute-context__back svg {
    width: 14px;
    height: 14px;
}

@media (max-width: 480px) {
    .contribute-context {
        padding: var(--space-sm);
        gap: var(--space-sm);
    }

    .contribute-context__cover {
        width: 44px;
        height: 44px;
    }

    .contribute-context__title {
        font-size: 0.95rem;
    }

    .contribute-context__back span {
        display: none;
    }
}

.hub-intro {
    text-align: center;
    max-width: 520px;
    margin: 0 auto var(--space-lg);
    font-size: 0.95rem;
    color: var(--color-text-secondary);
    line-height: 1.6;
}

/* ── Inspiration prompts (progressive disclosure) ──── */

.hub-prompts {
    max-width: 520px;
    margin: 0 auto var(--space-lg);
}

.hub-prompts__summary {
    cursor: pointer;
    text-align: center;
    font-size: 0.95rem;
    color: var(--color-primary-text);
    min-height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.hub-prompts__summary:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    box-shadow: var(--shadow-glow);
    border-radius: var(--radius-md);
}

.hub-prompts__list {
    margin: var(--space-sm) 0 0;
    padding-left: var(--space-lg);
    color: var(--color-text-secondary);
    line-height: 1.6;
}

.hub-prompts__list li {
    margin-bottom: var(--space-xs);
}

/* ── Mode Cards Grid ──── */

.hub-modes {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-lg);
    max-width: 600px;
    width: 100%;
    margin-bottom: var(--space-xl);
}

.hub-mode {
    position: relative;
    background: var(--color-bg-card);
    border: 1.5px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-xl) var(--space-lg) var(--space-lg);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    text-decoration: none;
    color: inherit;
    cursor: pointer;
    transition:
        border-color var(--duration-normal) var(--ease-out),
        box-shadow var(--duration-normal) var(--ease-out),
        transform var(--duration-normal) var(--ease-out),
        background var(--duration-normal) var(--ease-out);
    animation: fadeUp 0.6s var(--ease-out) both;
    overflow: hidden;
}

/* Stagger driven by --i (set inline as forloop.counter0). Supports any
   number of tiles without hand-rolled nth-child rules. */
.hub-mode,
.hub-primary {
    animation-delay: calc(var(--i, 0) * 80ms + 80ms);
}

.hub-mode::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--mode-color, var(--color-primary));
    opacity: 0;
    transition: opacity var(--duration-normal) var(--ease-out);
}

.hub-mode:hover {
    border-color: var(--mode-color, var(--color-primary));
    box-shadow: var(--shadow-md), 0 0 0 1px color-mix(in srgb, var(--color-primary) 6%, transparent);
    transform: translateY(-2px);
    background: var(--color-bg-card-hover);
}

.hub-mode:hover::before {
    opacity: 1;
}

.hub-mode:active {
    transform: translateY(0);
}

.hub-mode:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    box-shadow: var(--shadow-glow);
    border-color: var(--color-primary);
}

/* ── Mode Icons ──── */

.hub-mode__icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: var(--space-md);
    background: var(--mode-bg, var(--color-primary-glow));
    transition: transform var(--duration-normal) var(--ease-out);
}

.hub-mode:hover .hub-mode__icon {
    transform: scale(1.08);
    background: var(--mode-bg);
}

.hub-mode__icon svg {
    width: 26px;
    height: 26px;
    stroke: var(--mode-color, var(--color-primary));
    fill: none;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* ── Mode Text ──── */

.hub-mode__title {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 600;
    margin-bottom: var(--space-xs);
    line-height: 1.3;
}

.hub-mode__desc {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    line-height: 1.5;
    max-width: 200px;
}

/* ── Mode Color Variants ──── */

.hub-mode--write     { --mode-color: var(--color-primary); --mode-bg: var(--color-primary-glow); }
.hub-mode--photo     { --mode-color: var(--color-primary); --mode-bg: var(--color-primary-glow); }
.hub-mode--audio     { --mode-color: var(--color-primary-light); --mode-bg: var(--color-primary-glow); }
.hub-mode--chat      { --mode-color: var(--color-info); --mode-bg: rgba(122, 107, 102, 0.10); }
.hub-mode--video     { --mode-color: var(--color-accent); --mode-bg: rgba(125, 132, 113, 0.10); }

/* ── Primary Tile: Write ──────────────────────────────────────────────
   The hero affordance on /contribute/. Writing is the brand's literary
   core and the channel everyone can use, so it gets the most visual
   weight — full-width, taller, eyebrow + CTA. Voice / Video / Interview
   become smaller secondary tiles below.  */

.hub-primary {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-lg);
    width: 100%;
    max-width: 600px;
    margin: 0 auto var(--space-md);
    padding: var(--space-xl) var(--space-xl) var(--space-lg);
    background: var(--color-bg-card);
    border: 1.5px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    text-decoration: none;
    color: inherit;
    overflow: hidden;
    transition:
        border-color var(--duration-normal) var(--ease-out),
        box-shadow var(--duration-normal) var(--ease-out),
        transform var(--duration-normal) var(--ease-out),
        background var(--duration-normal) var(--ease-out);
    animation: fadeUp 0.6s var(--ease-out) both;
}

/* Single-pixel accent at the top — same vocabulary as .hub-mode::before
   but always visible on the primary tile to signal "this is the path". */
.hub-primary::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: var(--color-primary);
}

.hub-primary:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-md), 0 0 0 1px color-mix(in srgb, var(--color-primary) 6%, transparent);
    transform: translateY(-2px);
    background: var(--color-bg-card-hover);
}

.hub-primary:active { transform: translateY(0); }

.hub-primary:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    box-shadow: var(--shadow-glow);
    border-color: var(--color-primary);
}

.hub-primary__body {
    flex: 1;
    min-width: 0;
}

.hub-primary__eyebrow {
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-primary-text);
    margin-bottom: var(--space-sm);
}

.hub-primary__title {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    font-family: var(--font-display);
    font-size: clamp(1.35rem, 3vw, 1.6rem);
    font-weight: 500;
    line-height: 1.2;
    letter-spacing: -0.01em;
    margin-bottom: var(--space-xs);
    color: var(--color-text);
}

.hub-primary__icon {
    width: 22px;
    height: 22px;
    stroke: var(--color-primary);
    fill: none;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
    flex-shrink: 0;
}

.hub-primary__desc {
    font-size: 0.92rem;
    color: var(--color-text-secondary);
    line-height: 1.55;
    max-width: 38ch;
}

.hub-primary__cta {
    flex-shrink: 0;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-primary-text);
    white-space: nowrap;
    transition: transform var(--duration-fast) var(--ease-out);
}

.hub-primary:hover .hub-primary__cta {
    transform: translateX(3px);
}

/* ── Secondary Tiles: Voice / Video / Interview ───────────────────────
   Two- or three-up grid, lower visual weight than the primary tile.
   Reuses .hub-mode atom so color variants and icon styles still apply. */
.hub-secondary {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
    gap: var(--space-md);
    width: 100%;
    max-width: 600px;
    margin: 0 auto var(--space-lg);
}

.hub-secondary .hub-mode {
    padding: var(--space-lg) var(--space-md);
}

.hub-secondary .hub-mode__title {
    font-size: 1rem;
}

.hub-secondary .hub-mode__desc {
    font-size: 0.78rem;
}

/* ── Coming Soon Badge ──── */

.hub-mode--soon {
    opacity: 0.55;
    pointer-events: none;
}

.hub-mode__badge {
    position: absolute;
    top: var(--space-md);
    right: var(--space-md);
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    background: var(--color-surface);
    padding: 2px 8px;
    border-radius: 99px;
}

/* Messaging-channel disclosure & pill atoms (`.hub-disclosure*`,
   `.hub-channels*`, `.hub-channel*`) were removed when the contribute
   hub stopped advertising SMS/WhatsApp/Telegram/RCS/iMessage/Email to
   web visitors. The share-card surface (apps/sharing/) uses its own
   `.submission-method*` classes and is unaffected. */

.hub-mode__icon-inline {
    width: 20px;
    height: 20px;
    vertical-align: -3px;
    margin-right: 0.35em;
    stroke: var(--mode-color, var(--color-primary));
    fill: none;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* ── Hub Responsive ──── */

@media (max-width: 540px) {
    .hub {
        padding: var(--space-lg) var(--space-md) var(--space-xl);
    }

    .hub-modes {
        grid-template-columns: 1fr;
        gap: var(--space-md);
    }

    /* Primary Write tile: stack the CTA below the body so the headline
       has room to breathe on phone widths without truncating. */
    .hub-primary {
        flex-direction: column;
        align-items: flex-start;
        padding: var(--space-lg);
        gap: var(--space-sm);
    }

    .hub-primary__cta {
        align-self: flex-end;
    }

    /* Secondary tiles stay grid-auto, but become single column at the
       narrowest widths so each option keeps a comfortable tap target. */
    .hub-secondary {
        grid-template-columns: 1fr;
    }

    .hub-mode {
        flex-direction: row;
        text-align: left;
        padding: var(--space-lg);
        gap: var(--space-md);
    }

    .hub-mode__icon {
        margin-bottom: 0;
        flex-shrink: 0;
    }

    .hub-mode__desc {
        max-width: none;
    }
}

/* ---------- Feature Badges ---------- */
.feature-badge {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 2px var(--space-xs);
    border-radius: var(--radius-sm);
    vertical-align: middle;
    line-height: 1.4;
}

.feature-badge--coming-soon {
    background: color-mix(in srgb, var(--color-warning) 15%, transparent);
    color: var(--color-text-on-bg-warning);
    border: 1px solid color-mix(in srgb, var(--color-warning) 30%, transparent);
}

.feature-badge--beta {
    background: color-mix(in srgb, var(--color-info) 15%, transparent);
    color: var(--color-text-on-bg-info);
    border: 1px solid color-mix(in srgb, var(--color-info) 30%, transparent);
}

.feature-badge--live {
    background: color-mix(in srgb, var(--color-success) 15%, transparent);
    color: var(--color-text-on-bg-success);
    border: 1px solid color-mix(in srgb, var(--color-success) 30%, transparent);
}

/* ── F-11: Live Preview on /books/<slug>/branding/ ────────────────── */

.branding-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(280px, 380px);
    gap: var(--space-2xl);
    align-items: start;
    margin-top: var(--space-lg);
}

@media (max-width: 960px) {
    .branding-layout {
        grid-template-columns: 1fr;
    }
}

.branding-preview {
    position: sticky;
    top: var(--space-xl);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: 0 2px 8px color-mix(in srgb, var(--color-text) 6%, transparent);
}

@media (max-width: 960px) {
    .branding-preview {
        position: static;
        margin-bottom: var(--space-xl);
    }
}

.branding-preview__label {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    padding: var(--space-sm) var(--space-md);
    background: var(--color-bg-warm);
    border-bottom: 1px solid var(--color-border-light);
    font-family: var(--font-body);
}

.branding-preview__eyebrow {
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-primary-text);
}

.branding-preview__hint {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.branding-preview__frame {
    background: var(--color-bg);
}

.branding-preview__cover {
    aspect-ratio: 3 / 1;
    background-color: var(--color-surface);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    transition: background-image var(--duration-fast) var(--ease-out);
}

.branding-preview__content {
    padding: var(--space-md);
}

.branding-preview__title {
    font-family: var(--font-display);
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--color-text);
    margin: 0 0 var(--space-xs);
    line-height: 1.2;
}

.branding-preview__subtitle {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin: 0 0 var(--space-sm);
    line-height: 1.4;
}

.branding-preview__subtitle[hidden] {
    display: none;
}

/*
 * Welcome line in the branding preview. Reads as an italic editorial quote
 * over a parchment-warm field — keepsake decorative tokens carry the visual
 * weight (.impeccable.md Principle 4). The original 2px left-border accent
 * was removed 2026-04-30 (M-2 in the Linda persona review) — even with the
 * "scaled-down preview of public blockquote" framing it still matches the
 * BAN 1 pattern, and the parchment-tinted treatment is the more on-brand
 * answer.
 */
.branding-preview__welcome {
    /* Parchment-warm background instead of a side-stripe accent rule —
       the `border-left: Npx solid <color>` shape is an AI-tell ban per
       .impeccable.md BAN 1. Keepsake decorative tokens (parchment-warm)
       carry the visual weight without the AI-tell. M-2 fix from the
       2026-04-30 Linda persona review. */
    margin: var(--space-sm) 0;
    padding: var(--space-xs) var(--space-sm);
    background: var(--color-parchment-warm);
    border-radius: var(--radius-sm);
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    line-height: 1.5;
}

.branding-preview__welcome[hidden] {
    display: none;
}

.branding-preview__welcome cite {
    display: block;
    margin-top: var(--space-xs);
    font-style: normal;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    font-family: var(--font-body);
}

.branding-preview__cta {
    display: inline-block;
    margin-top: var(--space-sm);
    padding: 0.5rem 1rem;
    background: var(--preview-accent, var(--color-primary));
    color: var(--color-text-on-primary);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    border: none;
    border-radius: var(--radius-sm);
    cursor: default;
}

/* Memory Promise — editorial strip with italic numerals leading each right.
   Centered trio with breathing room; numerals carry the eye, text becomes caption. */
.promise-strip--horizontal {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-lg);
    padding: var(--space-xl) var(--space-lg);
    max-width: var(--width-grid, 1100px);
    margin: 0 auto;
}
.promise-strip__items {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-xl);
    width: 100%;
    list-style: none;
    margin: 0;
    padding: 0;
}
.promise-strip__item {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-md);
    align-items: baseline;
}
.promise-strip__num {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 500;
    font-size: 3.25rem;
    line-height: 0.85;
    /* Use the deep terracotta at full opacity so the numerals clear
       WCAG AA against parchment-base. The previous --color-primary at
       0.75 opacity rendered ~3.0:1, below the 4.5:1 threshold. The
       elements are aria-hidden but axe checks all visible text. */
    color: var(--color-primary-deep);
    opacity: 1;
}
.promise-strip__body {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
}
.promise-strip__short {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.15rem;
    line-height: 1.2;
    color: var(--color-text);
}
.promise-strip__hint {
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--color-text-secondary);
}
.promise-strip__more {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1rem;
    /* Deep terracotta clears WCAG AA against parchment; --color-primary
       at this size hits ~4.4:1 (just under 4.5:1 AA threshold). */
    color: var(--color-primary-deep);
    text-decoration: none;
    padding: 0.4rem 0.8rem;
    border-radius: var(--radius-sm);
    transition: color var(--duration-normal) var(--ease-out);
}
.promise-strip__more:hover {
    color: var(--color-primary-hover);
}
.promise-strip__more::after {
    content: " →";
    display: inline-block;
    transition: transform var(--duration-normal) var(--ease-out);
}
.promise-strip__more:hover::after {
    transform: translateX(3px);
}

@media (max-width: 720px) {
    .promise-strip__items {
        grid-template-columns: 1fr;
        gap: var(--space-lg);
    }
    .promise-strip__num {
        font-size: 2.25rem;
    }
}

/* ---------- Inline confirm (replaces native confirm() dialogs) ---------- */

.inline-confirm {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: 0.25rem 0.5rem 0.25rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface-alt);
    box-shadow: var(--shadow-sm);
    font-size: var(--text-sm);
}

.inline-confirm__prompt {
    color: var(--color-text);
    font-weight: 500;
    line-height: 1.3;
    max-width: 22ch;
}

.inline-confirm__yes,
.inline-confirm__no {
    display: inline-flex;
    align-items: center;
    height: 1.85rem;
    padding: 0 0.65rem;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    font: inherit;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-out),
        color var(--duration-fast) var(--ease-out),
        border-color var(--duration-fast) var(--ease-out);
}

.inline-confirm__yes {
    background: var(--color-error, #b65b37);
    color: var(--color-text-on-primary);
}

.inline-confirm__yes:hover {
    background: var(--color-error-hover, #a8412f);
}

.inline-confirm__no {
    background: var(--color-surface);
    color: var(--color-text-secondary);
    border-color: var(--color-border);
}

.inline-confirm__no:hover {
    color: var(--color-text);
    border-color: var(--color-text-secondary);
}

.inline-confirm__yes:focus-visible,
.inline-confirm__no:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

@media (max-width: 540px) {
    .inline-confirm {
        flex-wrap: wrap;
        width: 100%;
    }
    .inline-confirm__prompt {
        flex: 1 1 100%;
        max-width: none;
        margin-bottom: var(--space-xs);
    }
}

/* Shared brand confirm dialog. One visual idiom for every native
   <dialog method="dialog"> sheet on owner surfaces: the moderation
   bulk-action confirm (submissions.html), the export-row delete
   (exports/status.html), and any future destructive or high-cost
   action that needs focus trap + Esc-close + ::backdrop without a
   custom modal stack. Tokens match the deck reject sheet in
   _submission_deck.html. WCAG 2.4.3 focus order is handled at the
   call site by reordering submit buttons for non-destructive flows
   so Enter defaults to the safe action. */
.mod-confirm-dialog {
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-xl);
    max-width: 480px;
    width: calc(100% - 2rem);
    background: var(--color-bg-card);
    color: var(--color-text);
    box-shadow: var(--shadow-lg);
}
.mod-confirm-dialog::backdrop {
    background: rgba(26, 22, 20, 0.45);
}
.mod-confirm-dialog__form {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
}
.mod-confirm-dialog__title {
    font-family: var(--font-display);
    font-size: 1.5rem;
    line-height: 1.2;
    margin: 0;
    color: var(--color-text);
}
.mod-confirm-dialog__body {
    font-family: var(--font-body);
    font-size: 1rem;
    line-height: 1.5;
    color: var(--color-text-muted);
    margin: 0;
}
.mod-confirm-dialog__actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--space-md);
    margin-top: var(--space-sm);
}

/* ---------- Accessibility Utilities ---------- */
/* Canonical screen-reader-only utility. Referenced by class="sr-only"
   across many templates; previously defined ONLY in the unbundled
   static/css/pricing.css, so it rendered unstyled site-wide. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ── Reactions + replies (submission permalink) ──── */

.reaction-bar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    margin-top: var(--space-sm);
}

.reaction-form {
    display: inline;
    margin: 0;
}

.reaction-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    min-height: 44px;
    padding: 0 var(--space-sm);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-card);
    color: var(--color-text);
    cursor: pointer;
    font-size: 1rem;
}

.reaction-btn--active {
    border-color: var(--color-primary);
    background: var(--color-bg-warm);
}

.reaction-btn--static {
    cursor: default;
}

.reaction-btn:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    box-shadow: var(--shadow-glow);
}

.reaction-count {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
}

.replies {
    max-width: 640px;
    margin: var(--space-lg) auto 0;
}

.reply {
    padding: var(--space-sm) 0;
    border-top: 1px solid var(--color-border-light);
}

.reply--child {
    margin-left: var(--space-lg);
}

.reply-author {
    font-weight: 600;
}

.reply-meta {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.reply-form {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    margin-top: var(--space-md);
}

.reply-form textarea {
    width: 100%;
    padding: var(--space-sm);
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-size: 1rem;
    resize: vertical;
}

.reply-form textarea:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-border-focus);
    box-shadow: var(--shadow-glow);
}

/* ── Quick-book templates (48-hour instant book) ──── */

.quick-grid {
    display: grid;
    gap: var(--space-md);
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    margin-bottom: var(--space-lg);
}

.quick-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    padding: var(--space-md);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-card);
}

.quick-card h2 {
    margin: 0;
}
/* ---------- Auth Pages Layout ---------- */
.auth-page {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: calc(100vh - 200px);
    padding: var(--space-xl) var(--space-lg) var(--space-2xl);
    border-bottom: 1px solid var(--color-border-light);
}

.auth-card {
    width: 100%;
    max-width: 440px;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-xl);
    padding: var(--space-2xl);
    box-shadow: var(--shadow-lg);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
}

.auth-card h1 {
    text-align: center;
    margin-bottom: var(--space-xs);
    font-size: 2rem;
}

.auth-subtitle {
    text-align: center;
    color: var(--color-text-muted);
    font-size: 0.95rem;
    margin-bottom: var(--space-xl);
    max-width: none;
}

.auth-footer {
    text-align: center;
    margin-top: var(--space-lg);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border-light);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.auth-footer a {
    font-weight: 500;
}

/* ---------- Scroll Progress ---------- */
.scroll-progress {
    position: fixed;
    top: 0;
    left: 0;
    height: 2px;
    background: var(--color-primary);
    width: 100%;
    z-index: 100;
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 50ms linear;
    will-change: transform;
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .scroll-progress { display: none; }
}

/* ---------- Home / Hero ---------- */
.hero {
    text-align: center;
    padding: clamp(var(--space-2xl), 8vw, var(--space-3xl)) var(--space-lg) var(--space-2xl);
    /* Width tokens: --width-narrative (880) for read-y bands,
       --width-grid (1100) for 3-card row bands. See tokens.css. */
    max-width: var(--width-narrative, 880px);
    margin: 0 auto;
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
    background: radial-gradient(
        ellipse at 50% 30%,
        var(--color-primary-glow) 0%,
        transparent 60%
    );
}

.hero h1 {
    font-size: clamp(2.5rem, 6vw, 4rem);
    line-height: 1.1;
    margin-bottom: var(--space-lg);
    font-weight: 700;
}

.hero h1 em {
    font-style: italic;
    color: var(--color-primary-text);
}

.hero-description {
    font-size: clamp(1.05rem, 2.5vw, 1.2rem);
    color: var(--color-text-secondary);
    max-width: 55ch;
    margin: 0 auto var(--space-xl);
    line-height: 1.7;
}

.hero-actions {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-md);
    flex-wrap: wrap;
}

/* Below-fold sections: skip rendering until near viewport */
.how-it-works-teaser,
.occasion-section,
.channels-strip,
.social-proof,
.pricing-teaser,
.cta-banner {
    content-visibility: auto;
    contain-intrinsic-size: auto 400px;
}

/* ---------- Scroll Reveal ---------- */
/* No `will-change` hint: this animation runs ONCE per page-load on
   intersection and then the element stays static. Holding a GPU layer
   for the whole page lifetime to save 600ms of compositing isn't worth
   it. The browser auto-promotes during the transition just fine. */
.reveal {
    opacity: 0;
    transform: translateY(20px);
    transition: opacity var(--duration-slow) var(--ease-out),
                transform var(--duration-slow) var(--ease-out);
}

.reveal.is-visible {
    opacity: 1;
    transform: translateY(0);
}

.reveal-stagger > .reveal {
    opacity: 0;
    transform: translateY(16px);
}

.reveal-stagger.is-visible > .reveal {
    opacity: 1;
    transform: translateY(0);
}

/* Stagger delays for child elements */
.reveal-stagger.is-visible > :nth-child(1) { transition-delay: 0ms; }
.reveal-stagger.is-visible > :nth-child(2) { transition-delay: 80ms; }
.reveal-stagger.is-visible > :nth-child(3) { transition-delay: 160ms; }
.reveal-stagger.is-visible > :nth-child(4) { transition-delay: 240ms; }
.reveal-stagger.is-visible > :nth-child(5) { transition-delay: 320ms; }
.reveal-stagger.is-visible > :nth-child(6) { transition-delay: 400ms; }

@media (prefers-reduced-motion: reduce) {
    .reveal,
    .reveal-stagger > .reveal {
        opacity: 1;
        transform: none;
        transition: none;
        will-change: auto;
    }
}

/* ---------- Decorative Divider ---------- */
.divider {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin: var(--space-xl) 0;
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

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

/* ---------- Stats Row (compact clickable) ---------- */
/* Stats summary rules live in main.css */

/* ---------- Sharing Page ---------- */
.sharing-section {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-xl);
    margin-bottom: var(--space-lg);
}

.sharing-section h2 {
    font-size: 1.1rem;
    margin-bottom: var(--space-md);
    color: var(--color-text-secondary);
}

.qr-preview {
    width: clamp(150px, 50vw, 200px);
    height: auto;
    aspect-ratio: 1;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-md);
    margin-bottom: var(--space-lg);
    box-shadow: var(--shadow-sm);
}

.qr-preview svg {
    width: 100%;
    height: 100%;
}

.qr-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
}

/* ---------- Tables (Admin) ---------- */
.admin-nav {
    display: flex;
    gap: var(--space-sm);
    margin-bottom: var(--space-xl);
    padding-bottom: var(--space-md);
    border-bottom: 1px solid var(--color-border-light);
}

.admin-nav a {
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-secondary);
    padding: var(--space-xs) var(--space-md);
    border-radius: var(--radius-sm);
    transition: background-color var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.admin-nav a:hover,
.admin-nav a.active {
    color: var(--color-primary-text);
    background: var(--color-primary-glow);
}

.table-wrapper {
    overflow-x: auto;
    border-radius: var(--radius-lg);
    border: 1px solid var(--color-border-light);
    background: var(--color-bg-card);
}

.table-wrapper table {
    width: 100%;
    border-collapse: collapse;
}

.table-wrapper thead {
    background: var(--color-bg-warm);
}

.table-wrapper th {
    font-family: var(--font-body);
    font-size: 0.78rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
    padding: var(--space-md) var(--space-lg);
    text-align: left;
    border-bottom: 1px solid var(--color-border);
}

.table-wrapper td {
    font-size: var(--text-sm);
    color: var(--color-text);
    padding: var(--space-md) var(--space-lg);
    border-bottom: 1px solid var(--color-border-light);
}

.table-wrapper tbody tr:last-child td {
    border-bottom: none;
}

.table-wrapper tbody tr:hover {
    background: var(--color-bg-warm);
}

.admin-search {
    display: flex;
    gap: var(--space-sm);
    margin-bottom: var(--space-lg);
    max-width: 400px;
}

.admin-search input[type="text"] {
    flex: 1;
    padding: 0.6rem 0.9rem;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.admin-search input[type="text"]:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-border-focus);
    box-shadow: var(--shadow-glow);
}

/* ---------- Torn Page (404, 400) ---------- */

.torn-page {
    position: relative;
    width: 160px;
    height: 200px;
    margin: 0 auto;
}

.torn-page-inner {
    position: relative;
    width: 100%;
    height: 100%;
    background: var(--color-bg-card);
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    box-shadow: var(--shadow-md);
    overflow: hidden;
    animation: pageDrift 4s ease-in-out infinite;
}

.torn-page-number {
    display: block;
    font-family: var(--font-display);
    font-size: 3.2rem;
    font-weight: 700;
    color: var(--color-primary-text);
    text-align: center;
    padding-top: var(--space-xl);
    opacity: 0.7;
    letter-spacing: 0.05em;
}

.torn-edge {
    position: absolute;
    bottom: 0;
    left: -2px;
    right: -2px;
    height: 30px;
    background: var(--color-bg-card);
    clip-path: polygon(
        0% 0%, 5% 60%, 12% 20%, 20% 70%, 28% 30%,
        35% 80%, 42% 25%, 50% 65%, 58% 15%, 65% 75%,
        72% 35%, 80% 85%, 88% 20%, 95% 55%, 100% 0%,
        100% 100%, 0% 100%
    );
    border-bottom: none;
}

.torn-fragment {
    position: absolute;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    opacity: 0;
    animation: fragmentDrift var(--duration-slow) var(--ease-out) forwards;
}

.torn-fragment-1 {
    width: 24px;
    height: 18px;
    bottom: -20px;
    left: 20px;
    clip-path: polygon(10% 0%, 90% 20%, 70% 100%, 0% 80%);
    transform: rotate(-15deg);
    animation-delay: 0.3s;
}

.torn-fragment-2 {
    width: 18px;
    height: 14px;
    bottom: -25px;
    right: 30px;
    clip-path: polygon(0% 10%, 100% 0%, 80% 100%, 20% 90%);
    transform: rotate(12deg);
    animation-delay: 0.5s;
}

.torn-fragment-3 {
    width: 12px;
    height: 10px;
    bottom: -15px;
    left: 70px;
    clip-path: polygon(20% 0%, 100% 30%, 60% 100%, 0% 60%);
    transform: rotate(-8deg);
    animation-delay: 0.7s;
}

@keyframes pageDrift {
    0%, 100% { transform: rotate(-1.5deg); }
    50% { transform: rotate(1deg); }
}

@keyframes fragmentDrift {
    from { opacity: 0; transform: translateY(-8px) rotate(0deg); }
    to { opacity: 0.6; transform: translateY(0) rotate(5deg); }
}

/* ---------- Sealed Book (403) ---------- */

.sealed-book {
    position: relative;
    margin: 0 auto;
    perspective: 600px;
}

.sealed-book-cover {
    position: relative;
    width: 130px;
    height: 170px;
    margin: 0 auto;
    background: linear-gradient(145deg, var(--color-leather) 0%, var(--color-leather-dark) 100%);
    border-radius: 4px var(--radius-md) var(--radius-md) 4px;
    box-shadow:
        -4px 0 0 var(--color-leather-spine),
        -6px 1px 0 var(--color-leather-dark),
        var(--shadow-lg);
    animation: bookBreathe 3s ease-in-out infinite;
}

.sealed-book-cover::before {
    content: '';
    position: absolute;
    top: 12px;
    bottom: 12px;
    left: 12px;
    right: 12px;
    border: 1.5px solid rgba(212, 165, 116, 0.3);
    border-radius: 2px;
}

.sealed-book-cover::after {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 12px;
    background: linear-gradient(90deg, rgba(26, 22, 20, 0.15), transparent);
    border-radius: 4px 0 0 4px;
}

.sealed-book-clasp {
    position: absolute;
    right: -8px;
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 40px;
    background: linear-gradient(135deg, var(--color-primary-light), var(--color-clasp));
    border-radius: 0 6px 6px 0;
    box-shadow: 1px 1px 3px rgba(26, 22, 20, 0.2);
}

.sealed-book-keyhole {
    position: absolute;
    right: -4px;
    top: 50%;
    transform: translateY(-50%);
    width: 6px;
    height: 6px;
    background: var(--color-leather-dark);
    border-radius: 50%;
    box-shadow: inset 0 1px 2px rgba(26, 22, 20, 0.4);
}

.sealed-book-keyhole::after {
    content: '';
    position: absolute;
    top: 5px;
    left: 50%;
    transform: translateX(-50%);
    width: 2px;
    height: 6px;
    background: var(--color-leather-dark);
    border-radius: 0 0 1px 1px;
}

@keyframes bookBreathe {
    0%, 100% { transform: rotateY(0deg) scale(1); }
    50% { transform: rotateY(-3deg) scale(1.01); }
}

/* ==========================================================================
   Legal Pages
   ========================================================================== */

.legal-page {
    max-width: 720px;
    margin: 0 auto;
    padding: var(--space-xl) var(--space-lg) var(--space-3xl);
    line-height: 1.7;
}

.legal-page h1 {
    font-family: var(--font-display);
    font-size: clamp(1.75rem, 4vw, 2.5rem);
    font-weight: 600;
    margin-bottom: var(--space-xs);
}

.legal-updated {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    margin-bottom: var(--space-xl);
}

.legal-page h2 {
    font-family: var(--font-display);
    font-size: 1.3rem;
    font-weight: 600;
    margin-top: var(--space-xl);
    margin-bottom: var(--space-sm);
    padding-bottom: var(--space-xs);
    border-bottom: 1px solid var(--color-border-light);
}

.legal-page h3 {
    font-size: 1.05rem;
    font-weight: 600;
    margin-top: var(--space-lg);
    margin-bottom: var(--space-xs);
}

.legal-page ul {
    padding-left: var(--space-lg);
    margin-bottom: var(--space-md);
}

.legal-page li {
    margin-bottom: var(--space-xs);
}

.legal-table {
    width: 100%;
    border-collapse: collapse;
    margin: var(--space-md) 0;
    font-size: var(--text-sm);
}

.legal-table th,
.legal-table td {
    text-align: left;
    padding: var(--space-sm) var(--space-md);
    border-bottom: 1px solid var(--color-border-light);
}

.legal-table th {
    font-weight: 600;
    background: var(--color-surface);
}

/* ── Pricing ─────────────────────────────────────────────────────── */

.pricing-subtitle {
    max-width: 480px;
}

.pricing-book-selector {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-md);
    margin-bottom: var(--space-xl);
    flex-wrap: wrap;
}

.pricing-book-selector label {
    font-weight: 500;
    color: var(--color-text-secondary);
}

.pricing-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: var(--space-lg);
    max-width: 960px;
    margin: 0 auto;
}

/* Legacy .pricing-card* rules removed (H-2). The unified pricing page
   now renders as .plan-card / .plan-card__* via apps/billing/templates/
   billing/pricing.html; definitions live in static/css/main.css. No
   live template references .pricing-card anymore. */

.pricing-no-books {
    text-align: center;
    color: var(--color-text-secondary);
    margin-top: var(--space-xl);
    font-size: 0.95rem;
}

.pricing-no-books a {
    color: var(--color-primary-text);
    font-weight: 500;
}

/* ── Plan Picker (Book Creation) ─────────────────────────────────── */

.plan-picker {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--space-md);
    margin-top: var(--space-sm);
}

.plan-option {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-md) var(--space-lg);
    border: 2px solid var(--color-border);
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out),
                background-color var(--duration-fast) var(--ease-out);
    background: var(--color-bg-card);
}

.plan-option:hover {
    border-color: var(--color-primary-light);
}

.plan-option:has(input:checked) {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 1px var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 4%, var(--color-bg-card));
}

/* Focus surface — hidden radio's focus ring relayed to the visible card */
.plan-option:has(input[type="radio"]:focus-visible) {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
}

.plan-option input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.plan-option__name {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--color-text);
}

.plan-option__slots {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
}

/* Renewal wording for a single-option paid plan. Its billing-option fieldset
   is display:none (.billing-option-picker--single), so the per-option terms
   set in there never reach the screen for the shape production actually runs.
   Same size and role as __slots, on the visible card. */
.plan-option__terms {
    display: block;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.plan-option__slots--none {
    color: var(--color-text-muted);
}

.plan-option__slots--none a {
    color: var(--color-primary-text);
    font-weight: 500;
}

/* ── Billing Option Picker (Create Book) ─────────────────────────── */

.billing-option-picker {
    grid-column: 1 / -1;
    margin: calc(var(--space-xs) * -1) 0 0;
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--color-bg-card) 60%, transparent);
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

.billing-option-picker[hidden] {
    display: none;
}

/* Single-option paid plans — the sole option is shown on the plan card
   itself; this fieldset only holds the hidden-from-view radio whose
   value submits when the plan is selected. Never visible. */
.billing-option-picker--single {
    display: none;
}

.billing-option-picker__option {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-xs) var(--space-sm);
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: 0.92rem;
    color: var(--color-text-secondary);
    transition: background-color var(--duration-fast) var(--ease-out);
}

.billing-option-picker__option:hover {
    background: color-mix(in srgb, var(--color-primary) 6%, transparent);
}

.billing-option-picker__option:has(input:checked) {
    color: var(--color-text);
    font-weight: 500;
}

.billing-option-picker__option input[type="radio"] {
    accent-color: var(--color-primary);
}

/* The renewal mode, said plainly beside each option. The picker used to show
   only a label and a price, so "renews automatically" versus "one-time" was
   carried solely by a data attribute the buyer could not see. That matters on
   the redisplay after checkout withholds a terms mismatch: the message names
   the current terms, and the form has to show them too. */
.billing-option-picker__terms {
    display: block;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

/* ── Plan Badge (Book Detail) ────────────────────────────────────── */

.plan-badge {
    display: inline-block;
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
    color: var(--color-primary-text);
    border: 1px solid color-mix(in srgb, var(--color-primary) 25%, transparent);
    border-radius: var(--radius-xl);
    padding: var(--space-xs) var(--space-md);
    font-size: var(--text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* ── Previously-Plan Indicator ──────────────────────────────────── */

.previously-plan-indicator {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

/* ── Upgrade Hint (free book → see plans) ───────────────────────── */
/* Quiet single-line hint shown to free-book owners. Centered to match
   the page-header rhythm above (title + plan badge + description),
   warm voice, link-styled CTA instead of a chunky button card. */

.upgrade-hint {
    text-align: center;
    margin: var(--space-md) auto var(--space-lg);
    max-width: 60ch;
    color: var(--color-text-secondary);
    font-size: 0.92rem;
    line-height: 1.6;
}

.upgrade-hint a {
    color: var(--color-primary-text);
    font-weight: 500;
    text-decoration: none;
    margin-left: 0.25em;
    white-space: nowrap;
}

.upgrade-hint a:hover,
.upgrade-hint a:focus-visible {
    text-decoration: underline;
}

.upgrade-hint a:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* ── Quota Summary ───────────────────────────────────────────────── */

.quota-summary {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.quota-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--color-border-light);
    font-size: 0.92rem;
}

.quota-row:last-child {
    border-bottom: none;
}

.quota-row__plan {
    font-weight: 500;
    color: var(--color-text);
}

.quota-row__count {
    color: var(--color-text-secondary);
}

/* ── Package Cards (Pricing Page) ────────────────────────────────── */

.package-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: var(--space-lg);
    margin-bottom: var(--space-2xl);
}

.package-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-xl);
    box-shadow: var(--shadow-sm);
}

.package-card__name {
    font-family: var(--font-display);
    font-size: 1.3rem;
    font-weight: 600;
    margin: 0 0 var(--space-sm);
}

.package-card__price {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--color-primary-text);
    margin-bottom: var(--space-md);
}

.package-card__price span {
    font-size: var(--text-sm);
    font-weight: 400;
    color: var(--color-text-muted);
}

.package-card__allotments {
    list-style: none;
    padding: 0;
    margin: 0 0 var(--space-lg);
}

.package-card__allotments li {
    padding: var(--space-xs) 0;
    font-size: 0.92rem;
    color: var(--color-text-secondary);
}

.package-card__allotments li::before {
    content: "\2713 ";
    color: var(--color-text-on-bg-success);
    font-weight: 600;
}

/* ── How It Works Teaser (Homepage) ──────────────────────────────── */

.how-it-works-teaser {
    background: var(--color-bg-warm);
    padding: var(--space-3xl) var(--space-lg);
}

.how-it-works-teaser__inner {
    max-width: var(--width-narrative, 880px);
    margin: 0 auto;
}

.how-it-works-teaser__header {
    margin-bottom: var(--space-2xl);
}

.how-it-works-teaser h2 {
    font-family: var(--font-display);
    font-size: clamp(1.8rem, 4.5vw, 2.4rem);
    text-align: left;
    line-height: 1.2;
}

.how-it-works-teaser__steps {
    display: flex;
    flex-direction: column;
    gap: var(--space-lg);
    margin-bottom: var(--space-xl);
    text-align: left;
    max-width: 600px;
    margin-left: auto;
    margin-right: auto;
}

.how-it-works-teaser__step {
    display: flex;
    align-items: flex-start;
    gap: var(--space-lg);
    text-align: left;
}

.how-it-works-teaser__number {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--color-primary);
    color: var(--color-text-on-primary);
    font-family: var(--font-display);
    font-size: 1.2rem;
    font-weight: 700;
}

.how-it-works-teaser__step h3 {
    font-family: var(--font-display);
    font-size: 1.3rem;
    margin-bottom: var(--space-xs);
    font-weight: 700;
}

.how-it-works-teaser__step p {
    font-size: 0.95rem;
    color: var(--color-text-secondary);
    line-height: 1.6;
}

.how-it-works-teaser > .btn,
.how-it-works-teaser__inner > .btn {
    display: inline-flex;
}

/* ── Social Proof (Homepage) ────────────────────────────────────── */

.social-proof {
    padding: var(--space-2xl) var(--space-lg);
    max-width: 600px;
    margin: 0 auto;
}

.social-proof__quote {
    text-align: center;
    border: none;
    margin: 0;
    padding: var(--space-xl) var(--space-xl);
    background: var(--color-bg-warm);
    border-radius: var(--radius-lg);
}

.social-proof__quote p {
    font-family: var(--font-display);
    font-size: clamp(1.1rem, 3vw, 1.4rem);
    font-weight: 500;
    line-height: 1.6;
    color: var(--color-text-secondary);
    max-width: none;
}

.social-proof__stat {
    font-weight: 700;
    color: var(--color-primary-text);
}

.social-proof-fallback {
    padding: var(--space-xl) var(--space-lg);
    max-width: 500px;
    margin: 0 auto;
    text-align: center;
}

.social-proof-fallback__text {
    font-family: var(--font-display);
    font-size: 1.2rem;
    font-style: italic;
    color: var(--color-text-muted);
    line-height: 1.5;
}

/* ── Pricing Teaser (Homepage) ───────────────────────────────────── */

.pricing-teaser {
    text-align: center;
    padding: var(--space-3xl) var(--space-lg);
    max-width: var(--width-grid, 1100px);
    margin: 0 auto;
}

.pricing-teaser h2 {
    font-family: var(--font-display);
    font-size: clamp(1.6rem, 4vw, 2rem);
    margin-bottom: var(--space-xl);
}

/* Global p { max-width: 60ch } pins the box left; restore center
   alignment so the lede tracks with the heading and plan cards. */
.pricing-teaser > p {
    margin-inline: auto;
    margin-bottom: var(--space-xl);
}

.pricing-teaser__plans {
    display: flex;
    justify-content: center;
    gap: var(--space-lg);
    margin-bottom: var(--space-xl);
    flex-wrap: wrap;
}

.pricing-teaser__plan {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-lg);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    background: var(--color-bg-card);
    flex: 1;
    max-width: 240px;
    position: relative;
    transition: box-shadow var(--duration-normal) var(--ease-out);
}

.pricing-teaser__plan:hover {
    box-shadow: var(--shadow-md);
}

.pricing-teaser__plan--recommended {
    border-color: var(--color-primary-light);
    box-shadow: var(--shadow-sm);
}

.pricing-teaser__name {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 600;
}

.pricing-teaser__price {
    font-family: var(--font-display);
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--color-text);
}

.pricing-teaser__period {
    font-size: var(--text-xs);
    font-weight: 400;
    color: var(--color-text-muted);
}

.pricing-teaser__highlights {
    list-style: none;
    padding: 0;
    margin: var(--space-sm) 0 0;
    text-align: left;
    width: 100%;
}

.pricing-teaser__highlights li {
    font-size: var(--text-xs);
    color: var(--color-text-secondary);
    padding: var(--space-xs) 0;
    line-height: 1.4;
}

.pricing-teaser__compare {
    display: inline-block;
    margin-top: var(--space-md);
    font-size: 0.95rem;
    color: var(--color-text-muted);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}

.pricing-teaser__compare:hover,
.pricing-teaser__compare:focus-visible {
    color: var(--color-primary-text);
    border-bottom-color: currentColor;
}

@media (max-width: 640px) {
    .pricing-teaser__plans {
        flex-direction: column;
        align-items: center;
    }

    .pricing-teaser__plan {
        max-width: 300px;
        width: 100%;
    }
}

/* ── How-it-works teaser: arc-as-prose, not 3-up SaaS steps ──────── */
/* Moved from apps/accounts/templates/accounts/home.html <style>
   (2026-08 critique-color-fixes Task 4). */

.how-it-works-arc {
    max-width: 60ch;
    margin: var(--space-2xl) auto;
    padding: 0 var(--space-lg);
    text-align: center;
}
.how-it-works-arc__line {
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 3.2vw, 1.95rem);
    font-weight: 500;
    line-height: 1.35;
    letter-spacing: -0.005em;
    color: var(--color-text);
    margin: 0 0 var(--space-md);
}
.how-it-works-arc__line em {
    font-style: italic;
    color: var(--color-primary-deep);
}
.how-it-works-arc__link {
    font-family: var(--font-body);
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--color-primary-deep);
    text-decoration: none;
    border-bottom: 1px solid color-mix(in srgb, var(--color-primary) 35%, transparent);
    padding-bottom: 1px;
    transition: border-color var(--duration-fast) var(--ease-out);
}
.how-it-works-arc__link:hover {
    border-bottom-color: var(--color-primary);
}
.how-it-works-arc__link:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 4px;
    border-radius: 2px;
}

/* ── Channels-as-prose: editorial paragraph, no tile grid ────────── */

.channels-prose {
    max-width: 62ch;
    margin: var(--space-2xl) auto;
    padding: var(--space-xl) var(--space-lg);
    text-align: left;
}
.channels-prose__lead {
    font-family: var(--font-display);
    font-size: clamp(1.4rem, 3.2vw, 1.9rem);
    font-weight: 500;
    line-height: 1.3;
    letter-spacing: -0.005em;
    color: var(--color-text);
    margin: 0 0 var(--space-md);
}
.channels-prose__body {
    font-family: var(--font-body);
    font-size: 1.05rem;
    line-height: 1.7;
    color: var(--color-text-secondary);
    margin: 0;
}
.channels-prose__channel {
    font-style: normal;
    font-weight: 600;
    color: var(--color-text);
    white-space: nowrap;
}
.channels-prose__channel svg {
    width: 18px;
    height: 18px;
    vertical-align: -3px;
    margin-right: 0.18em;
    color: var(--color-primary-deep);
}
.channels-prose__coda {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.1rem;
    color: var(--color-text-secondary);
    margin: var(--space-md) 0 0;
    line-height: 1.5;
}

/* ── Pricing teaser: editorial prose, no card grid ───────────────── */

.pricing-teaser--prose {
    max-width: 60ch;
    margin: var(--space-3xl) auto;
    padding: 0 var(--space-lg);
    text-align: center;
}
.pricing-teaser__headline {
    font-family: var(--font-display);
    font-size: clamp(1.6rem, 3.5vw, 2.2rem);
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.2;
    color: var(--color-text);
    margin: 0 0 var(--space-md);
}
.pricing-teaser__prose {
    font-family: var(--font-body);
    font-size: 1.05rem;
    line-height: 1.7;
    color: var(--color-text);
    margin: 0 0 var(--space-lg);
}
.pricing-teaser__prose strong {
    font-weight: 700;
    color: var(--color-primary-deep);
}
.pricing-teaser__link {
    font-family: var(--font-body);
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--color-primary-deep);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    transition: color var(--duration-fast) var(--ease-out);
}
.pricing-teaser__link:hover {
    color: var(--color-primary-text-hover);
}
.pricing-teaser__link:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 4px;
    border-radius: 2px;
}

/* ── CTA Banner ──────────────────────────────────────────────────── */

.cta-banner {
    text-align: center;
    padding: var(--space-3xl) var(--space-lg);
    background: var(--color-bg-warm);
    margin-bottom: 0;
}

.cta-banner h2 {
    font-family: var(--font-display);
    font-size: clamp(1.8rem, 4.5vw, 2.4rem);
    margin-bottom: var(--space-md);
    line-height: 1.25;
    max-width: 600px;
    margin-inline: auto;
}

.cta-banner p {
    color: var(--color-text-secondary);
    margin-bottom: var(--space-xl);
    margin-inline: auto;
}

/* ── How It Works Page ───────────────────────────────────────────── */

/* ── How It Works (long-scroll narrative) ──────────────────────────
   Each step has its own visual world. Step 5 is the payoff and
   gets the strongest treatment. */

.hiw {
    max-width: var(--width-narrative, 880px);
    margin: 0 auto;
    padding: var(--space-2xl) var(--space-lg) var(--space-3xl);
}

/* Lede */
.hiw-lede {
    margin: var(--space-xl) 0 var(--space-3xl);
}

.hiw-lede__eyebrow {
    font-size: 0.78rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin: 0 0 var(--space-md);
}

.hiw-lede__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(2.4rem, 6vw, 3.8rem);
    line-height: 1.05;
    color: var(--color-text);
    margin: 0 0 var(--space-md);
    max-width: 18ch;
}

.hiw-lede__title em {
    font-style: italic;
    font-weight: 500;
    color: var(--color-primary-text);
}

.hiw-lede__sub {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.1rem;
    color: var(--color-text-secondary);
    margin: 0;
}

/* Generic step shell — each --modifier overrides what it needs. */
.hiw-step {
    margin: var(--space-3xl) 0;
}

.hiw-step__head {
    display: flex;
    align-items: baseline;
    gap: var(--space-md);
    margin-bottom: var(--space-lg);
}

.hiw-step__roman {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.2rem;
    /* Deep terracotta at full opacity clears WCAG AA against parchment.
       Element is aria-hidden so this is decoration, but axe checks all
       visible text and warm-cream parchment + terracotta at low opacity
       hits ~3:1 (below 4.5:1 AA). */
    color: var(--color-primary-deep);
    flex-shrink: 0;
    min-width: 1.8em;
}

.hiw-step__head h2 {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(1.6rem, 3.5vw, 2.2rem);
    line-height: 1.2;
    color: var(--color-text);
    margin: 0;
}

.hiw-step__body {
    max-width: 56ch;
}

.hiw-step__body p {
    font-family: var(--font-display);
    font-size: 1.1rem;
    line-height: 1.7;
    color: var(--color-text);
    margin-bottom: var(--space-md);
}

/* Step 1: just heading + copy. No card. */
/* (Inherits the defaults above.) */

/* Step 2: paired share demo (SMS bubble + printed card) */
.hiw-share {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-xl);
    margin: var(--space-xl) 0 0;
}

@media (min-width: 720px) {
    .hiw-share {
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: end;
        gap: var(--space-2xl);
    }
}

.hiw-share__sms {
    max-width: 360px;
}

.hiw-share__bubble {
    background: var(--color-primary);
    color: var(--color-text-on-primary);
    padding: var(--space-md) var(--space-lg);
    border-radius: var(--radius-xl) var(--radius-xl) var(--radius-xl) var(--radius-sm);
    line-height: 1.4;
    font-size: 0.95rem;
    box-shadow: 0 2px 8px color-mix(in srgb, var(--color-primary) 22%, transparent);
}

.hiw-share__url {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15em;
}

.hiw-share__bubble-meta {
    margin: var(--space-xs) 0 0 var(--space-sm);
    font-size: 0.72rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-text-muted);
}

.hiw-share__card {
    background: var(--color-bg-card);
    padding: var(--space-lg);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    width: 200px;
    text-align: center;
    box-shadow: var(--shadow-md);
}

.hiw-share__card-overline {
    font-size: 0.7rem;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin: 0 0 var(--space-xs);
}

.hiw-share__card-title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.15rem;
    line-height: 1.1;
    color: var(--color-text);
    margin: 0 0 var(--space-md);
}

.hiw-share__qr {
    width: 120px;
    height: 120px;
    margin: 0 auto var(--space-md);
    color: var(--color-text);
}

.hiw-share__qr svg {
    width: 100%;
    height: 100%;
    display: block;
    shape-rendering: crispEdges;
}

.hiw-share__card-code {
    font-family: var(--font-mono);
    font-size: 0.78rem;
    letter-spacing: 0.08em;
    color: var(--color-text-muted);
    margin: 0;
}

/* Step 3: example replies */
.hiw-replies {
    list-style: none;
    margin: var(--space-xl) 0 0 0;
    padding: 0;
    max-width: 60ch;
}

.hiw-replies__item {
    padding: var(--space-lg) 0;
    border-bottom: 1px solid var(--color-border-light);
}

.hiw-replies__item:last-child {
    border-bottom: none;
}

.hiw-replies__channel {
    font-size: 0.72rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin: 0 0 var(--space-xs);
}

.hiw-replies__text {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.2rem;
    line-height: 1.55;
    color: var(--color-text);
    margin: 0;
    padding: 0;
    border: none;
    quotes: '"' '"';
}

.hiw-replies__text::before {
    content: open-quote;
    margin-right: 0.05em;
    color: var(--color-primary-deep);
    opacity: 0.85;
}

.hiw-replies__text::after {
    content: close-quote;
    margin-left: 0.05em;
    color: var(--color-primary-deep);
    opacity: 0.85;
}

/* Step 4: moderation vignette */
.hiw-mod {
    margin: var(--space-xl) 0 0 0;
    max-width: 540px;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    padding: var(--space-sm) 0;
    box-shadow: var(--shadow-md);
}

.hiw-mod__row {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-md) var(--space-lg);
    border-bottom: 1px solid var(--color-border-light);
}

.hiw-mod__row:last-child {
    border-bottom: none;
}

.hiw-mod__handle {
    color: var(--color-text-muted);
    opacity: 0.5;
    font-size: 1.1rem;
    line-height: 1;
    cursor: grab;
}

.hiw-mod__title {
    flex: 1;
    font-size: 0.95rem;
    color: var(--color-text);
}

.hiw-mod__stamp {
    font-size: 0.7rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    padding: 0.25rem 0.7rem;
    border: 1px solid currentColor;
    border-radius: 2px;
    transform: rotate(-2deg);
    flex-shrink: 0;
}

.hiw-mod__stamp--approved {
    /* Use dedicated badge-text tokens — the bare --color-success / --color-warning
       fail WCAG AA contrast against the 8-10% tinted backgrounds. */
    color: var(--color-badge-text-success);
    background: color-mix(in srgb, var(--color-success) 12%, transparent);
    border-color: var(--color-badge-text-success);
}

.hiw-mod__stamp--pending {
    color: var(--color-badge-text-warning);
    background: color-mix(in srgb, var(--color-warning) 14%, transparent);
    border-color: var(--color-badge-text-warning);
}

/* Step 5: export — the payoff. Full-bleed pull, larger type, faux PDF spread. */
.hiw-step--export {
    margin-top: var(--space-3xl);
    padding-top: var(--space-3xl);
    border-top: 1px solid var(--color-border-light);
}

.hiw-export__title {
    font-size: clamp(2rem, 5vw, 3rem) !important;
    line-height: 1.1 !important;
}

.hiw-export__sub {
    font-size: 1.2rem !important;
    color: var(--color-text-secondary) !important;
}

.hiw-export__spread {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2px;
    margin: var(--space-2xl) 0;
    max-width: 560px;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: 4px;
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}

.hiw-export__page {
    background: var(--color-bg-card);
    padding: var(--space-xl) var(--space-lg);
    min-height: 280px;
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    position: relative;
}

.hiw-export__page--left {
    border-right: 1px solid var(--color-border-light);
}

.hiw-export__page-eyebrow {
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--text-xs);
    color: var(--color-primary-deep);
    opacity: 0.85;
    margin: 0 0 var(--space-xs);
}

.hiw-export__page-title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.4rem;
    color: var(--color-text);
    margin: 0;
}

.hiw-export__rule {
    display: block;
    width: 28%;
    height: 1px;
    background: var(--color-primary);
    opacity: 0.5;
    margin: var(--space-sm) 0;
}

.hiw-export__line {
    display: block;
    width: 100%;
    height: 4px;
    background: var(--color-text-muted);
    opacity: 0.18;
    border-radius: 1px;
}

.hiw-export__line--80 {
    width: 80%;
}

.hiw-export__line--60 {
    width: 60%;
}

.hiw-export__page-folio {
    margin-top: auto;
    text-align: right;
    font-family: var(--font-display);
    font-style: italic;
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.hiw-export__formats {
    list-style: none;
    margin: var(--space-2xl) auto;
    padding: 0;
    max-width: 560px;
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-lg);
}

.hiw-export__formats li {
    padding-left: var(--space-md);
    border-left: 1px solid var(--color-border-light);
}

.hiw-export__format-label {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.05rem;
    color: var(--color-text);
    margin: 0 0 var(--space-xs);
}

.hiw-export__format-detail {
    font-size: 0.95rem;
    line-height: 1.55;
    color: var(--color-text-secondary);
    margin: 0;
}

.hiw-export__code {
    display: block;
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    color: var(--color-text-secondary);
    background: var(--color-bg-warm);
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-sm);
    overflow-x: auto;
}

/* Final CTA */
.hiw-cta {
    margin-top: var(--space-3xl);
    padding: var(--space-3xl) 0 var(--space-xl);
    text-align: center;
    border-top: 1px solid var(--color-border-light);
}

.hiw-cta h2 {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(1.8rem, 4vw, 2.4rem);
    color: var(--color-text);
    margin: 0 0 var(--space-sm);
}

.hiw-cta p {
    color: var(--color-text-secondary);
    margin: 0 0 var(--space-xl);
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.05rem;
}

.page-subtitle {
    color: var(--color-text-secondary);
    font-size: 1.1rem;
    margin-top: var(--space-sm);
}

/* ── Help Center ─────────────────────────────────────────────────── */

.help-index {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: var(--space-lg);
    max-width: var(--width-grid, 1100px);
    margin: 0 auto;
}

.help-category-card h2 {
    font-family: var(--font-display);
    font-size: 1.35rem;
    margin-bottom: var(--space-md);
}

.help-category-card ul {
    list-style: none;
    padding: 0;
    margin: 0;
}

.help-category-card li {
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--color-border-light);
}

.help-category-card li:last-child {
    border-bottom: none;
}

.help-category-card a {
    color: var(--color-primary-text);
    text-decoration: none;
    display: inline-block;
    padding: 2px 0;
}

.help-category-card a:hover {
    text-decoration: underline;
}

.help-category-card a:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 2px;
}

.page-header--help {
    max-width: 900px;
}

.page-header--help .page-header-row {
    display: block;
}

.help-guide-layout {
    display: grid;
    grid-template-columns: 1fr 240px;
    gap: var(--space-xl);
    max-width: 900px;
    margin: 0 auto;
}

.help-guide h2 {
    font-family: var(--font-display);
    font-size: 1.35rem;
    margin-top: var(--space-xl);
    margin-bottom: var(--space-sm);
}

.help-guide h2:first-child {
    margin-top: 0;
}

.help-guide p,
.help-guide li {
    line-height: 1.7;
    color: var(--color-text-secondary);
    max-width: 70ch;
}

.help-guide ul,
.help-guide ol {
    padding-left: var(--space-lg);
    margin-bottom: var(--space-md);
}

.help-guide code {
    background: var(--color-bg-warm);
    padding: 2px 6px;
    border-radius: var(--radius-sm);
    font-size: 0.9em;
}

.help-sidebar {
    border-left: 1px solid var(--color-border-light);
    padding-left: var(--space-lg);
    position: sticky;
    top: var(--space-lg);
    align-self: start;
    max-height: calc(100vh - var(--space-xl));
    overflow-y: auto;
}

/* Same floor for the category toggles: they are the control that reveals each
   group, so they are as tappable as the links inside them. */
.help-sidebar__heading {
    min-height: 44px;
    display: flex;
    align-items: center;
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 600;
    color: var(--color-text-secondary);
    cursor: pointer;
    list-style: none;
    padding: var(--space-xs) 0;
}

.help-sidebar__heading::-webkit-details-marker {
    display: none;
}

.help-sidebar__heading:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 2px;
}

.help-sidebar__section {
    margin-top: var(--space-sm);
}

.help-sidebar__section:first-child {
    margin-top: 0;
}

.help-sidebar__section ul {
    list-style: none;
    padding: 0;
    margin: 0 0 var(--space-sm);
}

.help-sidebar__section li {
    /* The anchor owns its own height now (see below); keeping the old vertical
       padding here would stack two boxes and stretch the list. */
    padding: 0;
}

/* WCAG 2.5.8 (AA) target size. These rendered as unpadded INLINE anchors at
   13.6px, measuring 17px tall on a 34.4px pitch -- under the 24px floor, on the
   navigation for ~50 guides, on the surface a contributor is most likely to
   reach from a phone. The height is carried by PADDING, not by enlarging the
   type, so the sidebar keeps its density and the type scale is untouched.
   Design critique 2026-09-08. */
.help-sidebar__section a {
    display: flex;
    align-items: center;
    color: var(--color-text-secondary);
    text-decoration: none;
    font-size: var(--text-sm);
    min-height: 44px;
    padding: var(--space-sm) var(--space-xs);
}

.help-sidebar__section a:hover {
    color: var(--color-primary-text);
}

.help-sidebar__section a:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 2px;
}

.help-sidebar__section a.active {
    color: var(--color-primary-text);
    font-weight: 600;
}

.help-category-desc {
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
    line-height: 1.5;
    margin-bottom: var(--space-sm);
}

.help-category-card--start {
    border-color: var(--color-primary);
}

.help-start-badge {
    display: inline-block;
    font-size: var(--text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-primary-text);
    margin-bottom: var(--space-xs);
}

.help-guide-cta {
    grid-column: 1 / -1;
    text-align: center;
    padding: var(--space-lg) 0 var(--space-sm);
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
}

.help-guide-cta a {
    color: var(--color-primary-text);
    text-decoration: none;
}

.help-guide-cta a:hover {
    text-decoration: underline;
}

.breadcrumb {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-sm);
}

.breadcrumb a {
    color: var(--color-primary-text);
    text-decoration: none;
    padding: 2px 4px;
    margin: -2px -4px;
    border-radius: 2px;
}

.breadcrumb a:hover {
    text-decoration: underline;
}

.breadcrumb a:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.breadcrumb-separator {
    margin: 0 var(--space-xs);
}

@media (max-width: 768px) {
    .help-guide-layout {
        grid-template-columns: 1fr;
    }
    .help-sidebar {
        border-left: none;
        border-top: 1px solid var(--color-border-light);
        padding-left: 0;
        padding-top: var(--space-lg);
        position: static;
        max-height: none;
        overflow-y: visible;
    }
}

@media (max-width: 640px) {
    .help-index {
        grid-template-columns: 1fr;
    }
    .faq-item summary::after {
        flex-shrink: 0;
        margin-left: var(--space-sm);
    }
}

/* ── About Page ──────────────────────────────────────────────────── */
/* Archival-object register: dedication-style lede, narrow-measure
   founder story with drop-cap, CSS-drawn seal as section break,
   paired what-we-do + mission, datemark footer. */

.about {
    /* Outer-wrapper width matched to .hiw (880px) so narrative marketing
       pages share a single chrome width. Inner text columns (.about-major,
       .about-pair__col p) carry their own ch-based caps for read measure. */
    max-width: var(--width-narrative, 880px);
    margin: 0 auto;
    padding: var(--space-2xl) var(--space-lg) var(--space-3xl);
}

/* Dedication lede: asymmetric, display italic. */
.about-dedication {
    margin: var(--space-xl) 0 var(--space-3xl);
    padding-left: clamp(0px, 6vw, 60px);
    border-left: 1px solid var(--color-border-light);
}

.about-dedication__line {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 500;
    font-size: clamp(1.5rem, 3.5vw, 2.1rem);
    line-height: 1.25;
    color: var(--color-text);
    margin: 0 0 var(--space-sm);
    max-width: 28ch;
}

.about-dedication__attr {
    font-size: 0.78rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin: 0;
}

/* Pete section: section spans the wrapper, body text caps at 58ch
   for read measure (matching the .hiw-step__body pattern). The
   previous shape capped the whole section at 58ch so the right
   edge jumped between this section and .about-pair / .about-cta. */
.about-major {
    margin: var(--space-3xl) 0;
}

.about-major__heading {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(2rem, 4.5vw, 2.8rem);
    line-height: 1.15;
    margin: 0 0 var(--space-xl);
    color: var(--color-text);
    max-width: 18ch;
}

.about-major__body {
    max-width: 58ch;
}

.about-major__body p {
    font-family: var(--font-display);
    font-size: 1.15rem;
    line-height: 1.7;
    color: var(--color-text);
    margin-bottom: var(--space-lg);
}

/* Drop-cap on the first paragraph. Float left into the text. */
.about-major__lead::first-letter {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 4rem;
    line-height: 0.85;
    float: left;
    padding: 0.3rem 0.6rem 0 0;
    color: var(--color-primary-deep);
}

/* CSS-drawn seal: section break between story and present-day. */
.about-seal {
    display: flex;
    justify-content: center;
    margin: var(--space-3xl) 0;
    color: var(--color-primary-text);
    opacity: 0.7;
}

.about-seal svg {
    width: 56px;
    height: 56px;
}

/* Paired what-we-do + mission: two columns on desktop, stacked on mobile. */
.about-pair {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-2xl);
    margin: var(--space-3xl) 0;
    padding-top: var(--space-2xl);
    border-top: 1px solid var(--color-border-light);
}

@media (min-width: 720px) {
    .about-pair {
        grid-template-columns: 1fr 1fr;
        gap: var(--space-3xl);
    }
}

.about-pair__heading {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.4rem;
    margin: 0 0 var(--space-md);
    color: var(--color-text);
}

.about-pair__col p {
    line-height: 1.7;
    color: var(--color-text-secondary);
    margin-bottom: var(--space-md);
}

.about-pair__credo {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.15rem !important;
    color: var(--color-text) !important;
}

/* Datemark: small-caps colophon line. */
.about-datemark {
    margin: var(--space-3xl) 0;
    padding: var(--space-lg) 0;
    border-top: 1px solid var(--color-border-light);
    border-bottom: 1px solid var(--color-border-light);
    text-align: center;
}

.about-datemark p {
    font-size: 0.78rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin: 0;
}

.about-datemark__sep {
    margin: 0 0.6em;
    color: var(--color-primary-text);
    opacity: 0.55;
}

/* Final CTA: literary, restrained. */
.about-cta {
    margin: var(--space-3xl) 0 0;
    text-align: center;
    padding: var(--space-2xl) 0;
}

.about-cta__heading {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(1.6rem, 3.5vw, 2rem);
    margin: 0 0 var(--space-sm);
    color: var(--color-text);
}

.about-cta__sub {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.05rem;
    color: var(--color-text-secondary);
    margin: 0 0 var(--space-xl);
}

/* ── Promise Page (standalone /promise/) ─────────────────────────
   Six-card manifesto. Visual DNA shared with .about (880px chrome,
   Cormorant body at 1.1-1.15rem, italic terracotta numerals matching
   .promise-strip__num on the homepage strip so card and strip read
   as the same family). The .promise-card classes had no CSS
   anywhere in the project before this — the page rendered as raw
   unstyled text. */

.promise {
    max-width: var(--width-narrative, 880px);
    margin: 0 auto;
    padding: var(--space-2xl) var(--space-lg) var(--space-3xl);
}

.promise__hero {
    margin-bottom: var(--space-3xl);
}

.promise__hero h1 {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(2.4rem, 5vw, 3.4rem);
    line-height: 1.1;
    color: var(--color-text);
    margin: 0 0 var(--space-md);
}

.promise__lede {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.2rem;
    color: var(--color-text-secondary);
    margin: 0;
    max-width: 50ch;
}

.promise__list {
    list-style: none;
    margin: 0;
    padding: 0;
    counter-reset: promise;
}

.promise__list > li {
    margin: 0 0 var(--space-3xl);
}

.promise__list > li:last-child {
    margin-bottom: 0;
}

.promise-card {
    padding: var(--space-xl) 0 0;
    border-top: 1px solid var(--color-border-light);
}

.promise-card__header {
    display: flex;
    align-items: baseline;
    gap: var(--space-md);
    margin: 0 0 var(--space-md);
}

.promise-card__number {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 500;
    font-size: 1.4rem;
    color: var(--color-primary-text);
    opacity: 0.75;
    flex-shrink: 0;
    min-width: 1.4em;
}

.promise-card__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(1.6rem, 3.5vw, 2rem);
    line-height: 1.2;
    color: var(--color-text);
    margin: 0;
}

.promise-card__commitment {
    font-family: var(--font-display);
    font-size: 1.15rem;
    line-height: 1.6;
    color: var(--color-text);
    margin: 0 0 var(--space-lg);
    max-width: 60ch;
}

/* Proof + Won't stacked vertically — read like commitments under
   the commitment, not feature-card columns. Column runs flush-left in
   the .promise wrapper; the numeral hangs beside its title inside
   .promise-card__header without indenting the body. */
.promise-card__proof,
.promise-card__wont {
    margin-bottom: var(--space-md);
    max-width: 60ch;
}

.promise-card__wont:last-child {
    margin-bottom: 0;
}

.promise-card__label {
    font-size: 0.72rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin: 0 0 var(--space-sm);
}

.promise-card__proof ul,
.promise-card__wont ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

.promise-card__proof li,
.promise-card__wont li {
    font-size: 0.95rem;
    line-height: 1.5;
    margin: 0 0 var(--space-xs);
    color: var(--color-text-secondary);
}

.promise-card__proof a {
    color: var(--color-primary-deep);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.2em;
    transition: color var(--duration-fast) var(--ease-out);
}

.promise-card__proof a:hover {
    color: var(--color-primary-hover, var(--color-primary));
}

.promise-card__wont-mark {
    color: var(--color-primary-text);
    opacity: 0.7;
    font-weight: 600;
    margin-right: 0.4em;
    display: inline-block;
    width: 1em;
    text-align: center;
}

.promise__footer {
    margin-top: var(--space-3xl);
    padding-top: var(--space-xl);
    border-top: 1px solid var(--color-border-light);
}

.promise__footer p {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1rem;
    line-height: 1.6;
    color: var(--color-text-secondary);
    margin: 0 0 var(--space-sm);
    max-width: 60ch;
}

.promise__footer a {
    color: var(--color-primary-deep);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.2em;
}

.promise__updated {
    font-style: normal !important;
    font-family: var(--font-body) !important;
    font-size: 0.78rem !important;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--color-text-muted) !important;
    margin: var(--space-md) 0 0 !important;
}

/* ── FAQ Page ────────────────────────────────────────────────────── */

/* Single 880px wrapper matches the .about / .hiw / .promise convention
   so the page heading and the FAQ list share the same outer edges
   instead of the heading sitting at the wider 1100px page-header
   container while the list floats centered at 680px. */
.faq-page {
    max-width: var(--width-narrative, 880px);
    margin: 0 auto;
    padding: 0 var(--space-lg);
}

.faq-page .page-header {
    max-width: none;
    padding: 0;
}

.faq-list {
    margin: 0;
}

/* In-page table of contents: quiet pill list of anchor links to each
   section heading. Smooth scroll on click via [href^="#"] CSS scroll-behavior
   inherited from html; no JS required. */
.faq-toc {
    margin: 0 0 var(--space-xl);
    padding: var(--space-md) var(--space-lg);
    background: var(--color-bg);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
}

.faq-toc ul {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm) var(--space-lg);
}

.faq-toc a {
    color: var(--color-primary-text);
    font-family: var(--font-body);
    font-weight: 500;
    font-size: 0.95rem;
    text-decoration: none;
    border-bottom: 1px solid transparent;
    padding-bottom: 2px;
    transition: border-color var(--duration-fast) var(--ease-out);
}

.faq-toc a:hover,
.faq-toc a:focus-visible {
    border-bottom-color: var(--color-primary);
}

/* Section heading inside the FAQ list: Cormorant Garamond display face,
   sentence case, with a quiet binding-border rule above to separate
   sections without competing with the question text. The first section
   heading sits flush at the top of the list. */
.faq-section__title {
    font-family: var(--font-display);
    font-size: 1.6rem;
    font-weight: 600;
    color: var(--color-text);
    margin: var(--space-xl) 0 var(--space-md);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border-light);
    scroll-margin-top: var(--space-xl);
}

.faq-section__title:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

.faq-item {
    border-bottom: 1px solid var(--color-border-light);
    padding: var(--space-md) 0;
}

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

.faq-item summary {
    font-family: var(--font-display);
    font-size: 1.15rem;
    font-weight: 600;
    cursor: pointer;
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 44px;
    padding: var(--space-xs) 0;
    border-radius: 4px;
}

.faq-item summary:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.faq-item summary::after {
    content: "+";
    font-size: 1.25rem;
    color: var(--color-text-muted);
    transition: transform var(--duration-fast) var(--ease-out);
}

.faq-item[open] summary::after {
    content: "\2212";
}

.faq-item p {
    margin-top: var(--space-sm);
    line-height: 1.7;
    color: var(--color-text-secondary);
}

.faq-item a {
    color: var(--color-primary-text);
}

.form-subtitle {
    color: var(--color-text-secondary);
    margin-bottom: var(--space-lg);
}

/* ---------- Changelog ---------- */
/* --- Changelog --- */
.changelog-intro {
    max-width: 720px;
    margin: 0 auto var(--space-xl);
    color: var(--color-text-secondary);
    text-align: center;
    font-size: 1.05rem;
}

.changelog-timeline {
    max-width: 720px;
    margin: 0 auto;
    position: relative;
}

/* Vertical timeline connector */
.changelog-timeline::before {
    content: "";
    position: absolute;
    left: 135px;
    top: var(--space-lg);
    bottom: var(--space-lg);
    width: 2px;
    background: var(--color-border-light);
}

.changelog-day {
    display: grid;
    grid-template-columns: 140px 1fr;
    gap: var(--space-lg);
    padding: var(--space-lg) 0;
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
}

.changelog-date-col {
    position: relative;
    display: flex;
    align-items: flex-start;
    justify-content: flex-end;
    gap: var(--space-sm);
    padding-top: 2px;
    padding-right: var(--space-md);
}

/* Timeline dot */
.changelog-dot {
    position: absolute;
    right: -5px;
    top: 7px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--color-primary-light);
    border: 2px solid var(--color-bg);
    box-shadow: 0 0 0 2px var(--color-border);
    z-index: 1;
    flex-shrink: 0;
    transition: background var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.changelog-day:hover .changelog-dot {
    background: var(--color-primary);
    box-shadow: 0 0 0 2px var(--color-primary-light);
}

.changelog-date {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text-muted);
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.changelog-date-group {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
}

.changelog-relative {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.changelog-entries {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    transition: box-shadow var(--duration-normal) var(--ease-out),
                border-color var(--duration-normal) var(--ease-out);
}

.changelog-day:hover .changelog-entries {
    box-shadow: var(--shadow-md);
    border-color: var(--color-border);
}

.changelog-entry {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    line-height: 1.6;
    padding: 4px 0;
}

.changelog-entry + .changelog-entry {
    border-top: 1px solid var(--color-border-light);
    padding-top: var(--space-sm);
}

.changelog-tag {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 2px 8px;
    border-radius: 9999px;
    white-space: nowrap;
    flex-shrink: 0;
}

.changelog-tag-fix {
    background: rgba(94, 139, 101, 0.15);
    color: var(--color-text-on-bg-success);
}

.changelog-tag-new {
    background: var(--color-primary-glow);
    color: var(--color-primary-text);
}

.changelog-tag-update {
    background: color-mix(in srgb, var(--color-info) 15%, transparent);
    color: var(--color-text-on-bg-info);
}

.changelog-text {
    color: var(--color-text);
    font-size: 0.95rem;
}

.changelog-empty {
    max-width: 720px;
    margin: var(--space-2xl) auto;
    text-align: center;
    color: var(--color-text-muted);
    font-style: italic;
}

@media (max-width: 600px) {
    .changelog-timeline::before {
        display: none;
    }

    .changelog-day {
        grid-template-columns: 1fr;
        gap: var(--space-xs);
    }

    .changelog-date-col {
        justify-content: flex-start;
        padding-right: 0;
    }

    .changelog-date-group {
        align-items: flex-start;
    }

    .changelog-dot {
        display: none;
    }

    .changelog-date {
        font-size: var(--text-xs);
        font-weight: 600;
        color: var(--color-text-secondary);
    }
}

/* --- Export request page (/books/<slug>/export/) --- */
.export-form {
    /* The default page-content-form is 680px; the format + theme grid wants
       a bit more room so each theme card can breathe. */
    max-width: 760px;
}

.export-promise {
    margin: 0 0 var(--space-lg);
}

.export-form__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-xl);
}

/* Format radio cards: replaces the old <select> dropdown with a 3-up group
   that names what each download is. The native radio is visually hidden but
   still drives focus and keyboard nav. */
.format-cards {
    display: grid;
    /* auto-fit so single-format plans (e.g. ZIP-only) don't leave two
       empty grid tracks beside the lone card. */
    grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
    gap: var(--space-sm);
    margin-top: var(--space-sm);
}

.format-card {
    position: relative;
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    column-gap: var(--space-sm);
    row-gap: 0.15rem;
    align-items: start;
    padding: var(--space-md) var(--space-md);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: border-color var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.format-card input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    inset: 0;
    margin: 0;
}

.format-card:hover {
    border-color: var(--color-border);
    background: var(--color-bg-card-hover);
}

.format-card:focus-within {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
}

.format-card--selected {
    border-color: var(--color-primary);
    background: color-mix(in oklab, var(--color-primary) 5%, var(--color-bg-card));
    box-shadow: inset 0 0 0 1px var(--color-primary);
}

.format-card__icon {
    grid-row: span 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: var(--radius-sm);
    background: var(--color-bg-warm);
    color: var(--color-text-secondary);
    margin-top: 1px;
    transition: background var(--duration-fast) var(--ease-out),
                color var(--duration-fast) var(--ease-out);
}

.format-card--selected .format-card__icon {
    background: var(--color-primary);
    color: var(--color-text-on-primary);
}

.format-card__name {
    font-weight: 600;
    color: var(--color-text);
    font-size: 0.95rem;
    line-height: 1.2;
}

.format-card__desc {
    color: var(--color-text-secondary);
    font-size: 0.78rem;
    line-height: 1.4;
}

@media (max-width: 640px) {
    .format-cards {
        grid-template-columns: 1fr;
    }
    .format-card__icon {
        grid-row: 1;
    }
}

.export-format-hint {
    margin: calc(var(--space-md) * -1) 0 0;
    padding: var(--space-sm) var(--space-md);
    background: var(--color-bg-warm);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--color-text-secondary);
}

/* --- Theme Card Picker --- */
.theme-cards {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-md);
    margin: var(--space-sm) 0 0;
}
.theme-card {
    position: relative;
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    overflow: hidden;
    cursor: pointer;
    background: var(--color-bg-card);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
}
.theme-card input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    inset: 0;
}
.theme-card:hover {
    border-color: var(--color-border);
    box-shadow: var(--shadow-sm);
}
.theme-card:focus-within {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
}
.theme-card--selected {
    border-color: var(--color-primary);
    box-shadow: inset 0 0 0 1px var(--color-primary), var(--shadow-sm);
}

/* Selected indicator — small filled circle with a check, top-right of the
   preview. Only renders when the card is selected; replaces the heavy dual
   border + ring that read like a button-press state. */
.theme-card__check {
    position: absolute;
    top: var(--space-sm);
    right: var(--space-sm);
    width: 1.1rem;
    height: 1.1rem;
    border-radius: 999px;
    background: var(--color-primary);
    opacity: 0;
    transform: scale(0.7);
    transition: opacity var(--duration-fast) var(--ease-out),
                transform var(--duration-fast) var(--ease-out);
    z-index: 1;
}
.theme-card__check::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 47%;
    width: 0.32rem;
    height: 0.55rem;
    /* Decorative checkmark — border-width shorthand (top right bottom left). */
    border-style: solid;
    border-color: var(--color-text-on-primary);
    border-width: 0 1.5px 1.5px 0;
    transform: translate(-50%, -50%) rotate(45deg);
}
.theme-card--selected .theme-card__check {
    opacity: 1;
    transform: scale(1);
}

.theme-preview {
    min-height: 140px;
    padding: var(--space-sm) var(--space-md);
}
.theme-preview--elegant {
    background: var(--color-parchment-warm);
}
.theme-preview--modern {
    background: var(--color-bg-card);
}
.theme-preview--storybook {
    background: var(--color-parchment);
}
.theme-card-label {
    padding: var(--space-sm) var(--space-md);
    border-top: 1px solid var(--color-border-light);
    background: var(--color-bg);
}
.theme-card-label strong {
    display: block;
    font-size: var(--text-sm);
    color: var(--color-text);
}
.theme-card-label span {
    display: block;
    font-size: 0.72rem;
    color: var(--color-text-muted);
    line-height: 1.4;
    margin-top: 0.1rem;
}
@media (max-width: 720px) {
    .theme-cards {
        grid-template-columns: 1fr;
    }
}

/* ============================================================
 * Export request — v2 (use-case themes + structure + print)
 * Gated by export_themes_v2 Waffle switch. Shape: three sections
 * (Theme / Structure / Print) on a single scroll. Builds on the
 * existing .format-card and .theme-card primitives.
 * ============================================================ */

.export-form--v2 .export-section {
    margin-top: var(--space-2xl);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border-light);
}

.export-form--v2 .form-fieldset__legend {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-md);
    width: 100%;
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 600;
    color: var(--color-text);
    margin-bottom: var(--space-md);
}

.export-form--v2 .form-fieldset__sublegend {
    font-size: 0.95rem;
    color: var(--color-text-muted);
    margin: var(--space-md) 0 var(--space-sm);
}

.export-form--v2 .suggested-pill {
    display: inline-flex;
    align-items: center;
    padding: 0.18rem 0.7rem;
    border-radius: 999px;
    font-family: var(--font-body);
    font-size: 0.72rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    background: color-mix(in srgb, var(--color-primary) 12%, transparent);
    color: var(--color-primary-text);
}

.export-form--v2 .btn-text {
    background: none;
    border: 0;
    padding: 0;
    color: var(--color-primary-text);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
}

.export-form--v2 .btn-text:hover {
    color: var(--color-primary-text-hover);
}

/* Theme cards (v2) — 4-up at desktop, suggested card highlighted */
.theme-cards--v2 {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--space-md);
}

.theme-card--v2 {
    position: relative;
    cursor: pointer;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-md);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.theme-card--v2.theme-card--suggested {
    border-color: color-mix(in srgb, var(--color-primary) 35%, transparent);
}

.theme-card--v2.theme-card--suggested::before {
    content: "Suggested";
    position: absolute;
    top: -0.55rem;
    left: 1rem;
    padding: 0.1rem 0.55rem;
    background: var(--color-primary);
    color: var(--color-text-on-primary);
    font-family: var(--font-body);
    font-size: 0.65rem;
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    border-radius: 999px;
}

.theme-card--v2:hover {
    border-color: color-mix(in srgb, var(--color-primary) 50%, transparent);
}

.theme-card--v2.theme-card--selected {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 22%, transparent);
}

/* Per-theme preview tints — quick swatches that hint at the rendered
 * PDF identity color without paying for a real WeasyPrint render. The
 * second gradient stop on wedding (#F5EAD3) and baby (#F8E4DD) are
 * theme-bespoke pastels with no token equivalent — they exist only on
 * this preview and on the matching theme CSS file under
 * apps/exports/templates/exports/pdf/themes/, so a token here would
 * just be unused noise. */
.theme-preview--memorial { background: linear-gradient(180deg, var(--color-bg) 0%, var(--color-bg-warm) 100%); }
.theme-preview--memorial .tp-rule--memorial { background: var(--color-accent); }
.theme-preview--wedding { background: linear-gradient(180deg, var(--color-bg-card) 0%, #F5EAD3 100%); }
.theme-preview--wedding .tp-rule--wedding { background: var(--color-storybook-gold); }
.theme-preview--baby { background: linear-gradient(180deg, var(--color-bg-card) 0%, #F8E4DD 100%); }
.theme-preview--baby .tp-rule--baby { background: var(--color-occasion-rose); }
.theme-preview--journal { background: var(--color-bg-card); border-bottom: 4px solid var(--color-text); }
.theme-preview--journal .tp-rule--journal { background: var(--color-text); height: 2px; }
.theme-preview--retirement { background: var(--color-bg); border-top: 3px double var(--color-primary-hover); border-bottom: 3px double var(--color-primary-hover); }
.theme-preview--retirement .tp-rule--retirement { background: var(--color-primary-hover); }
.theme-preview--botanical { background: radial-gradient(circle at 16% 18%, rgba(168, 176, 158, 0.35) 0, transparent 38%), linear-gradient(180deg, #FBF7EF 0%, #F3E6D8 100%); }
.theme-preview--botanical .tp-rule--botanical { background: #A8B09E; }
.theme-preview--heirloom { background: linear-gradient(180deg, #F7F1E6 0%, #FFFDF8 100%); border: 1px solid #D8C5A5; box-shadow: inset 0 0 0 0.5rem rgba(255, 253, 248, 0.7); }
.theme-preview--heirloom .tp-rule--heirloom { background: #8A6A45; }
.theme-preview--noir { background: linear-gradient(180deg, #151311 0%, #2A2520 100%); color: #FFF8EA; }
.theme-preview--noir .tp-rule--noir { background: #B9824B; }
.theme-preview--noir .tp-meta,
.theme-preview--noir .tp-quote-author { color: #E8D6B8; }

.theme-preview .tp-glyph {
    font-size: 1.5rem;
    color: var(--color-primary-text);
    margin-bottom: var(--space-xs);
    line-height: 1;
}

/* Structure section — checkbox grid */
.export-structure-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--space-sm) var(--space-md);
    margin: var(--space-md) 0;
}

.check-row {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    padding: var(--space-sm);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background var(--duration-fast) var(--ease-out);
}

.check-row:hover {
    background: color-mix(in srgb, var(--color-primary) 5%, transparent);
}

.check-row input[type="checkbox"] {
    margin-top: 0.2rem;
    accent-color: var(--color-primary);
}

.check-row strong {
    font-family: var(--font-body);
    font-weight: 500;
    color: var(--color-text);
}

/* Section organize — radio pills */
.radio-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    margin-top: var(--space-sm);
}

.radio-pill {
    display: inline-flex;
    align-items: center;
    padding: 0.4rem 0.9rem;
    border-radius: 999px;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    font-family: var(--font-body);
    font-size: var(--text-sm);
    cursor: pointer;
    transition: border-color var(--duration-fast) var(--ease-out), background var(--duration-fast) var(--ease-out);
}

.radio-pill input[type="radio"] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
}

.radio-pill:hover {
    border-color: color-mix(in srgb, var(--color-primary) 35%, transparent);
}

.radio-pill--selected {
    background: color-mix(in srgb, var(--color-primary) 12%, transparent);
    border-color: var(--color-primary);
    color: var(--color-text);
}

/* Print intent — three large cards */
.print-intent-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: var(--space-md);
    margin-top: var(--space-md);
}

.print-intent-card {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    padding: var(--space-md);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: border-color var(--duration-fast) var(--ease-out);
}

.print-intent-card input[type="radio"] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
}

.print-intent-card:hover {
    border-color: color-mix(in srgb, var(--color-primary) 40%, transparent);
}

.print-intent-card--selected {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 18%, transparent);
}

.print-intent-card strong {
    font-family: var(--font-display);
    font-size: 1.2rem;
    font-weight: 600;
    color: var(--color-text);
}

/* Advanced disclosures */
.export-advanced-copy,
.export-advanced-print {
    margin-top: var(--space-lg);
    padding: var(--space-md);
    background: var(--color-bg-warm);
    border-radius: var(--radius-md);
}

.export-advanced-copy summary,
.export-advanced-print summary {
    cursor: pointer;
    font-family: var(--font-body);
    font-weight: 500;
    color: var(--color-primary-text);
    list-style: none;
    min-height: 44px;
    display: flex;
    align-items: center;
}

.export-advanced-copy summary::before,
.export-advanced-print summary::before {
    content: "▸ ";
    display: inline-block;
    transition: transform var(--duration-fast) var(--ease-out);
}

.export-advanced-copy[open] summary::before,
.export-advanced-print[open] summary::before {
    transform: rotate(90deg);
}

.export-advanced-copy .form-field,
.export-advanced-print .form-field {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin-top: var(--space-md);
}

.form-field__label {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 500;
    color: var(--color-text-muted);
}

.export-advanced-copy textarea {
    font-family: var(--font-body);
    width: 100%;
    padding: 0.55rem 0.75rem;
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    background: var(--color-bg-card);
    font-size: 0.95rem;
    line-height: 1.55;
    resize: vertical;
}

.export-advanced-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--space-md);
    margin-top: var(--space-md);
}

.export-advanced-grid select {
    font-family: var(--font-body);
    width: 100%;
    min-height: 44px;
    padding: 0.55rem 0.75rem;
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    background: var(--color-bg-card);
    font-size: 1rem;
}

@media (max-width: 720px) {
    .theme-cards--v2 {
        grid-template-columns: 1fr;
    }
    .export-form--v2 .form-fieldset__legend {
        font-size: 1.25rem;
    }
}

/* --- Export status page (/books/<slug>/export/<job_id>/) --- */
.export-status {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-lg) var(--space-xl);
    box-shadow: var(--shadow-sm);
}

.export-status .progress-bar {
    margin-bottom: var(--space-lg);
}

.export-status__panel {
    display: grid;
    grid-template-columns: max-content 1fr;
    column-gap: var(--space-lg);
    row-gap: var(--space-sm);
    margin: 0;
}

.export-status__row {
    display: contents;
}

.export-status__row dt {
    color: var(--color-text-muted);
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    align-self: center;
}

.export-status__row dd {
    margin: 0;
    color: var(--color-text);
    font-variant-numeric: tabular-nums;
}

.export-status__pill {
    display: inline-flex;
    align-items: center;
    padding: 0.18rem 0.6rem;
    border-radius: 999px;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    background: var(--color-badge-muted);
    color: var(--color-badge-text-muted);
}

.export-status__pill--complete {
    background: var(--color-badge-success);
    color: var(--color-badge-text-success);
}

.export-status__pill--processing,
.export-status__pill--pending {
    background: var(--color-badge-info);
    color: var(--color-badge-text-info);
}

.export-status__pill--failed {
    background: var(--color-badge-warning);
    color: var(--color-badge-text-warning);
}

.export-status__download {
    margin-top: var(--space-lg);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border-light);
}

.export-status__error {
    margin-top: var(--space-md);
}

.export-status__actions {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    margin-top: var(--space-lg);
    flex-wrap: wrap;
}

.export-status__back {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

/* Destructive action sits in a quiet disclosure so it can't be mis-clicked
   alongside the "Start another" / "Back to book" links. */
.export-status__danger {
    margin-top: var(--space-xl);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border-light);
}

.export-status__danger summary {
    list-style: none;
    cursor: pointer;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    user-select: none;
    transition: color var(--duration-fast) var(--ease-out);
    min-height: 44px;
    display: flex;
    align-items: center;
}

.export-status__danger summary::-webkit-details-marker {
    display: none;
}

.export-status__danger summary::before {
    content: "+";
    display: inline-block;
    width: 1rem;
    margin-right: 0.25rem;
    color: var(--color-text-muted);
    transition: transform var(--duration-fast) var(--ease-out);
}

.export-status__danger[open] summary::before {
    content: "−";
}

.export-status__danger summary:hover {
    color: var(--color-text-secondary);
}

.export-status__danger > p {
    margin: var(--space-sm) 0 var(--space-md);
}

/* Theme preview miniatures */
.form-card--wide { max-width: 720px; }
.export-subtitle { max-width: none; margin-bottom: var(--space-xl); }

/* Book-create editorial hero — bleeds to form-card edges for visual impact */
.form-card__hero-image {
    margin: 0 calc(var(--space-2xl) * -1) var(--space-xl);
    border-radius: var(--radius-md);
    overflow: hidden;
    aspect-ratio: 2 / 1;
    background: var(--color-bg-warm);
}

.form-card__hero-image picture,
.form-card__hero-image img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

@media (max-width: 560px) {
    .form-card__hero-image {
        margin-inline: calc(var(--space-lg) * -1);
        aspect-ratio: 3 / 2;
    }
}

/* ── Create-Book Wizard (2-step) ─────────────────────────────────── */

.form-card--wizard {
    max-width: 640px;
}

.wizard-header {
    margin-bottom: var(--space-xl);
}

.wizard-steps {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    font-family: var(--font-body);
    font-size: 0.88rem;
    color: var(--color-text-muted);
}

.wizard-step {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    padding: 0.3rem 0.6rem;
    border-radius: var(--radius-sm);
    transition: color var(--duration-fast) var(--ease-out),
                background-color var(--duration-fast) var(--ease-out);
}

.wizard-step__num {
    display: inline-grid;
    place-items: center;
    width: 1.4em;
    height: 1.4em;
    border-radius: 50%;
    background: var(--color-bg-warm);
    color: var(--color-text-muted);
    font-weight: 600;
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
}

.wizard-step--active {
    color: var(--color-text);
    font-weight: 500;
}

.wizard-step--active .wizard-step__num {
    background: var(--color-primary);
    color: var(--color-text-on-primary);
}

.wizard-step--done .wizard-step__num {
    /* 20% tint over --color-bg-card (.form-card) put --color-primary-text
       at 4.46:1 in light mode — under the 4.5:1 AA floor by a hair.
       Lightened to 15% (4.77:1 light / 4.87:1 dark, both clear AA);
       still reads as the same tinted-wash "done" badge. */
    background: color-mix(in srgb, var(--color-primary) 15%, transparent);
    color: var(--color-primary-text);
}

.wizard-step__divider {
    flex: 0 0 auto;
    width: 1.5rem;
    height: 1px;
    background: var(--color-border-light);
}

.wizard-step:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
}

.wizard-step-title {
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 3.5vw, 2rem);
    margin: 0 0 var(--space-xs);
    color: var(--color-text);
}

.wizard-step-subtitle {
    color: var(--color-text-secondary);
    font-size: 1rem;
    line-height: 1.55;
    margin: 0 0 var(--space-xl);
}

.wizard-actions {
    margin-top: var(--space-xl);
}

.wizard-actions--split {
    display: flex;
    gap: var(--space-md);
    align-items: center;
    justify-content: space-between;
}

.btn-ghost {
    background: transparent;
    color: var(--color-text-secondary);
    border: none;
    padding: 0.6rem 0.3rem;
    cursor: pointer;
    font-family: var(--font-body);
    font-size: 0.95rem;
    font-weight: 500;
}

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

.btn-ghost:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

.tp-header { text-align: center; padding: 8px; }
.tp-subtitle { font-family: var(--font-body); font-size: max(11px, 0.7rem); letter-spacing: 2px; text-transform: uppercase; color: var(--color-ink-muted); margin-bottom: 4px; }
.tp-title { font-family: var(--font-display); font-size: 14px; color: var(--color-ink-warm); font-weight: bold; }
.tp-title--modern { font-family: var(--font-display); font-size: 15px; color: var(--color-modern-ink); font-weight: 700; letter-spacing: -0.3px; }
.tp-title--storybook { color: var(--color-storybook-ink); }
.tp-star { font-size: 14px; color: var(--color-storybook-gold); }
.tp-rule { margin: 6px auto; }
.tp-rule--elegant { width: 30px; height: 1px; background: var(--color-ink-gold); }
.tp-rule--modern { width: 20px; height: 2px; background: var(--color-modern-green); border-radius: 1px; margin: 5px auto; }
.tp-rule--storybook { width: 50px; height: 1px; background: var(--color-storybook-gold); margin: 5px auto; }
.tp-meta { font-family: var(--font-body); font-size: max(8px, 0.6rem); color: var(--color-ink-muted); }
.tp-meta--modern { color: var(--color-ink-sage); text-transform: uppercase; letter-spacing: 0.5px; }
.tp-meta--storybook { color: var(--color-storybook-muted); font-style: italic; }

.tp-quote { margin-top: 6px; padding: 6px; }
.tp-quote--elegant { border-left: 1px solid var(--color-ink-gold); background: var(--color-parchment-warm); }
.tp-quote--modern { padding: 8px; background: var(--color-modern-card); border-radius: var(--radius-sm); }
.tp-quote--storybook { padding: 6px 8px; position: relative; }
.tp-quote-text { font-family: var(--font-body); font-size: max(8px, 0.6rem); line-height: 1.6; color: var(--color-ink-soft); }
.tp-quote-text--modern { color: var(--color-modern-ink); }
.tp-quote-text--storybook { font-family: var(--font-display); font-size: max(8px, 0.6rem); line-height: 1.7; color: var(--color-storybook-ink); }
.tp-quote-author { font-family: var(--font-body); font-size: max(7px, 0.6rem); color: var(--color-ink-muted); text-align: right; margin-top: 3px; }
.tp-quote-author--modern { font-weight: 600; color: var(--color-ink-deep); text-align: left; }
.tp-quote-author--storybook { color: var(--color-storybook-muted); }
.tp-quote-footer { display: flex; justify-content: space-between; margin-top: 4px; font-size: max(7px, 0.6rem); color: var(--color-ink-sage); }
.tp-quote-rule { margin-top: 6px; border-top: 1px dashed var(--color-storybook-border); }
.tp-dropcap { float: left; font-family: var(--font-display); font-size: 20px; color: var(--color-storybook-gold); line-height: 1; margin-right: 4px; }

/* ---------- Occasion Hero (Homepage) ---------- */
.occasion-section {
    padding: var(--space-3xl) var(--space-lg);
}

.occasion-hero {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-2xl);
    align-items: center;
    max-width: var(--width-grid, 1100px);
    margin: 0 auto var(--space-2xl);
}

.occasion-hero__image {
    border-radius: var(--radius-lg);
    overflow: hidden;
    aspect-ratio: 4 / 3;
}

.occasion-hero__image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.occasion-hero__content h2 {
    font-family: var(--font-display);
    font-size: clamp(1.6rem, 3.5vw, 2.2rem);
    color: var(--color-text);
    margin-bottom: var(--space-md);
    line-height: 1.2;
}

.occasion-hero__content p {
    font-size: 0.95rem;
    color: var(--color-text-secondary);
    line-height: 1.65;
    margin-bottom: var(--space-lg);
    max-width: 40ch;
}

.occasion-others {
    display: flex;
    justify-content: center;
    gap: var(--space-lg);
    flex-wrap: wrap;
    max-width: 700px;
    margin: 0 auto;
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border-light);
}

.occasion-others a {
    font-size: 0.88rem;
    color: var(--color-text-muted);
    text-decoration: none;
    font-weight: 500;
    transition: color var(--duration-fast) var(--ease-out);
}

.occasion-others a:hover {
    color: var(--color-primary-text-hover);
}

.occasion-others a:last-child {
    color: var(--color-primary-deep);
    font-weight: 600;
}

@media (max-width: 640px) {
    .occasion-hero {
        grid-template-columns: 1fr;
        gap: var(--space-lg);
    }

    .occasion-hero__image {
        aspect-ratio: 16 / 9;
    }

    .occasion-hero__content {
        text-align: center;
    }

    .occasion-hero__content p {
        max-width: none;
    }

    .occasion-others {
        gap: 0.75rem var(--space-md);
        row-gap: 0.25rem;
    }

    .occasion-others a {
        display: inline-block;
        padding: 0.6rem 0.25rem;  /* ≥44px hit-target without disturbing horizontal rhythm */
        line-height: 1.2;
    }
}

/* ---------- Occasion Cards Grid (Use Cases Index) ---------- */
.occasion-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: auto auto;
    gap: var(--space-lg);
    max-width: 900px;
    margin: 0 auto;
}

.occasion-card {
    background: var(--color-bg-card);
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    transition: transform var(--duration-normal) var(--ease-out),
                box-shadow var(--duration-normal) var(--ease-out);
    text-decoration: none;
    color: inherit;
    display: block;
}

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

.occasion-card--featured .occasion-card__name {
    font-size: 1.1rem;
}

/* Symbolic motif slot replaces the previous gradient strip.
   Single accent (Hearth Terracotta), thin-line gestural icons. */
.occasion-card__motif {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 48px;
    padding-top: var(--space-md);
    color: var(--color-primary-text);
}

.occasion-card--featured .occasion-card__motif {
    height: 56px;
    padding-top: var(--space-lg);
}

.occasion-card__motif svg {
    width: 40px;
    height: 40px;
    display: block;
}

.occasion-card__body {
    padding: var(--space-md);
    border-top: 1px solid var(--color-border-light);
    margin-top: var(--space-md);
}

.occasion-card__name {
    font-weight: 600;
    color: var(--color-text);
    margin-bottom: var(--space-xs);
    font-size: 1rem;
}

.occasion-card__desc {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    line-height: 1.4;
}

.occasion-card__link {
    display: block;
    margin-top: var(--space-sm);
    font-size: var(--text-xs);
    color: var(--color-primary-text);
    font-weight: 500;
}

/* ---------- Channels Callout Strip ---------- */
.channels-strip {
    background: var(--color-surface);
    padding: var(--space-2xl) var(--space-lg);
    text-align: center;
    border-top: 1px solid var(--color-border-light);
    border-bottom: 1px solid var(--color-border-light);
}

.channels-strip__tagline {
    font-family: var(--font-display);
    font-size: clamp(1.3rem, 3.5vw, 1.6rem);
    font-weight: 500;
    color: var(--color-text);
    margin-bottom: var(--space-lg);
    max-width: none;
    line-height: 1.3;
}

.channels-strip__icons {
    display: flex;
    justify-content: center;
    gap: var(--space-xl);
    flex-wrap: wrap;
    margin-bottom: var(--space-md);
}

.channels-strip__icon {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-sm);
    font-size: 0.72rem;
    color: var(--color-text-muted);
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

.channels-strip__icon svg {
    color: var(--color-primary-text);
    opacity: 0.85;
}

.channels-strip__conclusion {
    font-size: 0.88rem;
    color: var(--color-text-muted);
    max-width: none;
    margin: 0;
}

/* ---------- Nav Dropdown ---------- */
.nav-dropdown {
    position: relative;
}

.nav-dropdown-toggle {
    cursor: pointer;
    background: none;
    border: none;
    font: inherit;
    color: inherit;
    padding: 0;
    display: flex;
    align-items: center;
    gap: var(--space-xs);
}

.nav-dropdown-toggle::after {
    content: '\25BE';
    font-size: 0.7em;
}

.nav-dropdown-menu {
    display: none;
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    padding: var(--space-sm) 0;
    min-width: 200px;
    z-index: 100;
    /* No margin-top: a gap between the toggle and the menu becomes a
       dead zone where :hover / :focus-within drop, closing the menu
       the instant the cursor crosses it. Menu sits flush against the
       toggle bottom; visual breathing room lives in .nav-dropdown-menu's
       own padding. */
}

.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu {
    display: block;
}

.nav-dropdown-menu a {
    display: block;
    padding: var(--space-sm) var(--space-md);
    color: var(--color-text-secondary);
    text-decoration: none;
    font-size: var(--text-sm);
    white-space: nowrap;
}

.nav-dropdown-menu a:hover {
    background: var(--color-bg-warm);
    color: var(--color-primary-text);
}

.nav-dropdown-menu__divider {
    border-top: 1px solid var(--color-border-light);
    margin-top: var(--space-xs);
    padding-top: var(--space-sm);
}

/* ==========================================================================
   Use-Case Pages — Lean 3-section layout
   Hero → Proof (example book) → CTA
   ========================================================================== */

.uc-page {
    max-width: 100%;
}

/* ── Hero ──────────────────────────────────────────────────────── */
.uc-hero {
    background: linear-gradient(
        135deg,
        var(--color-bg-warm) 0%,
        var(--color-primary-light) 50%,
        var(--color-primary) 100%
    );
    padding: var(--space-3xl) var(--space-lg) var(--space-2xl);
    text-align: center;
    color: var(--color-text-on-primary);
}

.uc-hero h1 {
    font-family: var(--font-display);
    font-size: clamp(2rem, 5vw, 2.8rem);
    margin-bottom: var(--space-md);
    color: var(--color-text-on-primary);
    line-height: 1.2;
    max-width: 640px;
    margin-inline: auto;
}

.uc-hero p {
    font-size: 1.05rem;
    opacity: 0.9;
    max-width: 540px;
    margin: 0 auto;
    line-height: 1.6;
}

/* ── Proof (example book) ──────────────────────────────────────── */
.uc-proof {
    padding: var(--space-3xl) var(--space-lg);
}

.uc-proof__inner {
    max-width: 520px;
    margin: 0 auto;
}

.uc-example__book {
    background: var(--color-bg-card);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}

.uc-example__header {
    padding: var(--space-lg);
    border-bottom: 1px solid var(--color-border-light);
}

.uc-example__header h3 {
    font-family: var(--font-display);
    font-size: 1.25rem;
    color: var(--color-text);
    margin-bottom: var(--space-xs);
}

.uc-example__header p {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.uc-example__submission {
    padding: var(--space-lg);
    border-bottom: 1px solid var(--color-border-light);
}

.uc-example__submission:last-child {
    border-bottom: none;
}

.uc-example__channel-tag {
    display: inline-block;
    font-size: 0.78rem;
    color: var(--color-primary-text);
    font-weight: 600;
    letter-spacing: 0.02em;
    margin-bottom: var(--space-sm);
}

.uc-example__submission p {
    font-size: 0.95rem;
    color: var(--color-text-secondary);
    line-height: 1.6;
    max-width: none;
}

.uc-example__submission .author {
    display: block;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-top: var(--space-sm);
}

.uc-example__photo {
    width: 100%;
    height: 200px;
    object-fit: cover;
    border-radius: var(--radius-md);
    margin-bottom: var(--space-sm);
}

.uc-example__video-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    aspect-ratio: 16 / 9;
    background: var(--color-surface-alt);
    border-radius: var(--radius-sm);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    margin-bottom: var(--space-sm);
}

/* ── Bottom CTA ────────────────────────────────────────────────── */
.uc-bottom-cta {
    padding: var(--space-3xl) var(--space-lg);
    background: var(--color-leather);
    text-align: center;
}

.uc-bottom-cta h2 {
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 3.5vw, 2rem);
    color: var(--color-text-on-primary);
    margin-bottom: var(--space-lg);
    max-width: 500px;
    margin-inline: auto;
}

.uc-bottom-cta .btn {
    background: var(--color-primary);
    color: var(--color-text-on-primary);
}

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

/* ── Memorial muted treatment ──────────────────────────────────── */
.uc-memorial {
    --color-primary: var(--color-memorial);
    --color-primary-hover: var(--color-memorial-hover);
    --color-primary-light: var(--color-memorial-light);
    --color-primary-glow: var(--color-memorial-glow);
    --color-bg-warm: var(--color-memorial-bg);
}

.uc-memorial .uc-hero {
    background: linear-gradient(
        135deg,
        var(--color-memorial-bg) 0%,
        var(--color-memorial-light) 50%,
        var(--color-memorial) 100%
    );
}

/* ── Use-Cases Index Page ──────────────────────────────────────── */
.uc-index {
    padding: var(--space-3xl) var(--space-lg);
    max-width: 960px;
    margin: 0 auto;
}

.uc-index h1 {
    font-family: var(--font-display);
    font-size: clamp(1.8rem, 4vw, 2.4rem);
    color: var(--color-text);
    text-align: center;
    margin-bottom: var(--space-2xl);
}

.uc-index__grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-lg);
}

.uc-index__card {
    display: block;
    text-decoration: none;
    color: inherit;
    background: var(--color-bg-card);
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    transition: transform var(--duration-normal) var(--ease-out),
                box-shadow var(--duration-normal) var(--ease-out);
}

.uc-index__card:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
}

.uc-index__card img {
    width: 100%;
    height: 180px;
    object-fit: cover;
    display: block;
}

.uc-index__card-body {
    padding: var(--space-lg);
}

.uc-index__card-body h2 {
    font-family: var(--font-display);
    font-size: 1.2rem;
    color: var(--color-text);
    margin-bottom: var(--space-xs);
}

.uc-index__card-body p {
    font-size: 0.88rem;
    color: var(--color-text-muted);
    line-height: 1.5;
    max-width: none;
}

.uc-index__card-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 16 / 10;
    background: var(--color-surface);
    color: var(--color-text-muted);
    font-size: 2.5rem;
    border-radius: var(--radius-md) var(--radius-md) 0 0;
}

@media (max-width: 640px) {
    .uc-hero {
        padding: var(--space-2xl) var(--space-md);
    }

    .uc-proof {
        padding: var(--space-2xl) var(--space-md);
    }

    .uc-proof__inner {
        max-width: 100%;
    }

    .uc-bottom-cta {
        padding: var(--space-2xl) var(--space-md);
    }

    .uc-index__grid {
        grid-template-columns: 1fr;
    }
}

/* ============================================================== */
/*  Invitation accept page                                        */
/* ============================================================== */

.invitation-page {
    display: flex;
    justify-content: center;
    padding: var(--space-xl) var(--space-md);
}

.invitation-card {
    width: 100%;
    max-width: 560px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-md);
    overflow: hidden;
}

.invitation-card__cover {
    margin: 0;
    aspect-ratio: 16 / 10;
    background: var(--color-surface-alt);
    overflow: hidden;
}

.invitation-card__cover img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.invitation-card__body {
    padding: var(--space-xl) var(--space-lg) var(--space-lg);
}

.invitation-card__eyebrow {
    margin: 0 0 var(--space-sm);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.invitation-card__title {
    margin: 0 0 var(--space-sm);
    font-family: var(--font-display);
    font-weight: 500;
    font-size: clamp(1.85rem, 4vw, 2.5rem);
    letter-spacing: -0.015em;
    color: var(--color-text);
    line-height: 1.15;
}

.invitation-card__subtitle {
    margin: 0 0 var(--space-md);
    color: var(--color-text-secondary);
    font-size: 1.05rem;
    font-style: italic;
}

.invitation-card__welcome {
    margin: 0 0 var(--space-lg);
    padding: var(--space-md) var(--space-md) var(--space-md) var(--space-lg);
    border-radius: var(--radius-md);
    background: var(--color-surface-alt);
    color: var(--color-text);
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.05rem;
    line-height: 1.55;
    quotes: "\201C" "\201D";
}

.invitation-card__welcome::before {
    content: open-quote;
    margin-right: 0.15em;
    color: var(--color-text-muted);
    font-size: 1.4em;
    line-height: 0;
    vertical-align: -0.25em;
}

.invitation-card__welcome p {
    display: inline;
    margin: 0;
}

.invitation-card__welcome p + p {
    display: block;
    margin-top: var(--space-sm);
}

.invitation-card__message {
    margin: 0 0 var(--space-lg);
    color: var(--color-text);
    font-size: 1.05rem;
    line-height: 1.55;
}

.invitation-card__footnote {
    margin: var(--space-md) 0 0;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    text-align: center;
    line-height: 1.5;
}

@media (max-width: 480px) {
    .invitation-card__body {
        padding: var(--space-lg) var(--space-md) var(--space-md);
    }
}

/* ============================================================== */
/*  Invite page (members management)                              */
/* ============================================================== */

.invite-page {
    max-width: 760px;
    margin: 0 auto;
    padding: var(--space-lg) var(--space-md) var(--space-2xl);
}

.invite-page__intro {
    margin-bottom: var(--space-lg);
}

.invite-page__title {
    margin: 0 0 var(--space-xs);
    font-family: var(--font-display);
    font-weight: 500;
    font-size: clamp(1.7rem, 3.5vw, 2.2rem);
    letter-spacing: -0.01em;
}

.invite-page__subtitle {
    margin: 0;
    color: var(--color-text-muted);
    font-size: 1rem;
    max-width: 60ch;
    line-height: 1.5;
}

.invite-page__banner {
    margin-bottom: var(--space-lg);
}

.invite-form-card {
    margin-bottom: var(--space-xl);
    padding: var(--space-lg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
}

.invite-form-card__heading {
    margin: 0 0 var(--space-md);
    font-family: var(--font-display);
    font-weight: 500;
    font-size: 1.3rem;
    letter-spacing: -0.005em;
}

.invite-form-card .form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-md);
    margin-bottom: var(--space-md);
}

.invite-form-card .form-grid .form-group:nth-child(2) {
    grid-column: 1 / -1;
}

@media (max-width: 540px) {
    .invite-form-card .form-grid {
        grid-template-columns: 1fr;
    }
    .invite-form-card .form-grid .form-group:nth-child(2) {
        grid-column: auto;
    }
}

.people-list {
    margin-bottom: var(--space-xl);
}

.people-list__header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-md);
    flex-wrap: wrap;
    margin-bottom: var(--space-md);
}

.people-list__heading {
    margin: 0;
    font-family: var(--font-display);
    font-weight: 500;
    font-size: 1.25rem;
    letter-spacing: -0.005em;
    color: var(--color-text);
}

.people-list__hint {
    margin: 0;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

.people-list__items {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

.person-row {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    transition: border-color var(--duration-fast) var(--ease-out),
        background var(--duration-fast) var(--ease-out);
}

.person-row:hover {
    border-color: var(--color-border);
    background: var(--color-surface-alt);
}

.person-row__avatar {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    background: var(--color-accent-light);
    color: var(--color-text);
    font-family: var(--font-display);
    font-weight: 500;
    font-size: 1rem;
    letter-spacing: -0.01em;
}

.person-row__main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.person-row__identifier {
    color: var(--color-text);
    font-weight: 600;
    font-size: 0.95rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.person-row__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    align-items: center;
    color: var(--color-text-muted);
    font-size: 0.8125rem;
}

.person-row__channel {
    display: inline-flex;
    align-items: center;
    padding: 1px 0.5rem;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    background: var(--color-badge-muted);
    color: var(--color-badge-text-muted);
}

.person-row__channel--email {
    background: var(--color-badge-info);
    color: var(--color-badge-text-info);
}

.person-row__channel--phone {
    background: var(--color-badge-success);
    color: var(--color-badge-text-success);
}

.person-row__channel--telegram {
    background: var(--color-badge-info);
    color: var(--color-badge-text-info);
}

.person-row__role {
    color: var(--color-text-secondary);
    font-weight: 500;
}

.person-row__status {
    color: var(--color-text-muted);
    font-style: italic;
}

.person-row__action {
    flex: 0 0 auto;
    margin: 0;
}

.person-row__owner-tag {
    flex: 0 0 auto;
    color: var(--color-text-muted);
    font-size: 0.8125rem;
    font-style: italic;
}

.person-row--selectable {
    padding-left: var(--space-sm);
}

.person-row__select {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.25rem;
    cursor: pointer;
}

.person-row__select input[type="checkbox"] {
    width: 1.1rem;
    height: 1.1rem;
    margin: 0;
    accent-color: var(--color-primary);
    cursor: pointer;
}

.people-list__bulk {
    margin: 0;
}

.people-list__bulk-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    margin-top: var(--space-sm);
    padding: var(--space-sm) var(--space-md);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    background: var(--color-surface-alt);
    font-size: var(--text-sm);
}

.people-list__bulk-count {
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

.people-list__bulk-bar [data-bulk-submit][disabled] {
    opacity: 0.55;
    cursor: not-allowed;
}

.invite-page__back {
    margin: var(--space-xl) 0 0;
    text-align: center;
}

.invite-page__back a {
    color: var(--color-text-secondary);
    font-size: 0.95rem;
    text-decoration: none;
}

.invite-page__back a:hover {
    color: var(--color-text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

@media (max-width: 540px) {
    .person-row {
        flex-wrap: wrap;
    }
    .person-row__action {
        width: 100%;
    }
    .person-row__action .btn {
        width: 100%;
    }
}

/* ============================================================== */
/*  Settings layout — sticky table of contents                    */
/* ============================================================== */

.settings-layout {
    display: grid;
    grid-template-columns: 12rem 1fr;
    gap: var(--space-xl);
    align-items: start;
    max-width: 1080px;
    margin: 0 auto;
    padding: 0 var(--space-md);
    scroll-padding-top: var(--space-xl);
}

.settings-layout__main {
    min-width: 0;
}

.settings-toc {
    position: sticky;
    top: var(--space-md);
    padding: var(--space-md) var(--space-sm);
    border-left: 1px solid var(--color-border-light);
    align-self: start;
}

.settings-toc__label {
    margin: 0 0 var(--space-sm);
    padding-left: var(--space-sm);
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.settings-toc__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
}

.settings-toc__list li {
    margin: 0;
}

.settings-toc__link {
    display: block;
    padding: 0.4rem var(--space-sm);
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
    text-decoration: none;
    border-radius: var(--radius-sm);
    transition: color var(--duration-fast) var(--ease-out),
        background var(--duration-fast) var(--ease-out);
}

.settings-toc__link:hover {
    color: var(--color-text);
    background: var(--color-surface-alt);
}

.settings-toc__link--active {
    color: var(--color-text);
    background: var(--color-surface-alt);
    font-weight: 600;
}

/* Inline "Learn more" link inside form-help paragraphs */
.form-help__link {
    display: inline-block;
    margin-left: 0.25rem;
    color: var(--color-accent-text);
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
}

.form-help__link:hover {
    color: var(--color-text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.form-help__link:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

.settings-toc__link:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* Scroll-margin-top so anchored fieldsets clear the sticky page nav */
#section-general,
#section-channels,
#section-sharing,
#section-reminders,
#section-notifications,
#section-danger {
    scroll-margin-top: var(--space-xl);
}

@media (max-width: 900px) {
    .settings-layout {
        grid-template-columns: 1fr;
        gap: var(--space-md);
    }
    .settings-toc {
        position: static;
        padding: var(--space-sm) 0;
        border-left: none;
        border-bottom: 1px solid var(--color-border-light);
    }
    .settings-toc__list {
        flex-direction: row;
        flex-wrap: wrap;
        gap: var(--space-xs);
    }
    .settings-toc__link {
        padding: 0.35rem 0.65rem;
        border-left: none;
        border: 1px solid var(--color-border-light);
        border-radius: 999px;
        margin-left: 0;
    }
    .settings-toc__link:hover {
        border-color: var(--color-border);
    }
}

/* Two-tier book settings: quiet lead choices + a folded "more" disclosure.
   Lifted out of book_settings.html's inline <style> so it lives in the bundle
   (one cascade, one cache, lintable against token rules). Audit A-04. */
.settings-lead {
    max-width: 60ch;
    margin: var(--space-xl) auto var(--space-2xl);
    padding: 0 var(--space-md);
}
.settings-lead__header {
    margin-bottom: var(--space-lg);
}
.settings-lead h1 {
    font-family: var(--font-display);
    font-weight: 500;
    font-size: clamp(2rem, 3.5vw, 2.75rem);
    line-height: 1.15;
    color: var(--color-text);
    margin: 0 0 var(--space-xs);
}
.settings-lead__subtitle {
    font-family: var(--font-body);
    font-size: 1rem;
    color: var(--color-text-muted);
    margin: 0;
}
.settings-lead__subtitle em {
    font-style: italic;
    color: var(--color-text-secondary);
}
.settings-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 22rem);
    gap: var(--space-md) var(--space-lg);
    align-items: start;
    padding: var(--space-md) 0;
    border-bottom: 1px solid var(--color-border-light);
}
.settings-row:last-of-type {
    border-bottom: none;
}
.settings-row__text {
    min-width: 0;
}
.settings-row__label {
    font-family: var(--font-body);
    font-weight: 600;
    font-size: 1rem;
    color: var(--color-text);
    display: block;
    margin: 0 0 var(--space-xs);
}
.settings-row__help {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin: 0;
    line-height: 1.5;
}
.settings-row__control select,
.settings-row__control input[type="number"] {
    width: 100%;
}
.settings-row__error {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--color-primary-hover);
    margin: var(--space-xs) 0 0;
}
.settings-lead__actions {
    display: flex;
    justify-content: flex-end;
    margin-top: var(--space-lg);
}
.settings-more {
    max-width: 60ch;
    margin: 0 auto var(--space-2xl);
    padding: 0 var(--space-md);
}
.settings-more > summary {
    font-family: var(--font-body);
    font-size: 0.95rem;
    font-weight: 500;
    color: var(--color-primary-hover);
    cursor: pointer;
    padding: var(--space-md) 0;
    min-height: 44px;
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    list-style: none;
}
.settings-more > summary::-webkit-details-marker {
    display: none;
}
.settings-more > summary::before {
    content: "+";
    font-family: var(--font-display);
    font-size: 1.5rem;
    line-height: 1;
    color: var(--color-primary-text);
    transition: transform 200ms ease;
    display: inline-block;
}
.settings-more[open] > summary::before {
    content: "\2013"; /* en-dash glyph (not em-dash) */
}
.settings-more[open] > summary {
    border-bottom: 1px solid var(--color-border-light);
    margin-bottom: var(--space-lg);
}
.settings-more > summary:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 4px;
    border-radius: 2px;
}

@media (max-width: 640px) {
    .settings-row {
        grid-template-columns: 1fr;
        gap: var(--space-sm);
    }
}
/* ---- Contributor surfaces: moved from pages.css so /b/ can load app.css (2026-09-12) ----
   Every /b/ route serves static/css/app.css (the bundle minus pages.css), so
   any rule a contributor page needs lives here, PREPENDED: pages.css precedes
   books.css in main.css, so keeping these first preserves every cascade
   relation with the rest of this file. Guard:
   apps/quality/tests/test_css_bundle_split.py. */

/* ---------- Cover Image ---------- */
.book-cover-image {
    width: 100%;
    max-height: 300px;
    aspect-ratio: 16 / 5;
    object-fit: cover;
    border-radius: var(--radius-lg);
    margin-bottom: var(--space-lg);
    box-shadow: var(--shadow-md);
}

.back-link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    margin-top: var(--space-xl);
    transition: color var(--duration-fast) var(--ease-out);
}

.back-link::before {
    content: '\2190';
}

.back-link:hover {
    color: var(--color-primary-text);
}

/* ---------- Public Page ---------- */
.public-header {
    text-align: center;
    max-width: 700px;
    margin: 0 auto var(--space-xl);
    padding: var(--space-xl) var(--space-lg) var(--space-2xl);
    border-bottom: 1px solid var(--color-border-light);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
}

.public-header h1 {
    font-size: clamp(2.2rem, 5vw, 3.5rem);
    margin-bottom: var(--space-md);
}

.public-header p {
    color: var(--color-text-secondary);
    font-size: 1.05rem;
    max-width: none;
    margin-bottom: var(--space-xl);
    line-height: 1.7;
}

/* ---------- Public Page Branding ---------- */
.branding-wrapper {
    --color-primary-hover: var(--color-primary);
}

.branding-wrapper .btn-primary {
    background: var(--color-primary);
    border-color: var(--color-primary);
}

.branding-wrapper .btn-primary:hover {
    background: var(--color-primary-hover);
    filter: brightness(0.9);
}

.public-hero {
    width: 100%;
    max-height: 400px;
    overflow: hidden;
    margin-bottom: var(--space-lg);
}

.public-hero img {
    width: 100%;
    height: 100%;
    max-height: 400px;
    object-fit: cover;
    display: block;
}

.public-subtitle {
    font-family: var(--font-display);
    font-size: 1.25rem;
    color: var(--color-text-secondary);
    margin-top: var(--space-xs);
    margin-bottom: var(--space-sm);
}

.public-welcome {
    max-width: 640px;
    margin: var(--space-md) auto var(--space-lg);
    padding: var(--space-md) var(--space-lg);
    background: var(--color-bg-warm);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    font-size: 0.95rem;
    line-height: 1.6;
    color: var(--color-text-secondary);
}

/* ---------- Submission Methods ---------- */

.submission-methods {
    max-width: 700px;
    margin: 0 auto var(--space-xl);
    text-align: center;
}

.submission-methods__title {
    font-size: var(--text-xs);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-md);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.submission-methods__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: var(--space-md);
}

.submission-method {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-md);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
}

.submission-method__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    color: var(--color-primary-text);
    line-height: 1;
}

.submission-method__icon svg {
    width: 24px;
    height: 24px;
    opacity: 0.9;
}

.submission-method__label {
    font-weight: 600;
    font-size: 0.95rem;
}

.submission-method__instruction {
    font-size: var(--text-xs);
    color: var(--color-text-secondary);
    line-height: 1.4;
}

.submission-method__detail {
    font-size: var(--text-sm);
    font-weight: 600;
    word-break: break-all;
    color: var(--color-primary-text);
}

.submission-method__detail a {
    color: var(--color-primary-text);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    min-height: 44px;
}

.submission-method__detail a:hover {
    text-decoration: underline;
}

.public-powered-by {
    text-align: center;
    padding: var(--space-lg) 0;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

.public-powered-by a {
    color: var(--color-text-muted);
    text-decoration: underline;
}

/* ---------- Submission Methods (public book page) ---------- */

.submission-methods {
    max-width: 700px;
    margin: 0 auto var(--space-xl);
    padding: 0 var(--space-lg);
    text-align: center;
}

.submission-methods__details {
    text-align: center;
}

.submission-methods__toggle {
    font-family: var(--font-display);
    font-size: 1rem;
    color: var(--color-text-muted);
    cursor: pointer;
    padding: var(--space-sm) 0;
    letter-spacing: 0.02em;
}

.submission-methods__toggle:hover {
    color: var(--color-primary-text);
}

.submission-methods__title {
    font-family: var(--font-display);
    font-size: 1.15rem;
    color: var(--color-text-muted);
    margin-bottom: var(--space-md);
    font-weight: 400;
}

.submission-methods__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--space-md);
}

.submission-method {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-md);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
}

.submission-method__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    color: var(--color-primary-text);
    line-height: 1;
}

.submission-method__icon svg {
    width: 24px;
    height: 24px;
    opacity: 0.9;
}

.submission-method__label {
    font-weight: 600;
    font-size: 0.95rem;
    color: var(--color-text);
}

.submission-method__instruction {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    line-height: 1.4;
}

.submission-method__detail {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-primary-text);
    word-break: break-all;
}

.submission-method__detail a {
    color: var(--color-primary-text);
    text-decoration: none;
}

.submission-method__detail a:hover {
    text-decoration: underline;
}

.submission-methods__consent {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    line-height: 1.5;
    margin-top: var(--space-md);
    text-align: center;
}

.submission-methods__consent a {
    color: var(--color-text-secondary);
    text-decoration: underline;
}

/* ---------- Pagination ---------- */
.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-md);
    margin-top: var(--space-xl);
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border-light);
}

.pagination-info {
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

/* ── Footer Nav ──────────────────────────────────────────────────── */

.footer-nav {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-sm) var(--space-md);
    margin-top: var(--space-sm);
}

.footer-nav a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 var(--space-xs);
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: var(--text-sm);
}

.footer-nav a:hover {
    color: var(--color-primary-text);
}

/* /b/ routes: one quiet line, legal links only (T3, 2026-09-04). */
.footer--minimal {
    padding-top: var(--space-lg);
    padding-bottom: var(--space-lg);
}

.footer-nav-legal {
    font-size: var(--text-xs);
    margin-top: var(--space-sm);
}

.footer-nav-legal a {
    color: var(--color-text-muted);
    font-size: var(--text-xs);
}

/* ── Permalink / Share Page ──────────────────────────────────────── */

.permalink-page {
    max-width: 640px;
    margin: 0 auto;
    padding: var(--space-xl) var(--space-lg) var(--space-2xl);
    border-bottom: 1px solid var(--color-border-light);
}

.permalink-header {
    margin-bottom: var(--space-lg);
}

.permalink-book-link {
    font-family: var(--font-display);
    font-size: 1.1rem;
    color: var(--color-primary-text);
    text-decoration: none;
}

.permalink-book-link:hover {
    text-decoration: underline;
}

.permalink-card {
    margin-bottom: var(--space-xl);
}

.permalink-text {
    font-family: var(--font-display);
    font-size: 1.2rem;
    line-height: 1.7;
    max-width: 65ch;
    margin-inline: auto;
    margin-bottom: var(--space-md);
}

.permalink-media {
    position: relative; /* anchors the download overlay */
    /* #media-<pk> jumps (from an album thumbnail) clear the sticky header */
    scroll-margin-top: 80px;
    margin-bottom: var(--space-md);
}

.permalink-media img {
    width: 100%;
    height: auto;
    border-radius: var(--radius-md);
}

.permalink-meta {
    display: flex;
    justify-content: space-between;
    font-size: var(--text-sm);
    color: var(--color-text-muted);
}

.share-options {
    margin-bottom: var(--space-xl);
}

.share-options h2 {
    font-family: var(--font-display);
    font-size: 1.25rem;
    margin-bottom: var(--space-md);
}

.share-buttons {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
}

.share-downloads,
.share-embed {
    margin-top: var(--space-lg);
}

.share-more summary {
    min-height: 44px;
    display: flex;
    align-items: center;
    cursor: pointer;
    color: var(--color-primary-text);
}

.share-more summary:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    box-shadow: var(--shadow-glow);
    border-radius: var(--radius-md);
}

.permalink-footer {
    text-align: center;
    padding-top: var(--space-lg);
    border-top: 1px solid var(--color-border-light);
}

.permalink-footer a {
    color: var(--color-primary-text);
    text-decoration: none;
}

.permalink-footer a:hover {
    text-decoration: underline;
}

.share-icon {
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: 1rem;
    margin-left: auto;
}

.share-icon:hover {
    color: var(--color-primary-text);
}

/* ============================================================== */
/*  Members-only contribute lock state (on /b/<slug>/)            */
/* ============================================================== */

.contribute-hub-locked {
    margin-top: var(--space-md);
    padding: var(--space-md) var(--space-lg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface-alt);
    text-align: center;
}

.contribute-hub-locked__title {
    margin: 0 0 var(--space-xs);
    font-family: var(--font-display);
    font-weight: 500;
    font-size: 1.4rem;
    letter-spacing: -0.005em;
}

.contribute-hub-locked__copy {
    margin: 0 auto var(--space-sm);
    max-width: 42ch;
    color: var(--color-text-secondary);
    line-height: 1.55;
}

.contribute-hub-locked__action {
    margin: 0;
}

/* ---------- Book Grid & Cards ---------- */
.book-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: var(--space-lg);
}

.book-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    transition: box-shadow var(--duration-normal) var(--ease-out),
                transform var(--duration-normal) var(--ease-out),
                border-color var(--duration-normal) var(--ease-out);
    display: flex;
    flex-direction: column;
}

.book-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-lg);
    border-color: var(--color-border);
}

.book-card:focus-within {
    box-shadow: var(--shadow-glow);
    border-color: var(--color-primary);
}

.book-card-image {
    display: block;
    width: 100%;
    height: 140px;
    overflow: hidden;
}

.book-card-image img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform var(--duration-normal) var(--ease-out);
}

.book-card:hover .book-card-image img {
    transform: scale(1.03);
}

.book-card-body {
    padding: var(--space-xl);
}

.book-card h3 {
    /* User-authored proper noun — keepsake "Serif-for-Memory" rule. */
    font-family: var(--font-display);
    font-weight: 700;
    letter-spacing: -0.01em;
    font-size: 1.3rem;
    margin-bottom: var(--space-sm);
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

.book-card h3 a {
    color: var(--color-text);
    text-decoration: none;
    transition: color var(--duration-fast) var(--ease-out);
}

.book-card h3 a:hover {
    color: var(--color-primary-text);
}

.book-card p {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    line-height: 1.6;
    flex: 1;
    max-width: none;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
}

.book-card-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: var(--space-md);
    padding-top: var(--space-md);
    border-top: 1px solid var(--color-border-light);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

/* ---------- Book card: activity strip ---------- */
.book-card__activity {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-xs) 0.4em;
    font-family: var(--font-body);
    font-size: var(--text-xs);
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
    margin-top: var(--space-xs);
}

.book-card__activity-new strong {
    color: var(--color-primary-text);
    font-weight: 600;
}

.book-card__activity-sep {
    color: var(--color-text-muted);
}

.book-card__activity-total {
    color: var(--color-text);
    font-weight: 500;
}

.book-card__activity-last {
    color: var(--color-text-muted);
}

/* ---------- Book card: pin toggle (shelf rule: pinned first) ---------- */
.book-card__pin {
    margin-top: var(--space-md);
}

.book-card__pin-btn[aria-pressed="true"] {
    border-color: var(--color-primary);
    color: var(--color-primary-text);
}

/* ---------- Shelf sort (the /books/ list order control) ---------- */
.shelf-sort {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-sm);
    margin-bottom: var(--space-lg);
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
}

/* ---------- Book card: cover image + NEW badge ---------- */
.book-card-image--cover {
    position: relative;
}

.book-card__new-badge {
    position: absolute;
    top: var(--space-sm);
    right: var(--space-sm);
    background: var(--color-warning);
    color: var(--color-text);
    font-family: var(--font-body);
    font-size: 0.68rem;
    font-weight: 700;
    padding: 0.2rem 0.55rem;
    border-radius: 100px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    z-index: 2;
}

/* ---------- Badges ---------- */
.badge {
    display: inline-flex;
    align-items: center;
    padding: 0.2rem 0.65rem;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-radius: 100px;
    line-height: 1.4;
}

.badge-active {
    background: var(--color-badge-success);
    color: var(--color-badge-text-success);
}

.badge-closed {
    background: var(--color-badge-warning);
    color: var(--color-badge-text-warning);
}

.badge-archived,
.badge-muted {
    background: var(--color-badge-muted);
    color: var(--color-badge-text-muted);
}

.badge-private {
    background: var(--color-badge-info);
    color: var(--color-badge-text-info);
}

.memory-card-private {
    background: var(--color-bg-info);
    border: 1px solid color-mix(in srgb, var(--color-info) 25%, transparent);
}

.badge-pending {
    background: var(--color-badge-warning);
    color: var(--color-badge-text-warning);
}

.badge-pinned {
    background: var(--color-badge-warning-strong);
    color: var(--color-badge-text-warning);
}

.badge-channel {
    background: var(--color-bg-warm);
    color: var(--color-text-secondary);
}

.badge-owner {
    background: var(--color-badge-info);
    color: var(--color-badge-text-info);
    text-transform: none;
}

/* Semantic status badges (outreach contact/template lists). Share the
   --color-badge-* / --color-badge-text-* pairs, which are theme-aware and
   AA on the pill tint. Without these the classes rendered as unstyled,
   colorless pills. Audit 2026-06-22. */
.badge-success,
.badge-approved {
    background: var(--color-badge-success);
    color: var(--color-badge-text-success);
}

.badge-warning {
    background: var(--color-badge-warning);
    color: var(--color-badge-text-warning);
}

.badge-rejected {
    background: var(--color-badge-error);
    color: var(--color-badge-text-error);
}

/* ---------- Shareable Link ---------- */
.share-link {
    display: flex;
    gap: var(--space-sm);
    align-items: center;
    max-width: 600px;
}

.share-link input[type="text"],
.share-link textarea {
    flex: 1;
    min-width: 0;
    padding: 0.7rem 0.9rem;
    font-family: var(--font-body);
    font-size: 1rem;
    min-height: 44px;
    color: var(--color-text);
    background: var(--color-bg);
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-md);
}

/* The embed-code textarea is multi-line; align the Copy button to its top
   edge so it does not float to the vertical middle of a tall box. */
.share-link:has(textarea) {
    align-items: flex-start;
}

.share-link textarea {
    resize: vertical;
    line-height: 1.4;
}

.share-link input[type="text"]:focus-visible,
.share-link textarea:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-border-focus);
    box-shadow: var(--shadow-glow);
}

.share-code {
    font-family: var(--font-display);
    font-size: clamp(2.5rem, 5vw, 4rem);
    font-weight: 700;
    color: var(--color-primary-text);
    letter-spacing: 0.05em;
    text-align: center;
    padding: var(--space-lg) 0;
}

/* ---------- Memory Stream (Public) ---------- */
.memory-stream {
    display: flex;
    flex-direction: column;
    gap: var(--space-lg);
    margin-top: var(--space-xl);
    max-width: none;
}

.memory-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-lg) var(--space-xl);
    box-shadow: var(--shadow-sm);
    transition: box-shadow var(--duration-normal) var(--ease-out),
                transform var(--duration-normal) var(--ease-out);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
}

/* Stagger card entrance by position */
.memory-card:nth-child(2) { animation-delay: 80ms; }
.memory-card:nth-child(3) { animation-delay: 160ms; }
.memory-card:nth-child(4) { animation-delay: 240ms; }
.memory-card:nth-child(5) { animation-delay: 320ms; }

/* Skip rendering for cards below initial fold */
.memory-card:nth-child(n+7) {
    content-visibility: auto;
    contain-intrinsic-size: auto 200px;
}

/* Reading isn't an interactive gesture in a keepsake. The page is not
   a clickable card — it's a story to read. Hover-lift / shadow-shift
   was app-y on a brand surface (SaaS card affordance), so the
   ``.memory-card:hover`` state has been removed. Focus-visible rings
   on interactive children (share link, media controls) still surface
   keyboard a11y. 2026-05-23 polish. */

/* The 65ch Line Rule (DESIGN.md), expressed in a unit every child of the card
   resolves IDENTICALLY.

   The byline and the body were both capped at `65ch` and both centred, with a
   comment saying they shared a visual axis. They did not: `ch` resolves against
   each element's OWN font-size, so the 0.95rem byline got a materially narrower
   column than the 1.2rem body and, being centred, started further right. Add
   the footer link — pinned to the card's far edge rather than the text
   column — and the card had three different left edges with a marooned link in
   43% of dead space. Design critique 2026-09-08. */
.memory-card {
    --memory-measure: 37rem;
    /* The CARD is capped too, not only its children. Capping the children
       alone left a text-only memory sitting in a full-stream-width box with
       its prose in a 37rem column inside it -- a banner around a paragraph,
       and the second outcome Part 5 stated and did not deliver.
       This caps EVERY card, media included: a photo now sits in the same
       column as the prose rather than running wider than the words beside it,
       which is the shared-axis rule this measure exists for. Images already
       carry max-width: 100%, so they scale down rather than overflow. */
    max-width: calc(var(--memory-measure) + 2 * var(--space-xl));
    margin-inline: auto;
}

.memory-card-text {
    font-family: var(--font-display);
    font-size: 1.2rem;
    line-height: 1.7;
    color: var(--color-text);
    max-width: var(--memory-measure);
    margin-inline: auto;
    font-weight: 400;
    overflow-wrap: break-word;
    word-break: break-word;
}

.memory-card-media,
.memory-card-audio,
.memory-card-video {
    position: relative;
}

.memory-card-download {
    position: absolute;
    bottom: var(--space-sm);
    right: var(--space-sm);
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.65rem;
    border-radius: var(--radius-sm);
    background: color-mix(in srgb, var(--color-text) 55%, transparent);
    /* NOTE: backdrop-filter kept intentionally — this is an overlay on
       user-uploaded media where the blur is the point, not decoration. */
    backdrop-filter: blur(4px);
    color: var(--color-bg);
    text-decoration: none;
    font-size: var(--text-xs);
    font-family: var(--font-body);
    letter-spacing: 0.02em;
    line-height: 1;
    opacity: 0.85;
    transition: opacity var(--duration-fast), background var(--duration-fast);
}

.memory-card-download:hover,
.memory-card-download:focus-visible {
    opacity: 1;
    background: color-mix(in srgb, var(--color-text) 80%, transparent);
    color: var(--color-bg);
}

.memory-card-download .download-icon {
    font-size: var(--text-sm);
}

.bulk-download-bar {
    display: flex;
    justify-content: flex-end;
    margin-bottom: var(--space-md);
}

.bulk-download-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

/* Unified utility row for the public book page (above the memory
   stream). Pairs "View all photos →" (left, prominent) with
   "Download all media" (right, quiet). Was previously two separate
   wrappers stacked: ``.public-gallery-link-wrap`` (left-aligned p)
   and ``.bulk-download-bar`` (right-aligned flex). Visually they
   read as orphans. Layout fix unifies them in one row using
   ``justify-content: space-between``; on narrow viewports
   ``flex-wrap: wrap`` stacks them with the prominent gallery link
   on top.

   Touch-target floor: ``min-height: 44px`` covers the row so a thumb
   in the empty centre of the row still has a hit zone (the links
   inside also carry their own 44px floor from their existing rules).
*/
.book-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md) var(--space-lg);
    margin: 0 0 var(--space-xl);
    min-height: 44px;
}

.book-actions__secondary {
    /* "Download all media" is the utilitarian half of the row.
       Demote from button-shape to text-link weight so it does not
       compete with the keepsake-feeling gallery link. Quiet sans,
       muted color, terracotta-on-hover (the brand's "yes click me"
       tell). 44px min-height for WCAG 2.5.8. */
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    min-height: 44px;
    padding: var(--space-xs) 0;
    font-family: var(--font-body);
    font-size: 0.95rem;
    font-weight: 500;
    color: var(--color-text-muted);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: border-color var(--duration-fast) var(--ease-out),
        color var(--duration-fast) var(--ease-out);
}

.book-actions__secondary:hover,
.book-actions__secondary:focus-visible {
    color: var(--color-primary-text);
    border-bottom-color: var(--color-primary);
}

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

.memory-card-media {
    margin-top: var(--space-md);
}

.memory-card-media img {
    max-width: 100%;
    height: auto;
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    transition: transform var(--duration-normal) var(--ease-out);
}

.memory-card:hover .memory-card-media img {
    transform: scale(1.01);
}

/* Multi-photo album grid (bulk-import same-day grouping + any all-image
   submission with >4 photos). Static layout. */
.memory-card-album {
    display: grid;
    /* 140px floor keeps preview thumbnails legible: ~2-up on a phone,
       3-5-up on a wide card. The full-size view lives on the permalink. */
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: var(--space-xs);
    margin: var(--space-sm) 0;
}
.memory-card-album__tile {
    position: relative;
    display: block; /* it is a link to that photo on the permalink */
    aspect-ratio: 1 / 1;
    overflow: hidden;
    border-radius: var(--radius-sm);
}
.memory-card-album__img,
.memory-card-album__tile img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    transition: transform var(--duration-normal) var(--ease-out);
}
.memory-card-album__tile:hover .memory-card-album__img,
.memory-card-album__tile:focus-visible .memory-card-album__img {
    transform: scale(1.04); /* gentle zoom signals the tile is tappable */
}
/* Full-width "View all N photos ->" bar under the grid. */
.memory-card-album__viewall {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin: 0 0 var(--space-sm);
    font-weight: 600;
    color: var(--color-primary-text);
    text-decoration: none;
}
.memory-card-album__viewall:hover {
    color: var(--color-primary-text-hover);
}
.memory-card-album__viewall-arrow {
    transition: transform var(--duration-fast) var(--ease-out);
}
.memory-card-album__viewall:hover .memory-card-album__viewall-arrow {
    transform: translateX(3px);
}
@media (prefers-reduced-motion: reduce) {
    .memory-card-album__img,
    .memory-card-album__viewall-arrow {
        transition: none;
    }
    .memory-card-album__tile:hover .memory-card-album__img,
    .memory-card-album__tile:focus-visible .memory-card-album__img,
    .memory-card-album__viewall:hover .memory-card-album__viewall-arrow {
        transform: none;
    }
}

/* ── Live Photo (Apple) ─────────────────────────────────────────────
   The still (responsive_img) stacked UNDER a muted-loop <video> of the
   motion, plus a frosted LIVE badge. The video sits absolutely on top of
   the still and is hidden until .live-photo--playing (JS adds it on
   hover / press-hold). Playback logic: static/js/live-photo.js.
   --------------------------------------------------------------------- */
.live-photo {
    position: relative;
    display: block;
    border-radius: var(--radius-md);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    /* Hover/hold affordance; reduced-motion users get tap-to-toggle. */
    cursor: pointer;
}

/* The still rides the normal image rules so it matches plain photos. */
.live-photo__still {
    display: block;
}

.live-photo__still img,
.live-photo__still picture,
.live-photo__img {
    display: block;
    width: 100%;
    height: auto;
    /* The wrapper clips the corners; drop the per-image radius/shadow so the
       video can register exactly over the still. */
    border-radius: 0;
    box-shadow: none;
}

/* The motion overlays the still pixel-for-pixel; fades in when playing. */
.live-photo__video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--duration-fast) var(--ease-out);
}

.live-photo--playing .live-photo__video {
    opacity: 1;
}

/* Frosted dark pill, top-left — the iOS "LIVE" treatment. */
.live-photo__badge {
    position: absolute;
    top: var(--space-sm);
    left: var(--space-sm);
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    min-height: 24px;
    padding: 0.2rem 0.55rem;
    border-radius: 999px;
    /* color-mix fallback then override (overlay on user media — see policy). */
    background: rgba(26, 22, 20, 0.55);
    background: color-mix(in srgb, var(--color-text) 55%, transparent);
    backdrop-filter: blur(4px);
    color: var(--color-text-on-primary);
    font-family: var(--font-body);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    line-height: 1;
    text-transform: uppercase;
    z-index: 1;
    transition: background var(--duration-fast) var(--ease-out);
}

/* Concentric-ring dot — the Live Photo glyph, simplified. */
.live-photo__badge-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    border: 1.5px solid currentColor;
    /* Inner solid dot via the box-shadow trick (no extra element). */
    box-shadow: inset 0 0 0 1.5px transparent, 0 0 0 0 currentColor;
    position: relative;
}
.live-photo__badge-dot::after {
    content: "";
    position: absolute;
    inset: 1.5px;
    border-radius: 50%;
    background: currentColor;
}

/* When the motion is playing the dot pulses gently (Apple's live cue). */
.live-photo--playing .live-photo__badge {
    background: color-mix(in srgb, var(--color-text) 72%, transparent);
}
.live-photo--playing .live-photo__badge-dot {
    animation: live-photo-pulse 1.2s var(--ease-out) infinite;
}

@keyframes live-photo-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.45; }
}

/* Keyboard focus on the badge (it is role="button" tabindex="0" when playable). */
.live-photo__badge:focus-visible {
    outline: 2px solid var(--color-text-on-primary);
    outline-offset: 2px;
}

/* Static badge variant used on gallery thumbnails (no video / no JS): the
   motion plays on the permalink the tile links to. */
.live-photo__badge--static {
    cursor: default;
}

/* Reduced motion: no pulse, no opacity transitions; the badge becomes the
   explicit tap-to-toggle affordance (live-photo--reduced is set by JS). The
   video still cross-fades opacity on toggle, which is fine — it's a content
   change the user explicitly triggered, not autoplay. */
@media (prefers-reduced-motion: reduce) {
    .live-photo--playing .live-photo__badge-dot {
        animation: none;
    }
}

.memory-card-original {
    margin-top: var(--space-xs);
}

.memory-card-original__toggle {
    cursor: pointer;
}

.memory-card-original__text {
    margin-top: var(--space-xs);
    opacity: 0.8;
}

/* Byline header (2026-05-23 polish): contributor name + date sit
   ABOVE the story body so the reader knows the source before the
   prose starts. Cormorant italic per the Serif-for-Memory rule
   (DESIGN.md treats contributor names AND date stamps as serif
   territory). Both in muted ink so the byline whispers rather than
   shouts; the story itself is the headline. Middle dot in the same
   muted color to avoid a third visual register.
*/
.memory-card-byline {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0 var(--space-sm);
    margin: 0 0 var(--space-md);
    font-family: var(--font-display);
    font-style: italic;
    font-size: 0.95rem;
    line-height: 1.4;
    /* Shares the story column's axis. See --memory-measure: capping this in
       `ch` looked like it matched the body and silently did not. */
    max-width: var(--memory-measure);
    margin-inline: auto;
}

.memory-card-author {
    font-weight: 500;
    color: var(--color-text-secondary);
}

.memory-card-byline__sep {
    color: var(--color-text-muted);
}

.memory-card-date {
    font-weight: 400;
    color: var(--color-text-muted);
    font-variant-numeric: oldstyle-nums;
}

/* Footer is now share-link only (author + date moved to the byline
   header above). Right-aligned, no border-top, no padding-top — the
   share icon sits as a small quiet affordance at the end of each
   memory rather than as full-width chrome.
*/
.memory-card-footer {
    display: flex;
    /* Shares the LEFT edge of the byline and the prose. Right-aligned, the
       action floated away from the column it belongs to and read as chrome
       rather than as the end of that memory -- the outcome Part 5 stated and
       did not deliver. */
    justify-content: flex-start;
    max-width: var(--memory-measure);
    margin-inline: auto;
    width: 100%;
    margin-top: var(--space-xs);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
}

.memory-card-share {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    min-height: 44px;
    padding: 0 var(--space-sm);
    margin-right: calc(-1 * var(--space-sm));
    border-radius: var(--radius-md);
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
    font-weight: 500;
    text-decoration: none;
    transition: color var(--duration-fast) var(--ease-out),
                background var(--duration-fast) var(--ease-out);
}
.memory-card-share:hover { color: var(--color-primary-text); background: var(--color-primary-glow); }
/* A real ring, not the glow alone. --shadow-glow measures ~1.16:1 against
   these surfaces, far under the 3:1 WCAG 1.4.11 asks of a non-text indicator,
   so a keyboard user could not see where they were. --color-border-focus is
   measured by test_focus_indicators_clear_the_contrast_floor (5.78:1 light,
   3.22:1 dark on a card); the glow stays as the decorative half. */
.memory-card-share:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    box-shadow: var(--shadow-glow);
}

.memory-card:not(:last-child)::after {
    content: "";
    display: none;
}

/* ---------- Pinned Card ---------- */
.memory-card-pinned {
    border: 1.5px solid var(--color-primary-light);
    background:
        linear-gradient(135deg, var(--color-primary-glow) 0%, transparent 50%),
        var(--color-bg-card);
    box-shadow: var(--shadow-md);
    position: relative;
}

.memory-card-pinned:hover {
    box-shadow: var(--shadow-lg);
}

.memory-card-pin-accent {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    margin-bottom: var(--space-md);
}

.memory-card-pin-icon {
    width: 16px;
    height: 16px;
    display: inline-block;
    position: relative;
}

/* CSS-only pin icon */
.memory-card-pin-icon::before {
    content: '';
    position: absolute;
    top: 2px;
    left: 4px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--color-primary);
}

.memory-card-pin-icon::after {
    content: '';
    position: absolute;
    top: 9px;
    left: 7px;
    width: 2px;
    height: 6px;
    background: var(--color-primary);
    border-radius: 0 0 1px 1px;
}

.memory-card-pin-label {
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-primary-text);
}

.memory-card-pinned .memory-card-text {
    font-size: 1.3rem;
}

/* ---------- Media Processing Status ---------- */
.memory-card-media-status {
    margin-top: var(--space-md);
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    text-align: center;
}
.memory-card-media-status--pending {
    background: var(--color-bg-warm);
    color: var(--color-text-secondary);
}
.memory-card-media-status--failed {
    background: color-mix(in srgb, var(--color-error) 8%, transparent);
    color: var(--color-text-on-bg-error);
}

/* ---------- Video Player Status ---------- */
.video-player__pending,
.video-player__failed {
    padding: var(--space-md);
    border-radius: var(--radius-md);
    text-align: center;
    font-size: var(--text-sm);
}
.video-player__pending {
    background: var(--color-bg-warm);
    color: var(--color-text-secondary);
}
.video-player__failed {
    background: color-mix(in srgb, var(--color-error) 8%, transparent);
    color: var(--color-text-on-bg-error);
}

/* ---------- Video in Memory Cards ---------- */
.memory-card-video {
    margin-top: var(--space-md);
}

.video-player video,
.video-player__native {
    width: 100%;
    max-width: 100%;
    border-radius: var(--radius-md);
    background: var(--color-text);
}

/* ---------- Audio in Memory Cards ---------- */
.memory-card-audio {
    margin-top: var(--space-md);
}

.audio-player__native {
    width: 100%;
    border-radius: var(--radius-md);
}

.audio-transcript {
    margin-top: var(--space-sm);
}

.audio-transcript__toggle {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    cursor: pointer;
}

.audio-transcript__text {
    margin-top: var(--space-sm);
    padding: var(--space-md);
    background: var(--color-bg-warm);
    border-radius: var(--radius-md);
    font-size: 0.95rem;
    line-height: 1.7;
    color: var(--color-text-secondary);
    font-style: italic;
    white-space: pre-wrap;
}

.audio-transcript__pending {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    font-style: italic;
    margin-top: var(--space-sm);
}

.audio-transcript__failed {
    font-size: var(--text-xs);
    color: var(--color-text-on-bg-error);
    margin-top: var(--space-sm);
}

/* ---------- Moderation Queue ---------- */
.mod-queue {
    display: flex;
    flex-direction: column;
    gap: var(--space-lg);
}

.mod-item {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-xl);
    box-shadow: var(--shadow-sm);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

.mod-item--focused {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-glow);
}

/* Moderation toast */
/* Toasts STACK. Both creators used to append their own position: fixed element
   at identical bottom/left/z-index, so a second toast landed exactly on the
   first while the first's dismissal timer ran on underneath -- its Undo covered
   and unclickable for the rest of its window. That became a real defect rather
   than a curiosity when the draft-lifecycle work made two live Undos a
   SUPPORTED state (ModReload counts outstanding undos precisely so one cannot
   abort another). The container owns the position; each toast is a row in it. */
.mod-toast-stack {
    position: fixed;
    /* Above the home indicator on notched iPhones (viewport-fit=cover). */
    bottom: calc(var(--space-lg) + env(safe-area-inset-bottom, 0px));
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-xs);
    z-index: 150;
    /* The container spans the width it needs; only the toasts take pointers,
       so the empty column never swallows a click on the page beneath. */
    pointer-events: none;
}

.mod-toast {
    position: relative;
    transform: translateY(20px);
    opacity: 0;
    padding: var(--space-sm) var(--space-md) var(--space-sm) var(--space-lg);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    font-size: var(--text-sm);
    color: var(--color-text);
    z-index: 150;
    transition: opacity var(--duration-normal) var(--ease-out),
                transform var(--duration-normal) var(--ease-out);
    pointer-events: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-md);
    width: max-content;
    max-width: calc(100vw - 2 * var(--space-md));
}

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

/* Undo is a real 44px target, not an underlined word (WCAG 2.5.8 / HIG). */
.mod-toast__undo {
    flex: none;
    min-height: 44px;
    padding: 0 var(--space-md);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg);
    cursor: pointer;
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-primary-text);
    white-space: nowrap;
    transition: background var(--duration-fast) var(--ease-out);
}
.mod-toast__undo:hover { background: var(--color-primary-glow); }
/* Same floor as .memory-card-share. This one matters twice over: Undo is
   time-limited, so a keyboard user who cannot see the focus ring loses the
   action entirely when the toast dismisses. */
.mod-toast__undo:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    box-shadow: var(--shadow-glow);
}

/* Fallback rgba() declarations precede color-mix() so browsers below
   Chrome 111 / Safari 16.4 / Firefox 113 (which drop the unrecognised
   declaration) keep a solid border with the right hue. Modern browsers
   override with the color-mix() value below. */
.mod-toast.success {
    background: var(--color-bg-success);
    border: 1px solid rgba(94, 139, 101, 0.30);
    border: 1px solid color-mix(in srgb, var(--color-success) 30%, transparent);
}
.mod-toast.info {
    background: var(--color-bg-info);
    border: 1px solid rgba(122, 107, 102, 0.30);
    border: 1px solid color-mix(in srgb, var(--color-info) 30%, transparent);
}
.mod-toast.error {
    background: var(--color-bg-error);
    border: 1px solid rgba(192, 80, 62, 0.30);
    border: 1px solid color-mix(in srgb, var(--color-error) 30%, transparent);
}

/* Inline moderation preview */
.mod-preview {
    background: var(--color-bg);
    border: 1px dashed var(--color-border-light);
    border-radius: var(--radius-md);
    padding: var(--space-lg);
    margin-top: var(--space-md);
}

/* Keyboard hints */
.kbd-hints {
    margin-bottom: var(--space-md);
}

.kbd-hints kbd {
    display: inline-block;
    padding: 0.1em 0.45em;
    font-family: var(--font-body);
    font-size: 0.78rem;
    font-weight: 600;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    line-height: 1.4;
}

/* Hide keyboard-shortcut hints on touch viewports — J/K/A/R/X are
   useless without a physical keyboard and the row eats moderation-
   queue header space on mobile. */
@media (max-width: 768px) {
    .kbd-hints {
        display: none;
    }
}

/* kbd-hints disclosure (moderation queue only) — hides the shortcut
   row behind a <details> summary so Linda only sees it when she asks.
   min-height 44px satisfies WCAG 2.5.8 touch target on the summary
   control without inflating the visible text size.
   Moved from apps/moderation/templates/moderation/submissions.html
   <style> (2026-08 critique-color-fixes Task 4). */
.kbd-hints-disclosure { margin: 0.5rem 0 1rem; }
.kbd-hints-disclosure > summary {
    cursor: pointer;
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    list-style: none;
    padding: 0.25rem 0;
    min-height: 44px;
    display: flex;
    align-items: center;
}
.kbd-hints-disclosure > summary::-webkit-details-marker { display: none; }
.kbd-hints-disclosure > summary::before {
    content: "▸ ";
    display: inline-block;
    transition: transform 120ms ease-out;
}
.kbd-hints-disclosure[open] > summary::before { content: "▾ "; }
.kbd-hints-disclosure .kbd-hints { margin-top: 0.25rem; }

.mod-item-media {
    margin: var(--space-sm) 0;
    max-width: min(100%, 300px);
}

.mod-item-media picture,
.mod-preview .memory-card-media picture {
    display: block;
    max-width: 100%;
}

.mod-preview .memory-card-media {
    max-width: min(100%, 42rem);
}

.mod-item-image,
.mod-preview .memory-card-media img {
    display: block;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: min(70vh, 32rem);
    object-fit: contain;
    border-radius: var(--radius-sm);
}

/* Tier 1 — Identity row.
   The header is a single line: contributor identity (left) and the
   primary moderation status badge (right). Everything else (channel,
   private/pinned/note flags) is folded into quiet text qualifiers
   inside .mod-item-identity__meta so they no longer compete with the
   real status. See _submission_row.html. */
.mod-item-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-md);
    margin-bottom: var(--space-md);
    font-size: var(--text-sm);
}

.mod-item-identity {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-sm);
    min-width: 0; /* allow ellipsis on long contributor names */
    flex: 1 1 auto;
}

.mod-item-identity strong {
    /* User-authored proper noun — keepsake "Serif-for-Memory" rule. */
    font-family: var(--font-display);
    letter-spacing: -0.01em;
    color: var(--color-text);
    font-size: 0.95rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 300px;
}

.mod-item-identity__email {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

.mod-item-identity__email::before {
    content: "·";
    margin-right: var(--space-sm);
    color: var(--color-text-muted);
    opacity: 0.6;
}

.mod-item-identity__meta {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-xs);
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    line-height: 1.4;
}

.mod-item-identity__meta > span[aria-hidden="true"] {
    opacity: 0.6;
}

.mod-item-identity__qualifier {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    color: var(--color-text-secondary);
    font-weight: 500;
}

.mod-item-identity__qualifier > span[aria-hidden="true"] {
    font-size: 0.85em;
    line-height: 1;
}

/* Tier 2 — Story body. Generous reading rhythm; nothing competes for
   attention except the text and media.

   2026-09-08: the memory itself is set in the DISPLAY serif here, reversing
   the 2026-05-18 flip to Outfit. That flip's stated reason was that
   "Serif-for-Memory applies to titles + contributor names + story titles, NOT
   body prose" — but the public memory card's body prose is
   `.memory-card-text { font-family: var(--font-display) }`, so the premise did
   not match the surface it was justified against. The owner was judging prose
   in form-field type and publishing it in book type, and so could not see what
   she was actually approving.

   Scoped to `.mod-item-body` ONLY. `.mod-item p` deliberately keeps the body
   font: those paragraphs are UI chrome (the approve hint, the private note,
   the set-aside reason), not the memory, and serif would blur that line. */
/* Interface chrome first, memory prose second. ORDER IS LOAD-BEARING.
   `.mod-item-body` holds RENDERED MARKDOWN, so the actual words live in nested
   <p> children. `.mod-item p` and `.mod-item-body p` have identical
   specificity, so whichever is declared last wins — and with the chrome rule
   last, the serif applied to a wrapper whose text was all in sans children.
   The first attempt at this change therefore did nothing visible. */
.mod-item p {
    font-family: var(--font-body);
    font-size: 1.1rem;
    line-height: 1.7;
    color: var(--color-text);
    max-width: none;
    margin-bottom: var(--space-md);
}

/* The dense list stays in the BODY font, deliberately.
   2026-09-08: this was briefly switched to the display serif so the owner could
   "see what she is approving". That was solving an already-solved problem at a
   real cost. The Preview control on every pending row renders
   submissions/partials/_submission_card.html -- the ACTUAL public card, serif,
   at the public measure -- so the published appearance is one click away and
   always has been. Meanwhile this list is an INDEX: its job is scanning many
   rows to triage, and serif is measurably worse at that.
   The swipe deck is the opposite case (one memory, on a card, being read rather
   than scanned) and does use the serif -- see .deck-card__body.
   The 2026-05-18 flip to Outfit recorded a justification that was factually
   wrong (it claimed the public card's body prose is sans; it is not). The
   decision was still right; only its stated reason was not. */
.mod-item-body {
    /* The public card's reading measure. Left uncapped, a memory ran the full
       width of the row. */
    max-width: var(--memory-measure, 37rem);
}

/* Tier 3 — Actionable status callouts.
   ONE callout per problem class — never a stack of badges. Severity:
     --muted : routine in-flight (transcribing, processing) — soft warm
     --warn  : the user should know but can still approve (flag warning)
     --error : approval is technically possible but the file is broken
               (censure error). */
.mod-callout {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin: var(--space-sm) 0;
    padding: 0.55rem var(--space-md);
    border-radius: var(--radius-sm);
    font-size: var(--text-sm);
    line-height: 1.4;
}

.mod-callout__dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
    opacity: 0.55;
    animation: pulse-recording 1.8s ease-in-out infinite;
}

.mod-callout__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
    background: currentColor;
    color: var(--color-bg-card);
    font-family: var(--font-body);
    font-size: var(--text-xs);
    font-weight: 700;
    line-height: 1;
    flex-shrink: 0;
}

.mod-callout__body {
    display: flex;
    flex-direction: column;
    gap: 0.05rem;
    flex: 1 1 auto;
    min-width: 0;
}

.mod-callout__label {
    font-weight: 600;
}

.mod-callout__detail {
    color: var(--color-text-secondary);
    font-size: var(--text-xs);
    font-weight: 400;
}

.mod-callout--muted {
    background: var(--color-badge-muted);
    color: var(--color-badge-text-muted);
}

.mod-callout--warn {
    /* Solid semantic tint + text-on-bg pairing is verified AA together
       (tokens.css). The prior 10%-transparent color-mix sat darker than
       the solid token and, combined with the detail opacity below, dropped
       detail copy to ~3.2:1. No fallback needed — these are flat hex tokens. */
    background: var(--color-bg-warning);
    color: var(--color-text-on-bg-warning);
}

.mod-callout--error {
    background: var(--color-bg-error);
    color: var(--color-text-on-bg-error);
}

.mod-callout--error .mod-callout__detail,
.mod-callout--warn .mod-callout__detail {
    /* Full-strength color (AA on the solid tint); the label leads the eye
       via its 600 weight, so opacity de-emphasis is no longer needed. */
    color: inherit;
}

.mod-item-actions {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
    padding-top: var(--space-md);
    border-top: 1px solid var(--color-border-light);
}

/* Per-row "Reason (optional)" input (id="reject-reason-*", the only
   input[type="text"] inside .mod-item-actions -- verified against
   apps/moderation/templates/moderation/partials/_submission_row.html)
   had no rule at all and rendered at the 13.3px UA default (iOS
   focus-zoom). ONE rule for this element -- kept the compound selector
   so it still wins on specificity if a lower-specificity .mod-item-actions
   rule is ever reintroduced nearby, and folded in the transition/outline
   this element used to get from the old, now-deleted, plain
   .mod-item-actions input[type="text"] rule. */
.mod-item-actions input[type="text"].mod-reject-input {
    font-family: var(--font-body);
    font-size: 1rem;
    min-height: 44px;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-card);
    color: var(--color-text);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}
.mod-item-actions input[type="text"].mod-reject-input:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-primary);
    box-shadow: var(--shadow-glow);
}

.mod-item-actions form {
    display: inline-flex;
    align-items: center;
    gap: var(--space-sm);
}

.mod-filters {
    display: flex;
    gap: var(--space-sm);
    margin-bottom: var(--space-lg);
    flex-wrap: wrap;
}

.mod-filters__count {
    margin-left: var(--space-xs);
    padding: 0 var(--space-xs);
    border-radius: var(--radius-sm);
    background: color-mix(in srgb, currentColor 14%, transparent);
    font-size: 0.85em;
    font-variant-numeric: tabular-nums;
}

/* Button variants for moderation.

   Adding a memory to the book is the PRIMARY action of this product, so it
   wears the product's accent, exactly like every other primary action
   (.btn-primary). It used to be a solid green sitting beside two red-outlined
   buttons, which is the visual language of a spam console: the copy said
   "Read them, add what belongs, set anything aside" while the buttons said
   approve / reject / delete. Terracotta here, a quiet secondary for setting
   aside, and red reserved for the ONE genuinely destructive action.
   Design critique 2026-09-08. */
.btn-approve {
    background: var(--color-primary);
    color: var(--color-text-on-primary);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--color-primary) 20%, transparent);
}

.btn-approve:hover {
    background: var(--color-primary-hover);
    color: var(--color-text-on-primary);
    box-shadow: 0 4px 16px color-mix(in srgb, var(--color-primary) 30%, transparent);
    transform: translateY(-1px);
}

.btn-approve:active {
    transform: scale(0.96);
    transition-duration: 0.08s;
}

/* .btn-reject is now DELETE ONLY. Setting a memory aside is reversible (the
   owner can move it back to review); deleting is not. Giving both the same
   alarm colour taught owners to read past it. */
.btn-reject {
    background: transparent;
    color: var(--color-text-on-bg-error);
    border: 1.5px solid var(--color-error);
}

.btn-reject:hover {
    background: var(--color-error);
    color: var(--color-text-on-primary);
    transform: translateY(-1px);
}

/* Setting aside: a quiet secondary, not an alarm. Kept as its own class rather
   than reusing .btn-secondary so the keyboard handler has a stable, semantic
   hook that does not move when the styling does — see the data-mod-action
   attributes in _submission_row.html. Before this split, BOTH "Set aside" and
   "Delete" carried .btn-reject and the R shortcut resolved correctly only
   because querySelector returns document order. */
.btn-set-aside {
    background: transparent;
    color: var(--color-text-secondary);
    border: 1.5px solid var(--color-border);
}

.btn-set-aside:hover {
    background: var(--color-surface);
    color: var(--color-text);
    border-color: var(--color-text-muted);
    transform: translateY(-1px);
}

/* Set-aside disclosure. The reason field used to sit permanently between
   "Add to book" and "Set aside", visually attached to neither, in a SEPARATE
   <form> from the approve button that preceded it in tab order — so typing a
   reason and then adding the memory silently discarded what you wrote. Putting
   it inside the form that owns it makes the ownership unambiguous, and the
   native <details> keeps it working with no JavaScript. */
.mod-set-aside {
    display: inline-block;
}

.mod-set-aside > summary {
    /* Rendered as a button; the marker would read as a stray triangle beside
       real buttons. Focus and keyboard activation stay native to <summary>. */
    list-style: none;
    cursor: pointer;
}

.mod-set-aside > summary::-webkit-details-marker {
    display: none;
}

.mod-set-aside__panel {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
    margin-top: var(--space-sm);
}

/* ---------- Bulk Moderation ---------- */
.bulk-actions {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-md);
    background: var(--color-bg-warm);
    border-radius: var(--radius-md);
    margin-bottom: var(--space-lg);
    position: sticky;
    top: 60px;
    z-index: 50;
}

.bulk-select-all {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    font-size: var(--text-sm);
    cursor: pointer;
    margin-right: auto;
}

.mod-item-checkbox {
    /* Native checkbox (no appearance: none), so the hit area IS the box:
       grow it to the WCAG 2.5.8 AA 24x24 floor. */
    width: 24px;
    height: 24px;
    min-width: 24px;
    min-height: 24px;
    padding: 0;
    margin-right: var(--space-md);
    cursor: pointer;
    flex-shrink: 0;
    /* Every other checkbox in the system carries this; this one did not, so a
       native unstyled box rendered as the browser default light square. On the
       dark surface that is the brightest element on the page, repeated down the
       whole queue. Tinting it costs nothing: `accent-color` recolours the
       checked fill without `appearance: none`, so the hit area stays the box
       and the 24px AA floor above is untouched. */
    accent-color: var(--color-primary);
}

/* ---------- AI Enhancement Panel ---------- */
.mod-enhancement {
    margin: var(--space-md) 0;
    padding: var(--space-md);
    background: var(--color-surface-alt);
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border-light);
}

.mod-enhancement__header {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    cursor: pointer;
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-text);
    user-select: none;
}

.mod-enhancement__header::-webkit-details-marker {
    display: none;
}

.mod-enhancement__header::before {
    content: "\25B8";
    font-size: var(--text-xs);
    transition: transform var(--duration-fast) var(--ease-out);
}

details[open] > .mod-enhancement__header::before {
    transform: rotate(90deg);
}

.mod-enhancement__tabs {
    display: flex;
    gap: 0;
    margin-top: var(--space-md);
    border-bottom: 1px solid var(--color-border-light);
}

.mod-enhancement__tab {
    padding: var(--space-sm) var(--space-md);
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--color-text-muted);
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    transition: color var(--duration-fast) var(--ease-out),
                border-color var(--duration-fast) var(--ease-out);
}

.mod-enhancement__tab:hover {
    color: var(--color-text-secondary);
}

.mod-enhancement__tab--active {
    color: var(--color-primary-text);
    border-bottom-color: var(--color-primary);
}

.mod-enhancement__panel {
    padding-top: var(--space-md);
}

.mod-enhancement__diff {
    font-family: var(--font-display);
    font-size: 1.05rem;
    line-height: 1.7;
    color: var(--color-text);
}

.mod-enhancement__diff del {
    color: var(--color-text-on-bg-error);
    text-decoration: line-through;
    opacity: 0.8;
}

.mod-enhancement__diff ins {
    color: var(--color-text-on-bg-success);
    text-decoration: none;
    font-weight: 600;
}

.mod-enhancement__actions {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    margin-top: var(--space-md);
    padding-top: var(--space-sm);
    border-top: 1px solid var(--color-border-light);
}

.mod-enhancement__stale {
    padding: var(--space-xs) var(--space-sm);
    margin-bottom: var(--space-md);
    background: var(--color-bg-warning);
    border-radius: var(--radius-sm);
    font-size: var(--text-xs);
    color: var(--color-text-secondary);
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}

.mod-enhancement__status {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-xs);
}

.mod-enhancement__status .badge-pending {
    animation: pulse-recording 2s ease-in-out infinite;
}

/* Video section in moderation */
.mod-video {
    margin: var(--space-sm) 0;
}

.mod-video__player {
    width: 100%;
    max-width: 480px;
    border-radius: var(--radius-md);
}

/* Audio section in moderation */
.mod-audio {
    margin: var(--space-sm) 0;
}

.mod-audio__meta {
    display: flex;
    gap: var(--space-sm);
    flex-wrap: wrap;
    margin-top: var(--space-xs);
}

.mod-transcript-override {
    margin-top: var(--space-xs);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-sm);
}

.mod-select-sm {
    padding: 0.3rem 0.5rem;
    font-family: var(--font-body);
    font-size: var(--text-xs);
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-bg);
    color: var(--color-text);
    cursor: pointer;
    transition: border-color var(--duration-fast) var(--ease-out);
}

.mod-select-sm:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-border-focus);
    box-shadow: var(--shadow-glow);
}

/* ---------- Sortable / Reorder ---------- */
.sortable-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}

.sortable-item {
    display: flex;
    align-items: center;
    gap: var(--space-md);
    padding: var(--space-md);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    transition: box-shadow var(--duration-fast);
}

.sortable-item:hover {
    box-shadow: var(--shadow-sm);
}

.sortable-handle {
    cursor: grab;
    color: var(--color-text-muted);
    font-size: 1.2rem;
    padding: var(--space-xs);
    user-select: none;
}

.sortable-handle:active {
    cursor: grabbing;
}

.sortable-ghost {
    opacity: 0.4;
    background: var(--color-primary-glow);
}

.sortable-content {
    flex: 1;
    min-width: 0;
}

.sortable-text {
    margin: 0;
    max-width: none;
}

/* ---------- Channels page ---------- */
.channels-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: var(--space-lg);
    margin-top: var(--space-lg);
}

.channel-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-lg) var(--space-xl);
    box-shadow: var(--shadow-sm);
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    transition: border-color var(--duration-fast) var(--ease-out),
                box-shadow var(--duration-fast) var(--ease-out);
}

/* Off / blocked variants — surface only, never the channel name. The label
   stays full-strength so the channel's identity reads regardless of state. */
.channel-card--off,
.channel-card--blocked {
    background: var(--color-bg-warm);
}

.channel-card:hover {
    border-color: var(--color-border);
    box-shadow: var(--shadow-md);
}

.channel-card__header {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}

.channel-card__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    color: var(--color-primary-text);
    line-height: 1;
}

.channel-card__icon svg {
    width: 28px;
    height: 28px;
    opacity: 0.9;
}

.channel-card--off .channel-card__icon {
    color: var(--color-text-muted);
}

.channel-card__label {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 600;
    color: var(--color-text);
    flex: 1;
}

/* Status pill: dot + label, paired so on/off is legible without color alone.
   On = primary tint; off = quiet neutral; blocked = warning tint. */
.channel-card__status {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.18rem 0.55rem 0.18rem 0.45rem;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    background: var(--color-badge-muted);
    color: var(--color-text-secondary);
}

.channel-card__status-dot {
    width: 0.4rem;
    height: 0.4rem;
    border-radius: 999px;
    background: currentColor;
    opacity: 0.55;
}

.channel-card--on .channel-card__status {
    background: var(--color-badge-success);
    color: var(--color-badge-text-success);
}

.channel-card--on .channel-card__status-dot {
    opacity: 1;
    box-shadow: 0 0 0 3px var(--color-primary-glow);
}

.channel-card--blocked .channel-card__status {
    background: var(--color-badge-warning);
    color: var(--color-badge-text-warning);
}

.channel-card--blocked .channel-card__status-dot {
    opacity: 0.85;
}

.channel-card__meta {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-sm) var(--space-md);
    font-size: var(--text-sm);
}

.channel-card__meta-item {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}

/* Push values to the bottom of each cell so they baseline-align across the
   row even when one label wraps to two lines (e.g. "Submissions / last 30
   days"). The grid stretches cells to row height, so margin-top:auto pins
   the value to the bottom edge. */
.channel-card__meta-item .channel-card__meta-value,
.channel-card__meta-item .channel-card__meta-value--link {
    margin-top: auto;
}

.channel-card__meta-label {
    color: var(--color-text-muted);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 500;
}

.channel-card__meta-sublabel {
    text-transform: none;
    letter-spacing: 0;
    font-weight: 400;
    color: var(--color-text-muted);
    opacity: 0.75;
}

.channel-card__meta-value {
    color: var(--color-text);
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.channel-card__meta-value--zero {
    color: var(--color-text-muted);
    opacity: 0.55;
    font-weight: 400;
}

.channel-card__meta-value--soft {
    color: var(--color-text-secondary);
    font-weight: 400;
}

.channel-card__meta-value--link {
    color: var(--color-primary-text);
    text-decoration: none;
}

.channel-card__meta-value--link:hover {
    color: var(--color-primary-text-hover);
    text-decoration: underline;
}

.channel-card__detail {
    border-top: 1px solid var(--color-border-light);
    padding-top: var(--space-sm);
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

.channel-card__detail-label {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
}

.channel-card__detail-row {
    display: flex;
    gap: var(--space-xs);
    align-items: stretch;
}

.channel-card__detail-value {
    flex: 1;
    min-width: 0;
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    padding: var(--space-xs) var(--space-sm);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-sm);
    background: var(--color-bg);
    color: var(--color-text);
}

.channel-card__deep-link {
    font-size: var(--text-sm);
    color: var(--color-primary-text);
    text-decoration: none;
    align-self: flex-start;
}

.channel-card__deep-link:hover {
    color: var(--color-primary-text-hover);
    text-decoration: underline;
}

.channel-card__qr {
    border-top: 1px solid var(--color-border-light);
    padding-top: var(--space-sm);
}

.channel-card__qr summary {
    cursor: pointer;
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.5rem 0;
    min-height: 44px;
    user-select: none;
    transition: color var(--duration-fast) var(--ease-out);
}

.channel-card__qr summary:hover {
    color: var(--color-text);
}

.channel-card__qr summary::-webkit-details-marker {
    display: none;
}

.channel-card__qr-chevron {
    width: 0.5rem;
    height: 0.5rem;
    /* Decorative chevron — border-width shorthand (top right bottom left). */
    border-style: solid;
    border-color: currentColor;
    border-width: 0 1.5px 1.5px 0;
    transform: rotate(-45deg);
    transition: transform var(--duration-fast) var(--ease-out);
    margin-bottom: 1px;
}

.channel-card__qr[open] .channel-card__qr-chevron {
    transform: rotate(45deg);
    margin-bottom: 0;
    margin-top: -2px;
}

.channel-card__qr-preview {
    margin-top: var(--space-sm);
    padding: var(--space-sm);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-sm);
    max-width: 200px;
}

.channel-card__qr-preview svg {
    width: 100%;
    height: auto;
    display: block;
}

.channel-card__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    align-items: center;
    border-top: 1px solid var(--color-border-light);
    padding-top: var(--space-sm);
}

.channel-card__help {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    text-decoration: none;
    margin-left: auto;
}

.channel-card__help:hover {
    color: var(--color-primary-text);
    text-decoration: underline;
}

.channel-card__notice {
    margin: 0;
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-md);
    background: var(--color-bg-warm);
    border: 1px solid var(--color-border-light);
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--color-text-secondary);
}

.channel-card__notice a {
    color: var(--color-primary-text);
    text-decoration: none;
    font-weight: 500;
    white-space: nowrap;
}

.channel-card__notice a:hover {
    text-decoration: underline;
}

.channel-card__notice--warn {
    background: var(--color-badge-warning-subtle);
    border-color: color-mix(in oklab, var(--color-warning) 25%, transparent);
    color: var(--color-text);
}

.channel-card__sub-option-link {
    font-size: var(--text-sm);
    color: var(--color-text-secondary);
    text-decoration: none;
    align-self: flex-start;
    transition: color var(--duration-fast) var(--ease-out);
}

.channel-card__sub-option-link:hover {
    color: var(--color-primary-text);
    text-decoration: underline;
}

/* ---------- Dashboard Channels card (book detail) ---------- */
.dashboard-channels-card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-lg);
    box-shadow: var(--shadow-sm);
}

.dashboard-channels-card__header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: var(--space-md);
    gap: var(--space-sm);
}

.dashboard-channels-card__header h2 {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--color-text);
}

.dashboard-channels-card__manage {
    font-size: var(--text-sm);
    color: var(--color-primary-text);
    text-decoration: none;
}

.dashboard-channels-card__manage:hover {
    color: var(--color-primary-text-hover);
    text-decoration: underline;
}

.dashboard-channels-card__list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
}

.dashboard-channels-card__row {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-xs) 0;
    border-bottom: 1px solid var(--color-border-light);
    font-size: var(--text-sm);
}

.dashboard-channels-card__row:last-child {
    border-bottom: none;
}

.dashboard-channels-card__row--off {
    color: var(--color-text-muted);
}

.dashboard-channels-card__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    color: currentColor;
    line-height: 1;
}

.dashboard-channels-card__icon svg {
    width: 18px;
    height: 18px;
    opacity: 0.85;
}

.dashboard-channels-card__row--on .dashboard-channels-card__icon {
    color: var(--color-primary-text);
}

.dashboard-channels-card__label {
    color: inherit;
    font-weight: 500;
}

.dashboard-channels-card__status {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

.dashboard-channels-card__row--on .dashboard-channels-card__status {
    color: var(--color-primary-text);
}

.dashboard-channels-card__count {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: var(--color-text);
    min-width: 2ch;
    text-align: right;
}

.book-gallery-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-md);
}

.book-gallery-header__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    flex: 0 0 auto;
}

.book-gallery-header__actions .btn svg {
    margin-right: 0.35rem;
}

/* ---- Bulk photo-import progress -------------------------------------- */
/* Mirrors the export-status panel/pill vocabulary so the two async-job
   surfaces feel like one family. Tokenized throughout. */
.photo-import-progress .progress-bar {
    margin-bottom: var(--space-lg);
}

/* Determinate fill: the base .progress-bar-fill is transform: scaleX() driven,
   but this surface knows imported/total, so we drive a real width set inline
   by the template. Reset the base transform so width is the only geometry and
   transition width (not transform) for a smooth poll-to-poll advance. */
.photo-import-progress .progress-bar-fill {
    width: 0;
    transform: none;
    transition: width var(--duration-slow) ease-out;
}

.photo-import-progress__panel {
    display: grid;
    grid-template-columns: max-content 1fr;
    column-gap: var(--space-lg);
    row-gap: var(--space-sm);
    margin: 0 0 var(--space-lg);
}

.photo-import-progress__row {
    display: contents;
}

.photo-import-progress__row dt {
    color: var(--color-text-muted);
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    align-self: center;
}

.photo-import-progress__row dd {
    margin: 0;
    color: var(--color-text);
    font-variant-numeric: tabular-nums;
}

.photo-import-progress__pill {
    display: inline-flex;
    align-items: center;
    padding: 0.18rem 0.6rem;
    border-radius: 999px;
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    background: var(--color-badge-muted);
    color: var(--color-badge-text-muted);
}

.photo-import-progress__pill--complete,
.photo-import-progress__pill--undone {
    background: var(--color-badge-success);
    color: var(--color-badge-text-success);
}

.photo-import-progress__pill--processing,
.photo-import-progress__pill--pending {
    background: var(--color-badge-info);
    color: var(--color-badge-text-info);
}

.photo-import-progress__pill--failed {
    background: var(--color-badge-error);
    color: var(--color-badge-text-error);
}

.photo-import-progress__done,
.photo-import-progress__error {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-md);
    margin-top: var(--space-lg);
}

.photo-import-progress__actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-md);
    margin-top: var(--space-lg);
}

/* Live status line above the bar ("Adding photo N of M…"). */
.photo-import-progress__live {
    margin: 0 0 var(--space-sm);
    color: var(--color-text);
    font-weight: 500;
}

/* PII-safe skip-reason breakdown ("2 too large, 1 not a photo"). */
.photo-import-progress__skip-detail {
    color: var(--color-text-muted);
    font-size: 0.85em;
}

.photo-import-progress__skip-summary {
    margin: 0;
}

/* "name · 92 MB · ready to import" confirmation after a file is chosen. */
.photo-import-fileinfo {
    margin: 0 0 var(--space-md);
    color: var(--color-text-secondary);
    font-size: var(--text-sm);
    font-variant-numeric: tabular-nums;
}

/* Live XHR upload region (browser → server transfer). */
.photo-import-upload {
    margin: var(--space-md) 0;
}

.photo-import-upload .progress-bar-fill {
    width: 0;
    transform: none;
    transition: width var(--duration-normal) ease-out;
}

.photo-import-upload [data-upload-status] {
    margin: var(--space-sm) 0 0;
    color: var(--color-text);
    font-variant-numeric: tabular-nums;
}

/* Indeterminate shimmer: worker spinning up (progress page, imported still 0)
   or the server checking the zip (upload region). Decorative → color-mix with
   no fallback per the CSS policy. */
.progress-bar--indeterminate {
    position: relative;
    overflow: hidden;
}

.progress-bar--indeterminate::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(
        90deg,
        transparent,
        color-mix(in srgb, var(--color-primary) 28%, transparent),
        transparent
    );
    transform: translateX(-100%);
    animation: photo-import-shimmer 1.3s ease-in-out infinite;
}

@keyframes photo-import-shimmer {
    to {
        transform: translateX(100%);
    }
}

@media (prefers-reduced-motion: reduce) {
    .progress-bar--indeterminate::after {
        animation: none;
    }
}

/* Inline date-fix form inside a photo card (needs_date gallery slice). */
.book-photo-card__date-fix {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding: var(--space-sm) var(--space-md) var(--space-md);
    border-top: 1px solid var(--color-border);
}

.book-photo-card__date-fix .form-label {
    font-size: 0.78rem;
    color: var(--color-text-muted);
}

.book-photo-card__date-fix-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-xs);
}

.book-photo-card__date-fix-row input[type="date"] {
    flex: 1 1 8rem;
    min-height: 44px;
    font-size: 1rem;
    padding: 0 var(--space-sm);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text);
}

/* Gallery filter rows reuse the global .btn / .mod-filters__count system
   (matches moderation/submissions.html). Each row carries a small label
   ("Type" / "Status") so two adjacent pill rows read as grouped facets. */
.gallery-filter-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-sm);
    margin: 0 0 var(--space-md);
}

.gallery-filter-row + .gallery-filter-row {
    margin-top: calc(-1 * var(--space-xs));
}

.gallery-filter-row__label {
    flex: 0 0 auto;
    min-width: 3.5rem;
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.gallery-filter-row__pills {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
}

.book-photo-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: var(--space-md);
    list-style: none;
    padding: 0;
    margin: 0;
}

.book-photo-card {
    position: relative;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
    transition:
        transform var(--duration-normal) var(--ease-out),
        box-shadow var(--duration-normal) var(--ease-out);
}

@media (hover: hover) {
    .book-photo-card:hover {
        transform: translateY(-2px);
        box-shadow: var(--shadow-md);
    }
}

@media (prefers-reduced-motion: reduce) {
    .book-photo-card {
        transition: none;
    }
    .book-photo-card:hover {
        transform: none;
    }
    /* Kill the in-flight callout pulse — the dot still reads as a
       processing indicator without motion. */
    .mod-callout__dot {
        animation: none;
    }
}

.book-photo-card__image-link {
    position: relative;
    display: block;
    aspect-ratio: 1;
    background: var(--color-surface-alt);
    overflow: hidden;
}

.book-photo-card__image-link:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: -2px;
}

.book-photo-card__image-link picture {
    position: absolute;
    inset: 0;
    display: block;
}

.book-photo-card__image,
.book-photo-card__image-link img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.book-photo-card__pending-badge {
    position: absolute;
    top: var(--space-sm);
    right: var(--space-sm);
    display: inline-flex;
    align-items: center;
    padding: 2px 0.625rem;
    border-radius: 999px;
    background: rgba(26, 22, 20, 0.82);
    color: var(--color-text-on-primary);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    box-shadow: var(--shadow-sm);
    pointer-events: none;
}

.book-photo-card__strip {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-xs);
    padding: var(--space-sm) var(--space-md);
    margin-top: auto;
    font-size: var(--text-sm);
}

.book-photo-card__byline {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.2;
}

.book-photo-card__author {
    /* User-authored proper noun — keepsake "Serif-for-Memory" rule. */
    font-family: var(--font-display);
    letter-spacing: -0.01em;
    min-width: 0;
    overflow: hidden;
    color: var(--color-text);
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.book-photo-card__date {
    color: var(--color-text-muted);
    font-size: 0.8125rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.book-photo-card__actions {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    flex-wrap: wrap;
}

.book-photo-card__link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: var(--space-xs) var(--space-xs);
    /* --color-primary (the verified 4.5:1 link color), not --color-accent
       (sage ~3.2:1 as text). Accent stays on the focus outline below. */
    color: var(--color-primary-text);
    font-weight: 600;
    font-size: var(--text-sm);
    text-decoration: none;
    border-radius: var(--radius-sm);
}

.book-photo-card__link--secondary {
    color: var(--color-text-muted);
    font-weight: 500;
}

.book-photo-card__link:hover {
    color: var(--color-text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.book-photo-card__link:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

.book-video-card__placeholder {
    position: absolute;
    inset: 0;
    background:
        linear-gradient(135deg, var(--color-surface-alt), var(--color-surface));
}

.book-video-card__play {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, 0.92);
    background: rgba(0, 0, 0, 0.18);
    pointer-events: none;
    transition: background var(--duration-fast) var(--ease-out);
}

.book-video-card__image-link:hover .book-video-card__play,
.book-video-card__image-link:focus-visible .book-video-card__play {
    background: rgba(0, 0, 0, 0.32);
}

@media (max-width: 640px) {
    .book-gallery-header {
        display: block;
    }

    .book-gallery-header .btn {
        margin-top: var(--space-sm);
    }

    .book-photo-gallery {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--space-sm);
    }
}

/* ---------- Public photo gallery (visitor surface) ---------- */

.public-gallery-link-wrap {
    margin: 0 0 var(--space-md);
}

.public-gallery-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: var(--space-xs) var(--space-sm) var(--space-xs) 0;
    color: var(--color-text);
    font-family: var(--font-display);
    font-size: 1.05rem;
    font-weight: 500;
    letter-spacing: 0.005em;
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: border-color var(--duration-fast) var(--ease-out),
        color var(--duration-fast) var(--ease-out);
}

.public-gallery-link:hover {
    color: var(--color-primary-text);
    border-bottom-color: var(--color-primary);
}

.public-gallery-link:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 4px;
    border-radius: var(--radius-sm);
}

.public-gallery-page {
    padding-block: var(--space-lg);
}

.public-gallery-header {
    margin-bottom: var(--space-lg);
}

.public-gallery-header h1 {
    margin: 0 0 0.25rem;
    font-family: var(--font-display);
    font-weight: 500;
    letter-spacing: -0.01em;
}

.public-gallery-header p {
    margin: 0 0 var(--space-sm);
    color: var(--color-text-muted);
}

.public-gallery-back {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    color: var(--color-text-secondary);
    font-size: 0.95rem;
    text-decoration: none;
}

.public-gallery-back:hover {
    color: var(--color-text);
    text-decoration: underline;
    text-underline-offset: 3px;
}

.public-gallery-back:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

/* ==========================================================================
   Moderation Deck — mobile-only swipe surface
   --------------------------------------------------------------------------
   Rendered alongside the dense .mod-queue surface inside submissions.html;
   visibility is toggled by media query in responsive.css. The deck shows
   one pending memory at a time as a swipeable card. Swipe right = approve,
   swipe left = reject (opens reason sheet), long-press = approve-as-written,
   kebab menu = a11y fallback with all four actions.

   Animation discipline: transform + opacity only. The base ease/duration
   tokens (--ease-out / --duration-normal) are the single voice; cards
   never overshoot or scale anything that would re-layout.
   ========================================================================== */

/* Shown when the deck wants to refresh but a draft that never reached storage
   would be destroyed by it. Not tied to the empty state: a restored memory or a
   still-loaded card can be behind a held refresh just as easily. */
.deck-refresh-held {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
    margin: var(--space-md);
    padding: var(--space-md);
    background: var(--color-bg-warm);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.deck-refresh-held__text {
    flex: 1 1 100%;
    margin: 0;
    color: var(--color-text-secondary);
    font-size: 0.92rem;
}

/* One block per stranded reason: who it was for, the words themselves (so they
   can be read and copied even when that memory has left the deck), and a way
   to let it go. */
.deck-refresh-held__draft {
    flex: 1 1 100%;
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    padding-top: var(--space-sm);
    border-top: 1px solid var(--color-border-light);
}

.deck-refresh-held__who {
    margin: 0;
    font-weight: 500;
    color: var(--color-text);
    font-size: 0.92rem;
}

.deck-refresh-held__words {
    width: 100%;
    resize: vertical;
}

.deck-shell {
    display: none; /* responsive.css promotes this to block at <=768px */
    padding: var(--space-md);
}

.deck-stack {
    position: relative;
    width: 100%;
    max-width: 480px;
    margin: 0 auto;
    min-height: 60vh;
}

.deck-card {
    position: relative;
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: var(--space-lg);
    margin-bottom: var(--space-md);
    /* GPU layer for the swipe transform — touch-action: pan-y keeps
       vertical page-scroll alive while we capture horizontal pointers. */
    touch-action: pan-y;
    user-select: none;
    -webkit-user-select: none;
    will-change: transform, opacity;
}

/* Subtle directional cue while a swipe is in flight — color is the
   commitment indicator (terracotta for approve, censure for reject).
   Inset shadow so the card edge bleeds the meaning. */
.deck-card--swiping-right {
    box-shadow:
        inset 6px 0 0 0 var(--color-success),
        var(--shadow-lg);
}
.deck-card--swiping-left {
    box-shadow:
        inset -6px 0 0 0 var(--color-error),
        var(--shadow-lg);
}

.deck-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-sm);
    margin-bottom: var(--space-sm);
}

.deck-card__who {
    flex: 1;
    min-width: 0;
}

.deck-card__name {
    display: block;
    font-family: var(--font-display);
    font-size: 1.25rem;
    line-height: 1.2;
    color: var(--color-text);
}

.deck-card__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    margin-top: var(--space-xs);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
}

.deck-card__menu {
    flex-shrink: 0;
    width: 44px;
    height: 44px;
    border: 1px solid transparent;
    background: transparent;
    border-radius: var(--radius-md);
    cursor: pointer;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--color-text-muted);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background var(--duration-normal) var(--ease-out),
                color var(--duration-normal) var(--ease-out);
}
.deck-card__menu:hover,
.deck-card__menu:focus-visible {
    background: var(--color-surface);
    color: var(--color-text);
    border-color: var(--color-border-light);
}
.deck-card__menu:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    box-shadow: var(--shadow-glow);
}

.deck-card__body,
.deck-card__body p {
    /* Same reasoning as .mod-item-body: this is the memory, shown one at a
       time on a card, so it reads as it will be published. */
    font-family: var(--font-display);
    font-size: 1.15rem;
    line-height: 1.65;
    color: var(--color-text);
    margin-bottom: var(--space-md);
    /* Long stories cap height — the deck is a glance surface; full
       reading goes to the dense list. */
    max-height: 38vh;
    overflow-y: auto;
}

.deck-card__media {
    margin: 0 calc(var(--space-lg) * -1) var(--space-md);
    overflow: hidden;
}

.deck-card__image {
    width: 100%;
    height: auto;
    display: block;
}

.deck-card__hint {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    margin: var(--space-sm) 0 0;
    line-height: 1.4;
}
.deck-card__hint svg {
    width: 1em;
    height: 1em;
    vertical-align: -0.125em;
}
.deck-card__hint--quiet {
    text-align: center;
    margin-top: var(--space-md);
    font-size: 0.78rem;
    color: var(--color-text-secondary);
}

.deck-card__actions {
    display: flex;
    gap: var(--space-sm);
    margin-top: var(--space-md);
}

.deck-actions__btn {
    flex: 1;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-md);
    font-family: var(--font-body);
    font-weight: 500;
    font-size: 0.95rem;
    white-space: nowrap;
    cursor: pointer;
    transition: background var(--duration-normal) var(--ease-out),
                color var(--duration-normal) var(--ease-out),
                transform var(--duration-normal) var(--ease-out);
    border: 1px solid var(--color-border);
}

.deck-actions__btn--approve {
    background: var(--color-primary);
    color: var(--color-text-on-primary);
    border-color: var(--color-primary);
}
.deck-actions__btn--approve:hover,
.deck-actions__btn--approve:focus-visible {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
    transform: translateY(-1px);
}
.deck-actions__btn--approve:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    box-shadow: var(--shadow-glow);
}

.deck-actions__btn--reject {
    background: var(--color-bg-card);
    color: var(--color-text);
    border-color: var(--color-border);
}
.deck-actions__btn--reject:hover,
.deck-actions__btn--reject:focus-visible {
    background: var(--color-bg-error-subtle);
    color: var(--color-text-on-bg-error);
    border-color: var(--color-error);
}
/* The 15%-alpha red ring this used to carry measured ~1.2:1 -- decorative, not
   an indicator, and a hardcoded rgba() besides. The focus token is the ring. */
.deck-actions__btn--reject:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
}

/* Empty state */
.deck-empty {
    text-align: center;
    padding: var(--space-2xl) var(--space-lg);
}
.deck-empty__mark {
    display: inline-block;
    width: 64px;
    height: 64px;
    line-height: 64px;
    font-size: 2rem;
    border-radius: 50%;
    background: var(--color-badge-success);
    color: var(--color-badge-text-success);
    margin-bottom: var(--space-md);
}
.deck-empty__head {
    font-family: var(--font-display);
    font-size: 1.75rem;
    color: var(--color-text);
    margin: 0 0 var(--space-sm);
}
.deck-empty__sub {
    color: var(--color-text-muted);
    margin: 0 0 var(--space-lg);
}

/* Reject reason sheet — <dialog> slid in from the bottom edge */
.deck-reject-dialog,
.deck-menu-dialog {
    border: none;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    padding: 0;
    background: var(--color-bg-card);
    color: var(--color-text);
    box-shadow: var(--shadow-lg);
    width: 100%;
    max-width: 480px;
    margin: auto auto 0; /* anchor to bottom of viewport */
}
.deck-reject-dialog::backdrop,
.deck-menu-dialog::backdrop {
    background: rgba(26, 22, 20, 0.45);
}

.deck-reject-dialog__form,
.deck-menu-dialog__form {
    padding: var(--space-lg);
    display: flex;
    flex-direction: column;
    gap: var(--space-sm);
}
.deck-reject-dialog__head,
.deck-menu-dialog__head {
    font-family: var(--font-display);
    font-size: 1.4rem;
    margin: 0;
    color: var(--color-text);
}
.deck-reject-dialog__sub,
.deck-menu-dialog__sub {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    margin: 0 0 var(--space-sm);
}
.deck-reject-dialog__form textarea {
    width: 100%;
    /* 16px floor — prevents iOS focus-zoom (DESIGN.md §Form Inputs). */
    font-size: 1rem;
    font-family: var(--font-body);
    resize: vertical;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 0.7rem 0.9rem;
}
.deck-reject-dialog__form textarea:focus {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
    border-color: var(--color-primary);
    box-shadow: var(--shadow-glow);
}
.deck-reject-dialog__actions {
    display: flex;
    gap: var(--space-sm);
    justify-content: flex-end;
    list-style: none;
    margin: var(--space-md) 0 0;
    padding: 0;
}

/* Kebab menu items */
.deck-menu-dialog__item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    min-height: 56px;
    padding: var(--space-sm) var(--space-md);
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-md);
    cursor: pointer;
    text-align: left;
    transition: background var(--duration-normal) var(--ease-out),
                border-color var(--duration-normal) var(--ease-out);
}
.deck-menu-dialog__item:hover,
.deck-menu-dialog__item:focus-visible {
    background: var(--color-bg-card-hover);
    border-color: var(--color-primary);
}
/* Inset: a full-width row inside a dialog, so the ring sits on the row rather
   than bleeding into the dialog padding. Same shape as .dashboard-more__menu a. */
.deck-menu-dialog__item:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: -2px;
    box-shadow: var(--shadow-glow);
}
.deck-menu-dialog__item--primary {
    background: var(--color-primary);
    color: var(--color-text-on-primary);
    border-color: var(--color-primary);
}
.deck-menu-dialog__item--primary:hover,
.deck-menu-dialog__item--primary:focus-visible {
    background: var(--color-primary-hover);
    border-color: var(--color-primary-hover);
    color: var(--color-text-on-primary);
}
/* An INSET ring is drawn on the control's own fill, not on the page. This row
   is filled with --color-primary, and --color-border-focus on that measures
   1.28:1 -- the ring rendered and was invisible, which no guard could see
   because the contrast test measures the token against --color-bg and
   --color-bg-card, the surfaces an OUTSET ring lands on. Found by screenshot.
   Same token the primary-filled deck buttons already use for this. */
.deck-menu-dialog__item--primary:focus-visible {
    outline-color: var(--color-text-on-primary);
}
/* Set aside is REVERSIBLE and must not wear the destructive colour. books.css
   declares .btn-reject "DELETE ONLY" and the desktop queue was corrected to
   match; the deck kept red on both its confirm button and this menu row, so
   the collision the desktop fix removed was still live on the surface phones
   actually use. Quiet treatment here, red reserved for --danger below. */
.deck-menu-dialog__item--reject {
    color: var(--color-text-secondary);
}
.deck-menu-dialog__item--danger {
    color: var(--color-text-on-bg-error);
    border-color: var(--color-error);
}
.deck-menu-dialog__label {
    font-family: var(--font-body);
    font-size: 1rem;
    font-weight: 500;
}
.deck-menu-dialog__detail {
    font-size: var(--text-xs);
    opacity: 0.85;
    line-height: 1.3;
}
.deck-menu-dialog__cancel {
    min-height: 44px;
    margin-top: var(--space-sm);
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    color: var(--color-text-muted);
    font-family: var(--font-body);
    font-size: 0.95rem;
    cursor: pointer;
}
.deck-menu-dialog__cancel:hover,
.deck-menu-dialog__cancel:focus-visible {
    color: var(--color-text);
    border-color: var(--color-text-muted);
}

/* A keyboard user needs more than the hover colour shift, which is shared with
   the pointer state and says nothing about focus. Found by the focus-contrast
   guard, which the earlier version of this rule escaped. */
.deck-menu-dialog__cancel:focus-visible {
    outline: 2px solid var(--color-border-focus);
    outline-offset: 2px;
}

/* Committing state — synchronous busy flag set at the very start of
   commitAction in moderation-deck.js, BEFORE the 200ms animateToEdge
   lands the --in-flight class. Without this, a second pointer or an
   action-footer tap fired inside the 200ms window could queue a second,
   possibly conflicting, POST (approve plus reject is a data-integrity
   issue, not just cosmetic). pointer-events: none mirrors the in-flight
   rule so the visual and interaction state are coherent immediately at
   swipe-commit, not 200ms later. No opacity change so the user does not
   perceive a flash before the in-flight fade lands. */
.deck-card--committing {
    pointer-events: none;
}

/* In-flight state — the card is parked at the screen edge while the
   POST resolves. Hold position, reduce opacity, lock pointer-events so
   the reviewer cannot re-grab a card mid-commit. The leading-edge inset
   shadow stays from .deck-card--swiping-{left,right}; we layer a
   primary-tinted pulse on top so the in-flight signal reads as
   distinct from the pre-commit drag-tilt. */
.deck-card--in-flight {
    opacity: 0.7;
    pointer-events: none;
    box-shadow:
        inset 6px 0 0 0 var(--color-primary),
        var(--shadow-lg);
}
.deck-card--in-flight.deck-card--swiping-left {
    box-shadow:
        inset -6px 0 0 0 var(--color-primary),
        var(--shadow-lg);
}

/* Accessibility: honor the OS-level reduce-motion preference (WCAG
   2.3.3). Vestibular and migraine-sensitive reviewers should still be
   able to use the deck; we collapse the swipe-out / snap-back / tilt
   motion to a near-instant cross-fade while preserving the colour
   state cues (which are state communication, not decoration).

   Anything that translates, rotates, or scales the card is neutered
   here. Anything that paints state (inset edge shadow, opacity step
   on .deck-card--in-flight) stays. */
@media (prefers-reduced-motion: reduce) {
    .deck-card {
        transition: opacity 0.01ms linear !important;
        /* Tilt during drag would still fire from the inline transform
           the JS writes; the JS skips that branch when reduce is on,
           but keep the CSS-level transition equally flat as defense
           in depth. */
    }
    .deck-actions__btn {
        transition: background 0.01ms linear, color 0.01ms linear;
    }
    .deck-actions__btn--approve:hover,
    .deck-actions__btn--approve:focus-visible {
        transform: none;
    }
    .deck-card__menu {
        transition: background 0.01ms linear, color 0.01ms linear;
    }
    .deck-menu-dialog__item {
        transition: background 0.01ms linear, border-color 0.01ms linear;
    }
}

/* Owner dashboard (book_detail) recent-memory cards + manage link.
   Lifted out of book_detail.html's inline <style> into the bundle so it shares
   one cascade/cache and is lintable against the token rules. Audit A-04. */
.dashboard-recent {
    margin-top: var(--space-2xl, 2rem);
    margin-bottom: var(--space-2xl, 2rem);
}
.dashboard-recent__heading {
    font-family: var(--font-display);
    font-size: 1.5rem;
    font-weight: 500;
    margin: 0 0 var(--space-md, 1rem) 0;
    color: var(--color-text);
}
.dashboard-recent__list {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-md, 1rem);
    list-style: none;
    padding: 0;
    margin: 0;
}
.dashboard-recent__card {
    background: var(--color-bg-card);
    border: 1px solid var(--color-border-light);
    border-radius: var(--radius-lg);
    padding: var(--space-lg) var(--space-xl);
    box-shadow: var(--shadow-sm);
    transition: box-shadow var(--duration-normal, 240ms) var(--ease-out, ease-out),
                transform var(--duration-normal, 240ms) var(--ease-out, ease-out);
}
.dashboard-recent__card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
}
.dashboard-recent__byline {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--space-sm, 0.5rem);
    margin-bottom: var(--space-xs, 0.25rem);
}
.dashboard-recent__author {
    font-family: var(--font-display);
    font-size: 1.25rem;
    font-weight: 500;
    color: var(--color-text);
}
.dashboard-recent__date {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    letter-spacing: 0.01em;
}
.dashboard-recent__excerpt {
    font-family: var(--font-display);
    font-size: 1.0625rem;
    line-height: 1.6;
    color: var(--color-text);
    margin: 0 0 var(--space-md, 1rem) 0;
    max-width: 65ch;
    overflow-wrap: break-word;
    word-break: break-word;
}
.dashboard-recent__link {
    font-family: var(--font-body);
    font-size: 0.9375rem;
    color: var(--color-primary-text);
    text-decoration: none;
    border-bottom: 1px solid currentColor;
    padding-bottom: 1px;
}
.dashboard-recent__link:hover,
.dashboard-recent__link:focus-visible {
    color: var(--color-primary-text-hover);
}

.dashboard-manage {
    margin-top: var(--space-3xl, 3rem);
    padding-top: var(--space-lg, 1rem);
    border-top: 1px solid var(--color-border-light);
    text-align: center;
}
.dashboard-manage__link {
    font-family: var(--font-body);
    font-size: 0.9375rem;
    color: var(--color-text-muted);
    text-decoration: none;
    letter-spacing: 0.01em;
}
.dashboard-manage__link:hover,
.dashboard-manage__link:focus-visible {
    color: var(--color-text);
}
/* ---------- Tablet (641px – 1024px) ---------- */
@media (min-width: 641px) and (max-width: 1024px) {
    .hero {
        padding: var(--space-2xl) var(--space-lg);
    }

    .hero-features {
        grid-template-columns: repeat(3, 1fr);
        gap: var(--space-md);
    }

    .book-grid {
        grid-template-columns: repeat(2, 1fr);
    }

    .pricing-grid {
        grid-template-columns: repeat(2, 1fr);
    }

    .stats-grid {
        grid-template-columns: repeat(3, 1fr);
    }

    .page-header,
    .page-content {
        padding: 0 var(--space-lg);
    }

    .form-card,
    .success-card,
    .auth-card {
        max-width: 520px;
    }

    .memory-card {
        padding: var(--space-lg) var(--space-xl);
    }

    /* Use-case pages — tablet */
    .occasion-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* ---------- Mobile (≤640px) ---------- */
@media (max-width: 640px) {
    /* `body > header nav` (not `header nav`) to out-specificity the base
       rule in nav.css (also `body > header nav`) — a plain `header nav`
       here is a no-op against it and the base 16px/24px padding always
       wins, which is how the header grew past 64px in the first place. */
    body > header nav {
        padding: var(--space-sm) var(--space-md);
        gap: var(--space-xs);
        flex-wrap: nowrap;
        position: relative;
    }

    .nav-brand {
        font-size: 1.15rem;
        min-width: 0;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        flex: 1 1 auto;
    }

    .cmd-hint__label,
    .cmd-hint__kbd {
        display: none;
    }

    .nav-toggle {
        display: flex;
    }

    /* Drawer: overlays the page under the sticky header instead of growing
       the header (it reached 255px open, 145px closed). */
    .nav-links {
        display: none;
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        flex-direction: column;
        gap: var(--space-xs);
        padding: var(--space-sm) var(--space-md) var(--space-md);
        background: var(--color-bg-card);
        border-top: 1px solid var(--color-border-light);
        border-bottom: 1px solid var(--color-border);
        box-shadow: var(--shadow-md);
    }

    /* Shared mobile-nav row treatment.
       Convention: every interactive mobile-nav control is an <a> or <button>
       *inside* .nav-links — the layout (full-width, left-aligned, consistent
       padding) is applied here once. Naming new items individually drifts
       (see PR #164: .nav-dropdown-toggle was missed and rendered centered).
       Adding a new control? Use <a> or <button>, not a custom element.
       Wrappers (e.g. .nav-dropdown around the Use Cases toggle, .nav-logout-form
       around the Log out button) must stretch full-width too — otherwise the
       inner element's width:100% resolves to a content-width parent and the
       row sits centered in the column. */
    .nav-links .nav-dropdown,
    .nav-links .nav-logout-form {
        width: 100%;
    }
    .nav-links a,
    .nav-links button {
        font-size: var(--text-sm);
        padding: var(--space-sm) var(--space-md);
        border-radius: var(--radius-md);
        width: 100%;
        text-align: left;
        justify-content: flex-start;
        min-height: 44px;
        display: flex;
        align-items: center;
    }

    .nav-links a:hover,
    .nav-links button:hover {
        background: var(--color-primary-glow);
    }

    .nav-links a.btn-primary {
        text-align: center;
        justify-content: center;
        margin-top: var(--space-xs);
    }

    .nav-user {
        display: block;
        width: 100%;
        padding: var(--space-sm) var(--space-md);
        font-size: var(--text-sm);
        color: var(--color-text-muted);
        border-bottom: 1px solid var(--color-border-light);
    }

    .nav-separator {
        display: none;
    }

    .auth-card {
        padding: var(--space-xl) var(--space-lg);
        border-radius: var(--radius-lg);
    }

    .hero {
        padding: var(--space-xl) var(--space-md);
    }

    .hero-actions {
        flex-direction: column;
    }

    .hero-actions .btn {
        width: 100%;
    }

    .hero-features {
        grid-template-columns: 1fr;
        padding: 0 var(--space-md);
    }

    .pricing-book-selector {
        flex-direction: column;
        text-align: center;
    }

    .pricing-book-selector .form-select {
        width: 100%;
    }

    .pricing-card__limits {
        gap: var(--space-md);
    }

    .pricing-card__limit-value {
        font-size: 1.1rem;
    }

    .page-header,
    .page-content {
        padding: 0 var(--space-md);
    }

    .book-nav {
        padding: 0 var(--space-md);
        margin-bottom: var(--space-lg);
    }

    .book-nav__item {
        padding: var(--space-sm) var(--space-sm);
        font-size: var(--text-xs);
    }

    .dashboard-urgent {
        padding: var(--space-md);
    }

    .dashboard-tools {
        grid-template-columns: 1fr 1fr;
        gap: var(--space-sm);
    }

    .dashboard-tool {
        padding: var(--space-md);
    }

    .dashboard-tool:last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }

    .page-header-row {
        flex-direction: column;
        align-items: flex-start;
    }

    .settings-card {
        padding: var(--space-lg);
    }

    .settings-row {
        flex-direction: column;
        align-items: flex-start;
        gap: var(--space-xs);
    }

    .settings-value {
        text-align: left;
    }

    .settings-select {
        min-width: 100%;
    }

    .book-grid {
        grid-template-columns: 1fr;
    }

    .stats-grid {
        grid-template-columns: 1fr;
    }

    .stat-card {
        padding: var(--space-md);
    }

    .stat-card-number {
        font-size: 1.6rem;
    }

    .form-card,
    .danger-card,
    .success-card,
    .verify-card {
        padding: var(--space-xl) var(--space-lg);
        border-radius: var(--radius-lg);
    }

    .mod-item-actions {
        flex-direction: column;
        align-items: flex-start;
    }

    .mod-item-actions form {
        display: flex;
        flex-direction: column;
        width: 100%;
    }

    .mod-reject-input {
        width: 100%;
    }

    /* On narrow screens the identity / status row stacks: identity
       takes a full line, then the primary moderation badge sits
       below-right where it still anchors the row visually. */
    .mod-item-header {
        flex-wrap: wrap;
    }

    .mod-item-identity {
        width: 100%;
    }

    /* Callout: keep the icon + label legible but allow the inline
       Retry form to wrap below on narrow viewports. */
    .mod-callout {
        flex-wrap: wrap;
    }

    .mod-callout form {
        flex: 1 0 100%;
        margin-top: var(--space-xs);
    }

    .page-actions {
        gap: var(--space-xs);
    }

    .page-actions .btn-sm {
        font-size: var(--text-xs);
        padding: 0.4rem 0.8rem;
        min-height: 2.75rem;
    }

    .dashboard-more__menu {
        right: auto;
        left: 0;
        max-width: 90vw;
    }

    .success-next {
        padding: var(--space-md);
    }

    .share-link {
        flex-direction: column;
    }

    .share-link input[type="text"] {
        width: 100%;
    }

    .danger-card .form-footer {
        flex-direction: column;
    }

    .branding-footer {
        flex-direction: column-reverse;
        gap: var(--space-sm);
    }

    .branding-footer .btn-primary {
        width: 100%;
    }

    .branding-footer .btn-secondary {
        width: 100%;
        text-align: center;
    }

    .error-page {
        padding: var(--space-2xl) var(--space-md);
    }

    .error-actions {
        flex-direction: column;
    }

    .error-actions .btn {
        width: 100%;
    }

    .torn-page {
        width: 140px;
        height: 170px;
    }

    .torn-page-number {
        font-size: 2.5rem;
    }

    .sealed-book-cover {
        width: 110px;
        height: 140px;
    }

    .bottom-nav {
        display: flex;
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 100;
        justify-content: space-around;
        align-items: center;
        height: 60px;
        /* Glassmorphism removed; solid 96% warm background gives the
           sticky bottom-nav the contrast it needs without the blur. */
        background: color-mix(in srgb, var(--color-bg) 96%, transparent);
        border-top: 1px solid var(--color-border-light);
        padding-bottom: env(safe-area-inset-bottom, 0);
        transition: transform var(--duration-normal) var(--ease-out);
    }

    .bottom-nav--hidden {
        transform: translateY(100%);
    }

    /* Reserve bottom-nav space only when the nav is actually rendered.
       Pages that opt out via `hide_bottom_nav=True` (e.g. the moderation
       /books/<slug>/submissions/ queue, where the book context is
       already present) skip the .has-bottom-nav class so the gutter
       doesn't eat 68px of vertical density. */
    body.has-bottom-nav {
        padding-bottom: 68px;
    }

    /* Use-case pages — mobile */
    .occasion-grid {
        grid-template-columns: 1fr;
    }

    .channels-strip__icons {
        gap: var(--space-md);
    }

    .nav-dropdown-menu {
        position: static;
        transform: none;
        box-shadow: none;
        border: none;
        background: transparent;
        padding: 0;
        min-width: auto;
    }

    /* Phone: toasts span the width so their text stays on one or two lines
       instead of wrapping into a column over the deck buttons.

       The CONSTRAINTS BELONG TO THE STACK now, not to each toast. They used to
       sit on .mod-toast when every toast positioned itself; once the shared
       container took over the fixed positioning, left/right on a
       position: relative child stopped stretching anything and instead nudged
       it inside a shrink-to-fit column -- the narrow wrapping column this rule
       exists to prevent. */
    .mod-toast-stack {
        left: var(--space-md);
        right: var(--space-md);
        transform: none;
        align-items: stretch;
    }
    .mod-toast {
        left: auto;
        right: auto;
        width: auto;
        max-width: none;
        transform: translateY(20px);
    }
    .mod-toast--visible {
        transform: translateY(0);
    }

    /* Arrow glyphs pushed "Set aside"/"Add to book" to "Set"/"Add to" at
       390px; the swipe hint already teaches direction. */
    .deck-actions__btn > [aria-hidden="true"] {
        display: none;
    }
}

/* ---------- Borderless Memory Stream ---------- */
@media (max-width: 640px) {
    .memory-card {
        background: transparent;
        border: none;
        box-shadow: none;
        border-radius: 0;
        padding: 0;
    }

    .memory-card:hover {
        box-shadow: none;
        transform: none;
    }

    .memory-card:not(:last-child)::after {
        display: block;
        width: 40px;
        height: 1px;
        background: var(--color-border-light);
        margin: var(--space-xl) auto 0;
    }

    .memory-stream {
        gap: var(--space-xl);
    }

    .memory-card-text {
        font-size: 1.1rem;
        line-height: 1.8;
    }

    .memory-card-footer {
        border-top: none;
        padding-top: 0;
        margin-top: var(--space-sm);
    }

    .memory-card-media img {
        border-radius: var(--radius-sm);
        box-shadow: none;
    }

    /* Pinned: tinted border + background instead of stripe */
    .memory-card-pinned {
        border: 1px solid color-mix(in srgb, var(--color-primary) 30%, transparent);
        background: color-mix(in srgb, var(--color-primary) 5%, var(--color-bg-card));
        box-shadow: none;
        padding: var(--space-md);
        border-radius: var(--radius-md);
    }

    .memory-card-pinned:hover {
        box-shadow: none;
    }

    .memory-card-pinned .memory-card-text {
        font-size: 1.15rem;
    }
}

/* ==========================================================================
   Error Pages
   ========================================================================== */

.error-page {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    min-height: calc(100vh - 200px);
    padding: var(--space-3xl) var(--space-lg);
    animation: fadeUp var(--duration-slow) var(--ease-out) both;
}

.error-illustration {
    margin-bottom: var(--space-xl);
}

.error-title {
    font-family: var(--font-display);
    font-size: clamp(2rem, 5vw, 3rem);
    font-weight: 600;
    line-height: 1.15;
    margin-bottom: var(--space-md);
    color: var(--color-text);
}

.error-subtitle {
    font-size: 1.05rem;
    line-height: 1.7;
    color: var(--color-text-secondary);
    max-width: 440px;
    margin: 0 auto var(--space-xl);
}

.error-actions {
    display: flex;
    gap: var(--space-md);
    justify-content: center;
    flex-wrap: wrap;
}

.error-trail {
    display: flex;
    gap: var(--space-sm);
    margin-top: var(--space-3xl);
}

.error-trail-dot {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--color-border);
    animation: trailPulse 2s ease-in-out infinite;
}

.error-trail-dot:nth-child(2) {
    animation-delay: 0.3s;
}

.error-trail-dot:nth-child(3) {
    animation-delay: 0.6s;
}

@keyframes trailPulse {
    0%, 100% { opacity: 0.3; transform: scale(1); }
    50% { opacity: 1; transform: scale(1.4); }
}

/* ==========================================================================
   Small-phone fallback (320px) — iPhone SE and older Android compact
   ========================================================================== */
@media (max-width: 360px) {
    /* Tighter side padding so 65–75ch body text doesn't compress into a sliver */
    .page-content,
    .form-page,
    .form-card {
        padding-left: var(--space-sm);
        padding-right: var(--space-sm);
    }

    /* Stack any remaining grids that the 640px breakpoint left as 2-up */
    .form-grid,
    .pricing-grid,
    .dashboard-tools {
        grid-template-columns: 1fr;
    }

    /* Heading scale — pull the display sizes down a notch so they don't wrap on
       short titles. Body text already ramps via clamp() at the parent level. */
    h1 {
        font-size: clamp(1.5rem, 7vw, 2rem);
    }
    h2 {
        font-size: clamp(1.25rem, 5.5vw, 1.5rem);
    }

    /* Ensure form inputs don't overflow when border + padding pushes width past viewport */
    input[type="text"],
    input[type="email"],
    input[type="tel"],
    input[type="url"],
    textarea,
    select {
        max-width: 100%;
        box-sizing: border-box;
    }
}

/* ==========================================================================
   Moderation Deck — viewport-toggled visibility
   --------------------------------------------------------------------------
   The submissions queue renders BOTH the dense .mod-queue list and the
   swipe-deck .deck-shell. At <=768px the deck is the visible surface and
   the dense list hides; at >768px the dense list is visible and the deck
   hides. ?view=table / ?view=deck override the viewport default by
   stamping data-deck-view on <body>.

   The swap is gated on `(pointer: coarse)` — an ACTUAL touch-primary device —
   not width alone. A desktop user who ZOOMS IN (or uses a narrow/split window)
   shrinks the CSS viewport below 768px but keeps a fine pointer + keyboard;
   width-only gating handed them the touch swipe-deck and silently killed the
   J/K/A/R/X keyboard shortcuts (the handler in submissions.html bails when
   .queue--desktop is display:none). Coarse-pointer gating keeps the dense
   keyboard list for them while real phones/tablets still get the deck. Explicit
   ?view=deck still forces the deck via the data-deck-view overrides below.

   EVERY rule that hides the native list is additionally gated on
   `body[data-deck-ready]`, which moderation-deck.js stamps only after it has
   bound the cards. Each deck control is a `type="button"` that does nothing
   without that script, so hiding the native forms before it is ready — or when
   it never arrives — leaves a moderator on a phone with no working controls at
   all. "New" is a plain link in the filter pills, so an ordinary tap reaches
   this surface. The gate covers both the coarse-pointer default AND the
   `?view=deck` override: the override is stamped by an INLINE script in
   submissions.html that runs whether or not moderation-deck.js ever loads, so
   without the readiness condition a single failed script leaves the native
   controls hidden behind `!important`.
   ========================================================================== */
@media (max-width: 768px) and (pointer: coarse) {
    body[data-deck-ready] .queue--desktop {
        display: none;
    }
    /* No swipe deck is rendered on the approved/rejected filters, so the
       dense list is the ONLY surface there — keep it visible on mobile or
       the viewport shows a blank list under a non-zero count. */
    body[data-deck-ready] .queue--desktop.queue--standalone {
        display: block;
    }
    body[data-deck-ready] .deck-shell {
        display: block;
    }
}

/* Override hooks for the ?view= query param. The view sets data-deck-view
   on <body> (no JS needed — server-side template renders the attribute). */
body[data-deck-view="table"] .queue--desktop {
    display: block !important;
}
body[data-deck-view="table"] .deck-shell {
    display: none !important;
}
body[data-deck-ready][data-deck-view="deck"] .queue--desktop {
    display: none !important;
}
/* Standalone (deck-less) filters ignore ?view=deck — forcing the deck on a
   filter that renders no deck would re-create the blank-surface bug. */
body[data-deck-ready][data-deck-view="deck"] .queue--desktop.queue--standalone {
    display: block !important;
}
body[data-deck-ready][data-deck-view="deck"] .deck-shell {
    display: block !important;
}

/* ==========================================================================
   Print Styles — clean output for the public book page
   ========================================================================== */
@media print {
    /* Hide interactive and navigation elements */
    header,
    footer,
    .skip-link,
    .nav-toggle,
    .theme-toggle,
    .owner-toolbar,
    .btn,
    .pagination,
    .public-powered-by,
    .messages,
    .public-credits,
    .memory-card-share,
    .memory-card-download,
    .empty-state {
        display: none !important;
    }

    /* Reset backgrounds and shadows for ink. Literal paper/ink here is
       intentional — printing our warm off-white background wastes toner.
       Fallback-only CSS vars keep the lint happy without introducing
       production-time tokens that'd never actually resolve. */
    body,
    body::before {
        background: var(--print-paper, #ffffff) !important;
        color: var(--print-ink, #000000) !important;
    }

    body::before {
        display: none !important;
    }

    .memory-card,
    .card {
        box-shadow: none !important;
        border: 1px solid var(--color-border) !important;
        break-inside: avoid;
    }

    /* Let content flow naturally */
    main {
        padding: 0 !important;
    }

    .page-content,
    .page-header {
        max-width: none !important;
        padding: 0 !important;
    }

    /* Typography for print */
    .public-header h1 {
        font-size: 2rem;
    }

    .memory-card-text {
        font-size: 1rem;
        line-height: 1.6;
    }

    /* Images should print without filters */
    img {
        filter: none !important;
        max-width: 100% !important;
        break-inside: avoid;
    }

    /* Page breaks */
    .memory-card {
        break-inside: avoid;
        page-break-inside: avoid;
        margin-bottom: 1.5rem;
    }

    .public-header {
        break-after: avoid;
    }

    /* Show URLs for links */
    a[href^="http"]::after {
        content: " (" attr(href) ")";
        font-size: 0.8em;
        color: #7A6F66;
        word-break: break-all;
    }

    /* But not for internal links or buttons */
    .memory-card a::after,
    nav a::after {
        content: none !important;
    }
}
/* ==========================================================================
   Dark Mode — warm dark palette
   Activated by [data-theme="dark"] on <html>
   ========================================================================== */

[data-theme="dark"] {
    --color-bg: #1A1614;
    --color-bg-warm: #221E1B;
    --color-bg-card: #252220;
    --color-bg-card-hover: #2D2926;
    --color-surface: #2A2622;
    --color-surface-alt: #322E2A;

    --color-text: #F0EBE5;
    --color-text-secondary: #A89E95;
    /* Lifted from #7A7068 → #948A82 for AA contrast against dark bg at 12-14px */
    --color-text-muted: #948A82;

    /* #B25634 clears WCAG AA (4.80:1) against #FFFCF8 button text — verified 2026-04-28.
       The retired pre-April primary measured 3.67:1 and failed AA on every
       primary CTA in dark mode.
       Hover deepens (mirrors light-mode pattern) rather than lifts, to keep AA on hover. */
    --color-primary: #B25634;
    --color-primary-hover: #A85234;
    /* 2026-08 critique fix — dark-mode counterpart of --color-primary-deep
       (tokens.css). Lifted warm terracotta, same hue family as
       --color-primary above: 6.40:1 against --color-bg (#1A1614), 5.63:1
       against --color-bg-card (#252220) — both clear WCAG AA (4.5:1),
       verified via a relative-luminance script. */
    --color-primary-deep: #D08A5F;
    /* 2026-08 critique fix (Task 2) — dark-scoped text-safe alias for
       --color-primary (see tokens.css comment). Reuses --color-primary-deep's
       dark value: 6.40:1 on --color-bg (#1A1614), 5.63:1 on --color-bg-card
       (#252220) — both already clear WCAG AA (4.5:1), verified via a
       relative-luminance script. Re-point text/hover uses of --color-primary
       here, never backgrounds/borders/fills (those stay on --color-primary). */
    --color-primary-text: var(--color-primary-deep);
    /* 2026-08 critique fix (Task 2 review fix) — dedicated hover variant for
       --color-primary-text (see tokens.css comment). --color-primary-hover
       (#A85234) as text only hits 3.36:1/2.95:1 here — independently
       failing AA, not just non-distinct — so it can't be reused either.
       #BF7E57 is a darkened step off --color-primary-deep's dark value:
       5.42:1 on --color-bg, 4.77:1 on --color-bg-card — both clear AA
       (4.5:1), visibly darker/more muted than the rest color. */
    --color-primary-text-hover: #BF7E57;
    --color-primary-light: #8B6550;
    --color-primary-glow: rgba(178, 86, 52, 0.15);

    --color-accent: #96A088;
    --color-accent-light: #7D8471;
    /* sage as TEXT, dark mode: ≥4.5:1 on bg/card/surface — #A8B09E measures
       8.02:1 on --color-bg (#1A1614), 7.05:1 on --color-bg-card (#252220),
       6.41:1 on --color-surface (#2E2926); verified via a relative-luminance
       script (2026-09-04 audit P1, WCAG 1.4.3). */
    --color-accent-text: #A8B09E;

    --color-border: #3A3430;
    --color-border-light: #2E2A26;
    --color-border-focus: var(--color-primary);

    --color-success: #6EA076;
    --color-error: #D06858;
    --color-warning: #D4A343;
    /* Warm light-stone, dark-mode parity with the 2026-05-18 light-mode mauve. */
    --color-info: #B5A89F;

    /* Semantic state backgrounds */
    --color-bg-success: rgba(110, 160, 118, 0.08);
    --color-bg-error: rgba(208, 104, 88, 0.08);
    --color-bg-warning: rgba(212, 163, 67, 0.08);
    --color-bg-info: rgba(181, 168, 159, 0.08);
    --color-bg-error-subtle: rgba(208, 104, 88, 0.05);
    --color-error-hover: #B85848;
    --color-error-active: #A84838;
    --color-success-hover: #5E9A66;

    /* Status text on tinted bg — dark mode keeps the lighter status colors, which
       clear AA on the dark surface (success 5.95, error 4.96, warning 7.80, info 7.76
       on --color-bg #1A1614). The light-mode darker text would be unreadable here. */
    --color-text-on-bg-success: var(--color-success);
    /* 2026-08 critique fix (Task 2) — --color-error (#D06858) itself only hit
       4.96:1 on --color-bg but 4.37:1 on --color-bg-card (#252220, the card
       surface this token is actually verified against), failing AA there.
       #D37465 is a lightened step of the same warm-red hue: 4.86:1 on
       --color-bg-card, 5.52:1 on --color-bg — both clear AA (4.5:1). */
    --color-text-on-bg-error: #D37465;
    --color-text-on-bg-warning: var(--color-warning);
    --color-text-on-bg-info: var(--color-info);

    /* Badge backgrounds — dark */
    --color-badge-success: rgba(110, 160, 118, 0.15);
    --color-badge-warning: rgba(212, 163, 67, 0.15);
    --color-badge-warning-subtle: rgba(212, 163, 67, 0.08);
    --color-badge-warning-strong: rgba(212, 163, 67, 0.2);
    --color-badge-info: rgba(181, 168, 159, 0.15);
    --color-badge-error: rgba(208, 104, 88, 0.15);
    --color-badge-muted: rgba(122, 112, 104, 0.15);

    /* Badge text — dark mode lifts the foreground for AA on tinted dark pills. */
    --color-badge-text-success: #8FBE96;
    --color-badge-text-warning: #E0B870;
    --color-badge-text-info: #C8BCB1;
    --color-badge-text-error: #E08272;
    --color-badge-text-muted: #C0B7AE;

    --shadow-sm: 0 1px 3px rgba(26, 22, 20, 0.3);
    --shadow-md: 0 4px 12px rgba(26, 22, 20, 0.35);
    --shadow-lg: 0 8px 30px rgba(26, 22, 20, 0.4);
    --shadow-glow: 0 0 0 3px var(--color-primary-glow);

    /* Decorative — dark overrides */
    --color-leather-dark: #2A2420;
    --color-leather: #4A423B;
    --color-leather-spine: #3A3430;
    --color-clasp: #8B6550;
    --color-parchment: #2A2622;
    --color-parchment-warm: #252220;
    --color-ink-warm: #F0EBE5;
    --color-ink-soft: #D0C8BE;
    --color-ink-gold: #8B7A5E;
    --color-ink-muted: #7A7068;
    --color-ink-sage: #7A7068;
    --color-ink-deep: #A89E95;
    --color-storybook-gold: #A08650;
    --color-storybook-ink: #F0EBE5;
    --color-storybook-muted: #7A7068;
    --color-storybook-border: #3A3430;
    --color-modern-ink: #F0EBE5;
    --color-modern-card: #2A2622;
    --color-modern-green: #6EA076;
    --color-occasion-rose: #D06858;
    --color-occasion-rose-light: #2D2420;
    /* --color-occasion-sky overrides removed in parity with tokens.css. */
    --color-occasion-stone: #7A7068;
    --color-occasion-stone-light: #2A2622;
    --color-occasion-cream: #2A2622;
    --color-occasion-sand: #2A2420;
    --color-memorial: #A89E95;
    --color-memorial-hover: #B5ADA5;
    --color-memorial-light: #7A7068;
    --color-memorial-glow: rgba(168, 158, 149, 0.15);
    --color-memorial-bg: #221E1B;
}

/* Grain overlay — reduce in dark mode */
[data-theme="dark"] body::before {
    opacity: 0.02;
}

/* Header — border only override (background uses color-mix with --color-bg token) */
[data-theme="dark"] header {
    border-bottom-color: var(--color-border);
}

/* Images — slight brightness reduction to avoid eye strain */
[data-theme="dark"] img {
    filter: brightness(0.92);
}

/* Inputs — dark background */
[data-theme="dark"] input,
[data-theme="dark"] select,
[data-theme="dark"] textarea {
    background-color: var(--color-bg-warm);
    color: var(--color-text);
    border-color: var(--color-border);
}

/* Settings danger card — dark */
[data-theme="dark"] .settings-card--danger {
    background: color-mix(in srgb, var(--color-error) 8%, transparent);
    border-color: color-mix(in srgb, var(--color-error) 20%, transparent);
}

/* Success card — dark */
[data-theme="dark"] .success-card {
    border-color: rgba(110, 160, 118, 0.2);
}

/* Book sub-nav — dark */
[data-theme="dark"] .book-nav__track {
    border-bottom-color: var(--color-border);
}

/* Dashboard zones — dark */
[data-theme="dark"] .dashboard-urgent {
    background: var(--color-bg-warm);
    border-color: var(--color-border);
}

[data-theme="dark"] .dashboard-tool {
    background: var(--color-bg-warm);
    border-color: var(--color-border);
}

[data-theme="dark"] .dashboard-tool:hover {
    background: var(--color-surface);
}

/* Dashboard more menu — dark */
[data-theme="dark"] .dashboard-more__menu {
    background: var(--color-bg-warm);
    border-color: var(--color-border);
}

/* Keyboard hints — dark */
[data-theme="dark"] .kbd-hints kbd {
    background: var(--color-bg-warm);
    border-color: var(--color-border);
}

/* Success "What happens next" box — slightly more visible in dark */
[data-theme="dark"] .success-next {
    background: var(--color-surface);
}

/* Mobile bottom nav — dark (background uses color-mix with --color-bg token) */

/* Theme toggle icon swap */
[data-theme="dark"] .theme-toggle .icon-sun { display: none; }
[data-theme="dark"] .theme-toggle .icon-moon { display: inline; }
[data-theme="light"] .theme-toggle .icon-sun { display: inline; }
[data-theme="light"] .theme-toggle .icon-moon { display: none; }
.theme-toggle .icon-moon { display: none; }
