/* FeedEcho design tokens — OKLCH palette, light + dark themes */

:root {
    /* Shared brand hues (OKLCH: lightness chroma hue) */
    /* UX audit finding 1 (2026-09-08): this was 35, only 10° from
       --hue-red (25) below — on a neutral background that's not reliably
       distinguishable from the danger color, especially for anyone with
       a red-green color vision deficiency, and it showed up concretely
       on first load (the Sign Up button + the autofocused, empty email
       field's focus ring both read as an error state before any
       interaction). 50 keeps the same warm, energetic family the
       "coral" name and comment describe while sitting roughly midway
       between --hue-red (25) and --hue-gold (85), so it no longer
       collides with either. This is a brand-color judgment call, not a
       bug fix — flagged in the PR for design review; the number is a
       single, easily-tunable value if a different target hue is wanted. */
    --hue-coral: 50;
    --hue-teal: 195;    /* teal — secondary/info */
    --hue-gold: 85;     /* golden — warning */
    --hue-green: 150;   /* success */
    --hue-red: 25;      /* danger */
    --hue-neutral: 260; /* slight violet tint on neutrals */

    color-scheme: light dark;
}

/* ---------- Dark theme (default) ---------- */
:root,
:root[data-theme="dark"] {
    --bg: oklch(0.19 0.012 var(--hue-neutral));
    --surface: oklch(0.23 0.016 var(--hue-neutral));
    --surface-light: oklch(0.27 0.02 var(--hue-neutral));
    --border: oklch(0.33 0.022 var(--hue-neutral));
    --text: oklch(0.92 0.008 var(--hue-neutral));
    --text-muted: oklch(0.68 0.015 var(--hue-neutral));

    --primary: oklch(0.72 0.16 var(--hue-coral));
    --primary-hover: oklch(0.78 0.17 var(--hue-coral));
    --primary-contrast: oklch(0.22 0.03 var(--hue-coral));
    --accent: oklch(0.75 0.12 var(--hue-teal));
    --accent-hover: oklch(0.81 0.12 var(--hue-teal));

    --success: oklch(0.72 0.14 var(--hue-green));
    --danger: oklch(0.76 0.16 var(--hue-red));
    --warning: oklch(0.78 0.14 var(--hue-gold));
    --code-bg: oklch(0.15 0.01 var(--hue-neutral));

    /* translucent badge/alert washes */
    --success-wash: oklch(0.72 0.14 var(--hue-green) / 0.16);
    --danger-wash: oklch(0.68 0.18 var(--hue-red) / 0.16);
    --warning-wash: oklch(0.78 0.14 var(--hue-gold) / 0.16);
    --accent-wash: oklch(0.75 0.12 var(--hue-teal) / 0.14);
    --primary-wash: oklch(0.72 0.16 var(--hue-coral) / 0.14);

    --shadow: 0 1px 3px oklch(0.1 0.01 var(--hue-neutral) / 0.5);
}

/* ---------- Light theme ---------- */
:root[data-theme="light"] {
    --bg: oklch(0.97 0.006 var(--hue-neutral));
    --surface: oklch(0.99 0.003 var(--hue-neutral));
    --surface-light: oklch(0.94 0.008 var(--hue-neutral));
    --border: oklch(0.88 0.01 var(--hue-neutral));
    --text: oklch(0.24 0.015 var(--hue-neutral));
    --text-muted: oklch(0.48 0.02 var(--hue-neutral));

    --primary: oklch(0.46 0.19 var(--hue-coral));
    --primary-hover: oklch(0.41 0.20 var(--hue-coral));
    --primary-contrast: oklch(0.98 0.005 var(--hue-coral));
    --accent: oklch(0.47 0.12 var(--hue-teal));
    --accent-hover: oklch(0.42 0.13 var(--hue-teal));

    --success: oklch(0.46 0.16 var(--hue-green));
    --danger: oklch(0.47 0.21 var(--hue-red));
    --warning: oklch(0.48 0.16 var(--hue-gold));
    --code-bg: oklch(0.93 0.008 var(--hue-neutral));

    /* Contrast pass (impeccable critique 2026-08-29): the light-theme
       saturated tokens sit at the darkest L that still passes WCAG AA on
       their own washes and surfaces. Values browser-verified via canvas
       compositing; lower L = higher ratio but these hold >=4.5:1 for
       normal text with margin (tightest: warning on warning-wash 5.16:1).
       Do not lighten these without re-running the canvas check. */

    --success-wash: oklch(0.55 0.15 var(--hue-green) / 0.12);
    --danger-wash: oklch(0.55 0.20 var(--hue-red) / 0.10);
    --warning-wash: oklch(0.62 0.15 var(--hue-gold) / 0.14);
    --accent-wash: oklch(0.55 0.11 var(--hue-teal) / 0.10);
    --primary-wash: oklch(0.58 0.19 var(--hue-coral) / 0.10);

    --shadow: 0 1px 3px oklch(0.5 0.02 var(--hue-neutral) / 0.15);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* The reset above zeroes `margin`, which also defeats the browser's default
   `dialog[open] { margin: auto }` auto-centering — so modal <dialog>s must be
   centered explicitly or they render pinned to the top-left corner. */
dialog[open] {
    position: fixed;
    inset: 0;
    margin: auto;
    overflow: visible;
}

html { -webkit-text-size-adjust: 100%; }

/* ── Inter self-hosted (D3) ──────────────────────────────────────────────────
   Latin subset of the variable font: one 48K woff2 covers weights 100-900.
   Previously loaded from Google Fonts; self-hosting removes the only
   third-party browser request and lets CSP drop the Google origins. */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../fonts/inter-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Ubuntu, 'Helvetica Neue', Arial, sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.6;
    font-size: 16px;
    transition: background 0.2s ease, color 0.2s ease;
}

/* Navbar */
.navbar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 100;
    flex-wrap: wrap;
}
.nav-brand {
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--text);
    text-decoration: none;
    display: flex;
    align-items: center;
    gap: 0.3rem;
    white-space: nowrap;
}
.nav-icon {
  width: 22px;
  height: 22px;
  border-radius: 5px;
  vertical-align: -5px; /* optically center the tile against the nav text */
  margin-right: 0.15rem;
}
/* display:contents by default so this wrapper (added only to give the
   mobile scroll-fade below a non-scrolling positioning context) doesn't
   become a flex item itself on desktop — .nav-links's margin-left:auto
   needs to act as a direct child of .navbar to push the tab strip right. */
.nav-links-wrap { display: contents; }
.nav-links {
    display: flex;
    gap: 0.15rem;
    margin-left: auto;
    flex-wrap: wrap;
    align-items: center;
}
.nav-links a {
    color: var(--text-muted);
    text-decoration: none;
    font-size: 0.85rem;
    padding: 0.4rem 0.6rem;
    border-radius: 6px;
    transition: color 0.15s, background 0.15s;
    white-space: nowrap;
}
.nav-links a:hover { color: var(--text); background: var(--surface-light); }
.nav-links a.active {
    color: var(--primary);
    /* Non-color cue for the current page (WCAG 1.4.1): colour alone is not
       enough, so active links also get weight and an underline bar. */
    font-weight: 600;
    box-shadow: inset 0 -2px 0 var(--primary);
}

/* Skip link: first focusable element on every page, hidden until focused. */
.skip-link {
    position: absolute;
    left: 0.75rem;
    top: -3rem;
    z-index: 1000;
    padding: 0.5rem 0.9rem;
    border-radius: 0 0 6px 6px;
    background: var(--primary);
    color: var(--primary-contrast);
    font-size: 0.85rem;
    text-decoration: none;
    transition: top 0.15s;
}
.skip-link:focus {
    top: 0;
    outline: 2px solid var(--primary-contrast);
    outline-offset: -2px;
}

/* Account chrome (multi mode) */
.nav-account {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-left: 0.4rem;
    padding-left: 0.6rem;
    border-left: 1px solid var(--border);
}
.nav-email {
    color: var(--text-muted);
    font-size: 0.8rem;
    max-width: 12rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.nav-logout {
    background: var(--surface-light);
    border: 1px solid var(--border);
    color: var(--text);
    border-radius: 6px;
    padding: 0.35rem 0.6rem;
    font-size: 0.8rem;
    cursor: pointer;
}
.nav-logout:hover { background: var(--border); }

/* Trial banner (multi mode dashboard) */
.trial-banner {
    background: var(--surface-light);
    border: 1px solid var(--primary);
    border-radius: 8px;
    padding: 0.7rem 1rem;
    margin-bottom: 1rem;
    font-size: 0.9rem;
    color: var(--text);
}
.trial-banner p { margin: 0 0 0.3rem; }
.trial-banner p:last-child { margin-bottom: 0; }
.trial-usage { color: var(--text-muted); font-size: 0.85rem; }

/* Email-verification banner (multi mode dashboard) */
.verify-banner {
    background: var(--warning-wash);
    border: 1px solid var(--warning);
    border-radius: 8px;
    padding: 0.7rem 1rem;
    margin-bottom: 1rem;
    font-size: 0.9rem;
    color: var(--text);
}

/* Theme toggle */
.theme-toggle {
    background: var(--surface-light);
    border: 1px solid var(--border);
    color: var(--text);
    border-radius: 6px;
    padding: 0.35rem 0.55rem;
    font-size: 0.95rem;
    line-height: 1;
    cursor: pointer;
    min-height: 36px;
    min-width: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, border-color 0.15s;
}
.theme-toggle:hover { background: var(--border); }
.theme-toggle:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

/* Main */
main {
    max-width: 1100px;
    margin: 0 auto;
    padding: 1rem;
}

h1 { font-size: 1.4rem; margin-bottom: 0.75rem; }
h2 { font-size: 1.1rem; margin: 1.25rem 0 0.5rem; }

/* Stats — each card gets its own accent color */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
    gap: 0.5rem;
    margin-bottom: 1rem;
}
.stat-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.75rem;
    text-align: center;
    box-shadow: var(--shadow);
}
.stat-value {
    display: block;
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--primary);
}
.stat-label {
    display: block;
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-top: 0.1rem;
}
/* color rotation across stat cards */
.stat-card:nth-child(4n+1) .stat-value { color: var(--primary); }
.stat-card:nth-child(4n+2) .stat-value { color: var(--accent); }
.stat-card:nth-child(4n+3) .stat-value { color: var(--success); }
.stat-card:nth-child(4n+4) .stat-value { color: var(--warning); }
.stat-warning .stat-value { color: var(--warning) !important; }

/* Tables — responsive: card layout on mobile, table on desktop */
.data-table-wrapper {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin-bottom: 1rem;
}
.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}
.data-table th {
    text-align: left;
    padding: 0.5rem 0.6rem;
    background: var(--surface);
    color: var(--text-muted);
    font-weight: 600;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
.data-table td {
    padding: 0.5rem 0.6rem;
    border-bottom: 1px solid var(--border);
    vertical-align: top;
}
.data-table tr:hover td { background: var(--surface); }
.data-table small { color: var(--text-muted); }
.data-table a { color: var(--accent); text-decoration: none; }
.data-table a:hover { text-decoration: underline; color: var(--accent-hover); }

/* Mobile: convert tables to stacked cards */
@media (max-width: 640px) {
    .data-table thead { display: none; }
    .data-table, .data-table tbody, .data-table tr, .data-table td {
        display: block;
        width: 100%;
    }
    .data-table tr {
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: 8px;
        margin-bottom: 0.5rem;
        padding: 0.25rem 0;
    }
    .data-table td {
        padding: 0.4rem 0.75rem;
        border: none;
        display: flex;
        justify-content: space-between;
        align-items: flex-start;
        gap: 0.5rem;
        text-align: right;
    }
    .data-table td::before {
        content: attr(data-label);
        font-weight: 600;
        font-size: 0.75rem;
        text-transform: uppercase;
        color: var(--text-muted);
        white-space: nowrap;
        flex-shrink: 0;
    }
    .data-table td.action-cell {
        flex-wrap: wrap;
        justify-content: flex-end;
    }
    .data-table td.action-cell::before {
        width: 100%;
        margin-bottom: 0.25rem;
    }
    /* Destination cell: value column is a wrapped .dest-cell (badge + long
       handle). Let the value claim the full line and wrap; keep badge-only
       rows (IMG/CW/DIGEST/DRIP flags that follow a <br>) on their own lines
       aligned right like every other value. */
    .data-table td[data-label="Destination"] {
        flex-wrap: wrap;
    }
    .data-table td[data-label="Destination"] .dest-cell {
        flex: 1 1 auto;
        min-width: 0;
        justify-content: flex-end;
        text-align: right;
    }
    .data-table td[data-label="Destination"] .dest-cell .dest-type {
        flex: 0 0 auto;
    }
}

/* Badges — semantic colors with translucent washes */
.badge {
    display: inline-block;
    padding: 0.15rem 0.5rem;
    border-radius: 4px;
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}
.badge-success { background: var(--success-wash); color: var(--success); }
.badge-danger { background: var(--danger-wash); color: var(--danger); }
.badge-info { background: var(--accent-wash); color: var(--accent); }
.badge-warning { background: var(--warning-wash); color: var(--warning); }
.badge-muted { background: var(--surface-light); color: var(--text-muted); }

/* Forms */
.inline-form {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}
.inline-form input, .inline-form select, .inline-form button {
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text);
    font-size: 0.9rem;
    min-height: 44px; /* iOS touch target */
}
.inline-form input, .inline-form select { flex: 1; min-width: 0; }
.inline-form input:focus, .inline-form select:focus {
    border-color: var(--primary);
    outline: 2px solid var(--primary);
    outline-offset: 1px;
}
/* The URL field's placeholder ("https://example.com/feed.xml") is the
   longest and most informative of the row's placeholders — give it more
   of the row's width than poll-interval/folder need, instead of every
   field getting an equal flex:1 share and truncating it. UX audit
   finding 6 (2026-09-08). */
#feed-url { flex: 2.5; }

/* Accounts "add account" forms stack each field on its own line at every
   viewport width. .inline-form is row-flex by default, so a multi-field
   connect form (Bluesky: name + handle + app password; Matrix: server +
   room + token; etc.) squeezes its inputs into unreadably narrow columns on
   desktop. Column layout puts the label above a full-width input, one per
   line, matching how these forms already render on phones. */
.inline-form.stacked {
    flex-direction: column;
    align-items: stretch;
}
.inline-form.stacked label {
    display: block;
    width: 100%;
    font-size: 0.85rem;
    color: var(--text-muted);
    margin-bottom: 0.15rem;
}
.inline-form.stacked input {
    width: 100%;
    min-width: 0;
    flex: none;
}
.inline-form.stacked button {
    align-self: flex-start;
}

/* History filter bar (issue #16): the .inline-form shape, but its controls are
   selects — .inline-form only styles inputs — plus a Clear link that reads as
   secondary next to the submit button. */
.filter-form select {
    flex: 1;
    min-width: 0;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--surface);
    color: var(--text);
    font-size: 0.9rem;
    font-family: inherit;
    min-height: 44px;
}
.filter-form select:focus {
    border-color: var(--primary);
    outline: 2px solid var(--primary);
    outline-offset: 1px;
}
.filter-form .filter-clear {
    align-self: center;
    color: var(--text-muted);
    font-size: 0.85rem;
}
.filter-form .filter-clear:hover { color: var(--text); }
@media (max-width: 640px) {
    /* Match the mobile input rule: each select claims its own full-width line
       under its label instead of being squeezed onto the label's line. */
    .filter-form select { flex: 1 1 100%; width: 100%; }
    .filter-form button { flex: 0 0 auto; }
}

.echo-form {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 1rem;
    margin-bottom: 1rem;
}
.form-row {
    display: flex;
    gap: 0.75rem;
    margin-bottom: 0.5rem;
    flex-wrap: wrap;
}
.form-row label {
    display: flex;
    flex-direction: column;
    font-size: 0.8rem;
    color: var(--text-muted);
    flex: 1;
    min-width: 0;
}
.form-row input, .form-row select, .form-row textarea {
    margin-top: 0.2rem;
    padding: 0.5rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg);
    color: var(--text);
    font-size: 0.9rem;
    font-family: inherit;
    min-height: 44px;
}
.form-row textarea { font-family: 'Courier New', monospace; min-height: 60px; }
.form-row input:focus, .form-row select:focus, .form-row textarea:focus {
    border-color: var(--primary);
    outline: 2px solid var(--primary);
    outline-offset: 1px;
}
.form-row input[type="checkbox"] {
    width: 24px;
    min-height: 24px;
    margin-top: 0.5rem;
    accent-color: var(--primary);
}
.edit-actions {
    justify-content: flex-end;
    padding-top: 0.5rem;
}
.echo-edit-form {
    background: var(--surface);
    border: 1px solid var(--primary);
    border-radius: 8px;
    padding: 0.75rem 1rem;
    margin: 0;
}
.echo-edit-form .form-row {
    margin-bottom: 0.4rem;
}

@media (max-width: 640px) {
    /* Two rows: [brand | theme | account] on row 1; tab strip wraps to row 2.
       Sticky retained deliberately: feeds/history/echoes are long lists and
       one-tap primary nav beats ~96px of vertical cost. */
    .navbar {
        flex-wrap: wrap;
        row-gap: 0;
        column-gap: 0.5rem;
        align-items: center;
        /* env() = 0px in normal browsers; matters because the app ships
           viewport-fit=cover + standalone PWA meta, so the sticky header must
           not underlap the status bar. */
        padding:
            calc(0.5rem + env(safe-area-inset-top, 0px))
            max(0.75rem, env(safe-area-inset-right, 0px))
            0.5rem
            max(0.75rem, env(safe-area-inset-left, 0px));
    }
    .nav-brand   { order: 1; flex: 0 1 auto; min-width: 0; }
    .theme-toggle { order: 2; flex: 0 0 auto; margin-left: auto; min-height: 44px; min-width: 44px; }
    .nav-account  { order: 3; flex: 0 0 auto; margin-left: 0; padding-left: 0; border-left: 0; position: relative; }
    /* Wraps .nav-links so the "more content" fade below can stay fixed at
       the visible edge — a fade generated on .nav-links itself would be
       inside the scrolling content and scroll away with it instead of
       overlaying the viewport edge. */
    .nav-links-wrap {
        display: block;
        position: relative;
        order: 4;
        flex: 1 1 100%;
        margin-left: 0;
        min-width: 0;
    }
    /* Tabs wrap to a second row instead of scrolling off-screen: every
       destination is visible at first paint. (v1.26.3 shipped a horizontally
       scrolling strip + edge fade; an external review in 2026-09 found it
       still read as clipped — History/Settings/How To hidden behind an
       undiscoverable swipe — so the strip was replaced with a wrap. The
       fade cue is gone with it: nothing scrolls, nothing needs a cue.) */
    .nav-links {
        margin-left: 0;
        flex-wrap: wrap;
        overflow-x: visible;
        row-gap: 2px;
    }
    .nav-links a {
        flex: 0 0 auto;                /* natural width: rows pack left like
                                          wrapped text, no full-width orphan */
        min-height: 44px;              /* touch target */
        display: inline-flex;
        align-items: center;
        padding: 0.3rem 0.75rem;
        font-size: 0.9rem;
    }
    .nav-links a:focus-visible,
    .nav-brand:focus-visible {
        outline: 2px solid var(--primary);
        outline-offset: -2px;
        border-radius: 6px;
    }
    /* The wrapped tab rows make the sticky header up to ~200px tall at
       320px; the pending-card redirect targets /settings#billing, which
       would land hidden under it. */
    #billing { scroll-margin-top: 220px; }

    /* Account: inline email/logout are desktop-only; on mobile they collapse
       into a no-JS <details> menu. */
    .nav-account > .nav-email,
    .nav-account > form { display: none; }
    .nav-account-menu { display: block; position: relative; z-index: 50; }
    .nav-account-menu summary {
        list-style: none;
        cursor: pointer;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 0.15rem;
        min-width: 44px;               /* touch target */
        min-height: 44px;
        border-radius: 8px;
    }
    .nav-account-menu summary::-webkit-details-marker { display: none; }
    .nav-account-menu summary:focus-visible {
        outline: 2px solid var(--primary);
        outline-offset: 2px;
    }
    .nav-account-menu summary::after {  /* disclosure cue, non-color-only */
        content: "▾";
        font-size: 0.7rem;
        color: var(--text-muted);
    }
    .nav-account-menu[open] summary::after { content: "▴"; }
    .nav-avatar {
        flex: 0 0 28px;
        width: 28px;
        height: 28px;
        border-radius: 50%;
        background: var(--primary);
        color: var(--primary-contrast);
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 0.75rem;
        font-weight: 700;
    }
    .nav-account-panel {
        position: absolute;
        right: 0;
        top: calc(100% + 6px);
        min-width: 210px;
        max-width: min(80vw, 320px);
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: 10px;
        box-shadow: 0 10px 30px rgb(0 0 0 / 0.35);
        padding: 0.75rem;
        display: flex;
        flex-direction: column;
        gap: 0.5rem;
    }
    .nav-account-panel .nav-email {      /* full address, wraps - no ellipsis */
        max-width: none;
        white-space: normal;
        overflow-wrap: anywhere;
        font-size: 0.85rem;
    }
    .nav-account-panel .nav-logout {
        width: 100%;
        min-height: 44px;               /* touch target */
        padding: 0.5rem;
    }
}

@media (min-width: 641px) {
    .nav-account-menu { display: none; }  /* mobile menu is mobile-only */
}

@media (max-width: 640px) {
    /* Form layout: labels claim their own line and inputs go full-width
       beneath them. The natural inline-form flex layout squeezes `flex: 1`
       inputs down to whatever the label left over (a "Name" input rendered
       ~30px wide), so contents were unreadable on phones. Wrapping labels
       (display:block, full width) push the input to the next flex line; the
       100% basis below makes it fill the line. */
    .inline-form label {
        display: block;
        width: 100%;
        font-size: 0.85rem;
        color: var(--text-muted);
        margin-bottom: 0.15rem;
    }
    .inline-form input {
        flex: 1 1 100%;
        min-width: 0;
        width: 100%;
    }
    .inline-form input[type="number"] {
        flex: 0 1 auto;
        min-width: 5rem;
    }
    /* sr-only labels (before the P2 visible-label change) stay out of flow */
    .inline-form label.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;
    }
    /* keep the submit button from stretching to full width */
    .inline-form button { flex: 0 0 auto; }
}

@media (max-width: 640px) {
    .form-row { flex-direction: column; }
    .form-row label { width: 100%; }
    /* A wrapping label next to a standalone <label for> (P2 visible-label
       pattern) puts the caption and control on separate lines; without a
       full-width basis the input shrinks to its content. */
    .form-row input, .form-row select, .form-row textarea {
        width: 100%;
    }
    .form-row input[type="checkbox"] {
        width: 24px;
    }
}

@media (max-width: 640px) {
    /* Admin action cells: each control cluster (Suspend / Make admin /
       plan select + Set plan / days input + Extend trial) is its own
       .inline-form. In the card layout these forms sat side by side inside
       the ACTIONS cell, colliding at the right edge: "Make admin" clipped
       under the plan dropdown, "Extend trial" cut off. Stack one action
       cluster per line instead, controls sized to content and wrapped
       safely. The admin template's Actions cells carry no .action-cell
       class (only accounts/feeds/echoes/history do), so target the cell by
       its data-label. */
    .data-table td[data-label="Actions"] {
        display: block;            /* not flex: forms stack vertically */
        white-space: normal;       /* let button labels live */
        text-align: left;
    }
    .data-table td[data-label="Actions"] .inline-form {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        margin-bottom: 0.5rem;
        max-width: 100%;
    }
    .data-table td[data-label="Actions"] .inline-form:last-child {
        margin-bottom: 0;
    }
    .data-table td[data-label="Actions"] .inline-form select,
    .data-table td[data-label="Actions"] .inline-form input:not([type="checkbox"]) {
        flex: 1 1 auto;
        min-width: 0;
        max-width: 9rem;           /* dropdown/input stay compact, never overlap */
        min-height: 44px;
    }
    .data-table td[data-label="Actions"] .inline-form .btn-sm {
        margin-right: 0;
        margin-bottom: 0;
        min-height: 44px;
    }
    /* standalone button-only forms: keep the button compact, not stretched */
    .data-table td[data-label="Actions"] .inline-form .btn-sm:only-child {
        flex: 0 0 auto;
    }
}

.template-vars {
    margin-bottom: 0.5rem;
    font-size: 0.85rem;
}
.template-vars summary {
    cursor: pointer;
    color: var(--text-muted);
    padding: 0.25rem 0;
    min-height: 44px;
    display: flex;
    align-items: center;
}
.vars-table {
    width: 100%;
    margin-top: 0.5rem;
    font-size: 0.85rem;
}
.vars-table td { padding: 0.25rem 0.5rem; }
.vars-table td:first-child {
    /* The variable itself must stay on one row: 'Available template
       variables' reads as a lookup table, and a wrapped `{{ title }}`
       (reported on iOS Safari, where table cells shrink to content and
       the code glyphs break mid-token) forces eyeball ping-pong between
       two stacked fragments and the description. */
    white-space: nowrap;
}
.vars-table code { color: var(--accent); }

/* Echo destination cell: type badge + account handle. The handle is a code
   element that can be a long Mastodon address (@user@instance.social), so it
   must wrap on narrow screens instead of pushing siblings out of the card. */
.dest-cell {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.35rem 0.5rem;
    max-width: 100%;
}
.dest-name {
    overflow-wrap: anywhere;
    word-break: break-word;
    min-width: 0;
    max-width: 100%;
}

/* Buttons */
button, .btn-sm {
    padding: 0.5rem 1rem;
    border: none;
    border-radius: 6px;
    background: var(--primary);
    color: var(--primary-contrast);
    font-size: 0.9rem;
    cursor: pointer;
    transition: background 0.15s;
    min-height: 44px;
    -webkit-tap-highlight-color: transparent;
}
button:hover { background: var(--primary-hover); }
.btn-sm {
    padding: 0.35rem 0.6rem;
    font-size: 0.8rem;
    background: var(--surface-light);
    border: 1px solid var(--border);
    color: var(--text);
    text-decoration: none;
    margin-right: 0.25rem;
    margin-bottom: 0.25rem;
    min-height: 36px;
}
.btn-sm:hover { background: var(--border); }
.btn-danger { background: var(--danger); color: var(--primary-contrast); border-color: var(--danger); }
.btn-danger:hover { background: var(--danger); filter: brightness(1.12); }
.btn-success { background: var(--success); color: var(--primary-contrast); border-color: var(--success); }
.btn-success:hover { background: var(--success); filter: brightness(1.12); }
.action-cell { white-space: nowrap; }

/* Inline action status (showStatus): feedback rendered next to the button
   that fired it, instead of a blocking alert() dialog. */
.action-status {
    margin-top: 0.4rem;
    padding: 0.45rem 0.7rem;
    border-radius: 6px;
    font-size: 0.82rem;
    line-height: 1.45;
    max-width: 34rem;
    overflow-wrap: anywhere;
    white-space: normal;
}
.action-status-success { background: var(--success-wash); color: var(--success); border: 1px solid var(--success); }
.action-status-error { background: var(--danger-wash); color: var(--danger); border: 1px solid var(--danger); }
.action-status-info { background: var(--surface-light); color: var(--text); border: 1px solid var(--border); }

/* Error page (admin 403, etc.) */
.error-page {
    max-width: 30rem;
    margin: 3rem auto;
    text-align: center;
}
.error-page h1 { font-size: 3rem; margin-bottom: 0.5rem; }

/* Flash messages */
.flash { padding: 0.7rem 1rem; border-radius: 8px; margin-bottom: 1rem; font-size: 0.9rem; }
.flash-ok { background: var(--success-wash); color: var(--success); border: 1px solid var(--success); }
.flash-error { background: var(--danger-wash); color: var(--danger); border: 1px solid var(--danger); }
.flash-warn { background: var(--warning-wash); color: var(--warning); border: 1px solid var(--warning); }

/* How To page */
.howto-steps { margin: 0.5rem 0 1rem 1.25rem; line-height: 1.7; }
.howto-steps li { margin-bottom: 0.4rem; }

/* Site footer — links, plus the running version for the operator (issue #8) */
.site-footer {
    max-width: 1100px;
    margin: 2rem auto 0;
    padding: 1rem;
    border-top: 1px solid var(--border);
    font-size: 0.8rem;
    color: var(--text-muted);
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    align-items: baseline;
    justify-content: space-between;
}
.site-footer a { color: var(--text-muted); }
.footer-version { font-variant-numeric: tabular-nums; }

@media (max-width: 640px) {
    .btn-sm {
        min-height: 40px;
        padding: 0.4rem 0.75rem;
    }
}

/* Misc */
.empty-state {
    color: var(--text-muted);
    padding: 1rem;
    text-align: center;
    background: var(--surface);
    border-radius: 8px;
    border: 1px dashed var(--border);
    font-size: 0.9rem;
}
.empty-state a { color: var(--primary); }

.hint {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-bottom: 0.5rem;
}

code {
    font-family: 'Courier New', monospace;
    background: var(--code-bg);
    padding: 0.1rem 0.3rem;
    border-radius: 3px;
    font-size: 0.85rem;
}

.inline { display: inline; }

/* Alerts */
.alert {
    padding: 0.75rem 1rem;
    border-radius: 6px;
    margin-bottom: 0.75rem;
    font-size: 0.9rem;
}
.alert-success { background: var(--success-wash); border: 1px solid var(--success); color: var(--success); }
.alert-error { background: var(--danger-wash); border: 1px solid var(--danger); color: var(--danger); }
.alert-warning { background: var(--warning-wash); border: 1px solid var(--warning); color: var(--warning); }

/* OAuth section */
.oauth-section, .manual-section {
    margin-bottom: 1rem;
}
.oauth-section h2, .manual-section summary {
    font-size: 1rem;
    margin-bottom: 0.4rem;
}
.manual-section summary {
    cursor: pointer;
    color: var(--text-muted);
    padding: 0.5rem 0;
    min-height: 44px;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    list-style: none;
    user-select: none;
}
/* This <details> toggle previously had no visual cue distinguishing it
   from plain body text (cursor:pointer alone isn't visible in a static
   screenshot or discoverable without hovering) — matches the chevron
   pattern already used for details.account-section below. UX audit
   finding 4 (2026-09-08). */
.manual-section summary::-webkit-details-marker { display: none; }
.manual-section summary::after {
    content: "▾";
    color: var(--text-muted);
    transition: transform 0.15s ease;
}
.manual-section details:not([open]) > summary::after { transform: rotate(-90deg); }
.manual-section summary:hover { color: var(--text); text-decoration: underline; }
.manual-section summary:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Responsive heading sizes */
@media (max-width: 640px) {
    h1 { font-size: 1.25rem; }
    h2 { font-size: 1rem; }
    main { padding: 0.75rem; }
    .stat-value { font-size: 1.25rem; }
    .stats-grid {
        grid-template-columns: repeat(3, 1fr);
    }
}

@media (max-width: 400px) {
    .stats-grid {
        grid-template-columns: repeat(2, 1fr);
    }
    /* Brand alone shrinks; the tab strip keeps its 44px targets and scrolls
       horizontally instead of shrinking font/padding below touch size. */
    .nav-brand { font-size: 1rem; }
}

/* Auth/login page */
.auth-container {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 70vh;
    padding: 1rem;
}

.auth-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 2rem;
    max-width: 400px;
    width: 100%;
    text-align: center;
    box-shadow: var(--shadow);
}

.auth-card h1 {
    margin-bottom: 0.5rem;
}

.auth-tagline {
    color: var(--accent);
    margin: -0.25rem 0 0.35rem;
    font-size: 0.95rem;
    font-weight: 500;
}

.auth-subtitle {
    color: var(--text-muted);
    margin-bottom: 1.5rem;
    font-size: 0.9rem;
}

.auth-form {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.auth-input {
    width: 100%;
    padding: 0.75rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 1rem;
    background: var(--bg);
    color: var(--text);
    box-sizing: border-box;
    min-height: 44px;
}

.auth-input:focus {
    outline: 2px solid var(--primary);
    outline-offset: 1px;
    border-color: var(--primary);
}

/* Template preview panel (echo forms) */
.template-preview {
    margin-top: 0.5rem;
    padding: 0.75rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
}

.template-preview-btn {
    margin-top: 0.4rem;
}

.preview-item {
    padding: 0.5rem 0;
    border-top: 1px solid var(--border);
}

.preview-item:first-child {
    border-top: none;
    padding-top: 0;
}

.preview-item:last-child {
    padding-bottom: 0;
}

.preview-title {
    margin: 0 0 0.3rem;
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--text-muted);
}

.preview-item pre {
    margin: 0;
    white-space: pre-wrap;
    word-break: break-word;
    font-family: inherit;
    font-size: 0.95rem;
    color: var(--text);
}

.preview-error {
    margin: 0;
    color: var(--danger);
}

.template-help {
    margin-top: 0.75rem;
    color: var(--text-muted);
    font-size: 0.9rem;
}

.template-help p {
    margin: 0.3rem 0;
}

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

/* Visually hidden but announced: labels for inputs whose visible cue is the
   placeholder. Placeholders disappear on input and are unreliable for screen
   readers, so every input needs a real label even when the layout is compact. */
.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;
}

/* Admin per-user usage rows */
.usage-row td { background: var(--warning-wash); }
.usage-cell { padding: 0.4rem 1rem; }
.usage-summary { cursor: pointer; font-size: 0.85rem; color: var(--text-muted); }
.usage-summary:hover { color: var(--text); }
.usage-detail { margin: 0.5rem 0 0.25rem; font-size: 0.85rem; }
.usage-error { color: var(--danger); margin: 0.2rem 0; overflow-wrap: anywhere; }
.usage-ok { color: var(--success); margin: 0.2rem 0; }

/* Landing page (hosted, anonymous) */
.landing-hero {
    display: flex;
    gap: 2.5rem;
    align-items: center;
    padding: 2.5rem 0 2rem;
    flex-wrap: wrap;
}
.landing-hero-text { flex: 1 1 22rem; }
.landing-hero-text h1 {
    font-size: clamp(2rem, 5vw, 3rem);
    line-height: 1.15;
    margin: 0 0 1rem;
}
.landing-lede {
    color: var(--text-muted);
    font-size: 1.05rem;
    line-height: 1.65;
    margin: 0 0 1.5rem;
    max-width: 34rem;
}
.landing-cta { display: flex; gap: 0.75rem; flex-wrap: wrap; }
.landing-cta .btn { text-decoration: none; }
.btn-landing-primary {
    background: var(--accent);
    color: var(--bg);
    padding: 0.7rem 1.4rem;
    font-weight: 600;
    border-radius: 8px;
}
.btn-landing-primary:hover { background: var(--accent-hover); }
.btn-landing-secondary {
    border: 1px solid var(--accent);
    color: var(--accent);
    padding: 0.7rem 1.4rem;
    font-weight: 600;
    border-radius: 8px;
}
.btn-landing-secondary:hover { background: var(--accent-wash); }
.landing-trial-note {
    color: var(--text-muted);
    font-size: 0.82rem;
    margin: 0.9rem 0 0;
}
.landing-hero-art { flex: 1 1 24rem; min-width: 0; }
.landing-hero-art img {
    width: 100%;
    height: auto;
    border-radius: 12px;
    display: block;
}
.landing-features {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: 1rem;
    padding: 1.5rem 0;
}
.landing-feature {
    border: 1px solid var(--accent-wash);
    border-radius: 10px;
    padding: 1rem 1.1rem;
}
.landing-feature h3 { margin: 0 0 0.4rem; font-size: 1rem; }
.landing-feature p { margin: 0; color: var(--text-muted); font-size: 0.9rem; line-height: 1.55; }
.landing-how { padding: 1.5rem 0 2rem; }
.landing-how h2 { margin: 0 0 0.75rem; }
.landing-steps {
    line-height: 1.7;
    margin: 0 0 1rem;
    padding-left: 1.25rem; /* keep list markers on narrow screens */
    overflow-wrap: break-word;
}
@media (max-width: 640px) {
    .landing-steps { padding-left: 1.1rem; }
    .landing-steps li strong { display: block; }
}
.landing-how-cta { color: var(--text-muted); }
.landing-how-cta a { color: var(--accent); }

/* ---------- Pricing page (hosted, anonymous) ---------- */
.pricing-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 1rem;
    padding: 1rem 0 0.5rem;
    align-items: stretch;
}
.pricing-card {
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    padding: 1.4rem 1.4rem 1.6rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.pricing-card-featured {
    border-color: var(--accent);
    box-shadow: 0 0 0 1px var(--accent);
}
.pricing-card h2 { margin: 0 0 0.25rem; font-size: 1.15rem; }
.pricing-price { font-size: 2.2rem; font-weight: 700; margin: 0; }
.pricing-period { font-size: 1rem; font-weight: 500; color: var(--text-muted); }
.pricing-alt { margin: 0; font-size: 1rem; font-weight: 600; color: var(--text); }
.pricing-desc { margin: 0; color: var(--text-muted); font-size: 0.9rem; line-height: 1.55; }
.pricing-list {
    list-style: none;
    margin: 0.25rem 0 0.5rem;
    padding: 0;
    flex: 1 1 auto;
}
.pricing-list li {
    padding: 0.35rem 0;
    border-bottom: 1px solid var(--border);
    font-size: 0.92rem;
    color: var(--text);
}
.pricing-list li:last-child { border-bottom: none; }
.pricing-card .btn { text-decoration: none; align-self: flex-start; }
@media (max-width: 640px) {
    .pricing-grid { grid-template-columns: 1fr; }
}

/* ---------- Accounts page: per-destination collapsible sections ---------- */
.account-sections-toolbar {
    display: flex;
    gap: 0.5rem;
    margin: 1rem 0 0.75rem;
}
details.account-section {
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    margin-bottom: 0.75rem;
    overflow: hidden;
}
details.account-section > summary {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.8rem 1rem;
    cursor: pointer;
    list-style: none;
    user-select: none;
}
details.account-section > summary::-webkit-details-marker { display: none; }
details.account-section > summary::after {
    content: "▾";
    margin-left: auto;
    color: var(--text-muted);
    transition: transform 0.15s ease;
}
details.account-section:not([open]) > summary::after { transform: rotate(-90deg); }
details.account-section > summary:hover { background: var(--surface-light); }
details.account-section > summary:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}
.account-section-title { font-size: 1.05rem; font-weight: 600; }
.account-count {
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--text-muted);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0.1rem 0.55rem;
    background: var(--surface-light);
}
.account-count.count-active {
    color: var(--success);
    border-color: currentColor;
    background: var(--success-wash);
}
.account-section-body { padding: 0 1rem 1rem; }
.account-section-body > section { margin-top: 1rem; }
.account-section-body h2 { margin-top: 1.25rem; }

/* ── Reader (issue #11) ─────────────────────────────────────────────── */
.reader { display: grid; grid-template-columns: 260px 1fr; gap: 1.25rem; align-items: start; }
.reader-feeds { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 1rem; }
.reader-feeds h2 { margin: 0 0 0.75rem; font-size: 0.82rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em; }
.reader-feeds-hint { font-size: 0.78rem; color: var(--text-muted); line-height: 1.45; margin: -0.45rem 0 0.75rem; }
.reader-feed-list { list-style: none; margin: 0; padding: 0; }
.reader-feed { border-bottom: 1px solid var(--border); }
.reader-feed:last-child { border-bottom: 0; }
.reader-feed-link { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; color: var(--text); text-decoration: none; padding: 0.45rem 0.5rem; border-radius: 6px; }
.reader-feed-link:hover { background: var(--surface-light); }
.reader-feed.active .reader-feed-link { background: var(--primary-wash); }
.reader-feed.active .reader-feed-name { color: var(--primary); }
.reader-feed-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reader-feed-meta { display: inline-flex; align-items: center; gap: 0.4rem; flex-shrink: 0; }
.reader-feed-echo { color: var(--text-muted); font-size: 0.85rem; }
.reader-feed-unread { background: var(--primary-wash); color: var(--primary); border-radius: 999px; min-width: 1.4rem; text-align: center; padding: 0 0.4rem; font-size: 0.75rem; font-weight: 600; line-height: 1.4; }
/* Saved-search badges count TOTAL matches (the page shows read items too),
   so they must not wear the unread pill styling — a permanent total styled
   as an unread counter never clears and misleads. Muted outline instead. */
.reader-search-count { background: transparent; color: var(--text-muted); border: 1px solid var(--border); border-radius: 999px; min-width: 1.4rem; text-align: center; padding: 0 0.4rem; font-size: 0.75rem; font-weight: 600; line-height: 1.3; }
.reader-main { min-width: 0; }
.reader-toolbar { display: flex; justify-content: space-between; align-items: center; gap: 0.75rem; margin-bottom: 1rem; flex-wrap: wrap; }
.reader-tabs { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.reader-tab { display: inline-flex; align-items: center; min-height: 44px; padding: 0.35rem 0.95rem; color: var(--text-muted); text-decoration: none; border-right: 1px solid var(--border); }
.reader-tab:last-child { border-right: 0; }
.reader-tab.active { background: var(--primary); color: var(--primary-contrast); font-weight: 600; }
.reader-item-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.6rem; }
.reader-item { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
.reader-item summary { display: flex; flex-direction: column; gap: 0.3rem; padding: 0.8rem 1rem; cursor: pointer; list-style: none; }
.reader-item summary::-webkit-details-marker { display: none; }
.reader-item-title { font-family: Georgia, 'Iowan Old Style', 'Charter', 'Times New Roman', serif; font-size: 1.15rem; font-weight: 500; line-height: 1.3; }
.reader-item.unread .reader-item-title { font-weight: 700; }
.reader-item.unread .reader-item-title::before { content: ''; display: inline-block; width: 0.55rem; height: 0.55rem; border-radius: 50%; background: var(--primary); margin-right: 0.6rem; vertical-align: 0.08em; }
.reader-item.reader-auto-read { opacity: 0.6; }
.reader-item-meta { color: var(--text-muted); font-size: 0.82rem; }
.reader-item-body { padding: 0 1rem 1rem; display: flex; flex-direction: column; gap: 0.75rem; }
.reader-item-content { color: var(--text); line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; }
.reader-item-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; }

/* Hidden on desktop; the media query below re-enables it as the mobile drawer toggle. */
.reader-feeds-toggle { display: none; }
.reader-feeds-close { position: absolute; top: 0.75rem; right: 0.75rem; min-width: 44px; min-height: 44px; display: none; align-items: center; justify-content: center; background: transparent; border: none; color: var(--text-muted); font-size: 1.4rem; line-height: 1; cursor: pointer; border-radius: 6px; }
.reader-feeds-close:hover { background: var(--surface-light); }
@media (max-width: 720px) {
    .reader { grid-template-columns: 1fr; }
    .reader-feeds-toggle { display: inline-flex; }
    .reader-feeds-close { display: inline-flex; }
    .reader-feeds {
        position: fixed; top: 0; left: 0; bottom: 0; z-index: 110;
        width: min(85vw, 320px); overflow-y: auto; padding: 1rem;
        background: var(--surface); border: none; border-radius: 0;
        box-shadow: 2px 0 16px rgba(0, 0, 0, 0.25);
        transform: translateX(-100%); transition: transform 0.2s ease;
    }
    .reader-feeds.open { transform: translateX(0); }
}

/* Shout (reader one-time post) — overlay dialog */
.reader-shout {
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface);
    color: var(--text);
    padding: 1.25rem;
    width: min(92vw, 440px);
}
.reader-shout::backdrop { background: rgba(0, 0, 0, 0.45); }
.reader-shout-title { margin: 0 0 0.25rem; font-size: 1.1rem; font-weight: 700; }
.reader-shout-subtitle { margin: 0 0 1rem; color: var(--text-muted); font-size: 0.85rem; overflow-wrap: anywhere; }
.reader-shout-form { display: flex; flex-direction: column; gap: 0.8rem; }
.reader-shout-form label { display: flex; flex-direction: column; gap: 0.35rem; font-size: 0.9rem; font-weight: 600; color: var(--text); }
.reader-shout-form select,
.reader-shout-form textarea {
    font: inherit;
    font-size: 0.95rem;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    min-height: 44px;
}
.reader-shout-form select:focus,
.reader-shout-form textarea:focus { outline: 2px solid var(--primary); outline-offset: 1px; border-color: var(--primary); }
.reader-shout-form textarea {
    min-height: 5.5rem;
    resize: vertical;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.9rem;
    line-height: 1.5;
}
.reader-shout-actions { display: flex; justify-content: flex-end; gap: 0.5rem; margin-top: 0.25rem; }
.reader-shout-actions .action-status { flex: 1 1 auto; margin-right: auto; }

/* Variables tooltip (hover/toggle) next to the Template label */
.reader-shout-tpl-head { display: flex; flex-direction: row; align-items: center; gap: 0.35rem; }
.reader-shout-vars {
    position: relative; display: inline-flex; align-items: center;
    background: none; border: none; padding: 0; margin: 0;
    cursor: pointer; font: inherit; color: inherit;
    -webkit-tap-highlight-color: transparent;
}
/* The global `button:hover { background: var(--primary-hover) }` would paint a
   coral block behind this icon-only trigger on hover (and on touch, via the
   sticky simulated :hover). Keep it a plain glyph — no coral highlight. */
.reader-shout-vars:hover,
.reader-shout-vars:active {
    background: none;
}
.reader-shout-vars-trigger {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.15rem; height: 1.15rem; border-radius: 50%;
    background: var(--surface-light); border: 1px solid var(--border);
    color: var(--text-muted); font-size: 0.7rem; font-weight: 700;
}
.reader-shout-vars-tip {
    position: absolute; bottom: calc(100% + 0.4rem); left: 0;
    width: max-content; max-width: 300px;
    max-height: min(240px, 60vh);
    overflow-y: auto;
    padding: 0.6rem 0.75rem;
    background: var(--code-bg);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.78rem; font-weight: 400; line-height: 1.9;
    box-shadow: var(--shadow);
    opacity: 0; pointer-events: none; transition: opacity 0.15s; z-index: 20;
}
.reader-shout-vars-tip code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.75rem;
    background: var(--surface-light);
    color: var(--text);
    padding: 0.1em 0.35em;
    border-radius: 4px;
    white-space: nowrap;
    display: inline-block;
}
/* Reveal: hover only on devices with a real hover-capable fine pointer — touch
   devices get a sticky simulated :hover after a tap, which traps the tooltip
   open. On touch, the .is-open toggle is the only reveal path, and a tap
   outside the trigger dismisses it (JS document-level click listener). */
@media (hover: hover) and (pointer: fine) {
    .reader-shout-vars:hover .reader-shout-vars-tip { opacity: 1; }
}
.reader-shout-vars.is-open .reader-shout-vars-tip { opacity: 1; }

/* Reader toast (Shout success, after the overlay closes) */
.reader-toast {
    position: fixed; left: 50%; bottom: 1.5rem; transform: translateX(-50%);
    z-index: 200; padding: 0.6rem 1.1rem; border-radius: 999px;
    background: var(--primary-wash); color: var(--primary);
    border: 1px solid var(--primary);
    font-size: 0.9rem; font-weight: 600; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}

/* Reader full-text search */
.reader-search { display: flex; align-items: center; gap: 0.5rem; flex: 1 1 auto; max-width: 420px; }
.reader-search input[type="search"] { flex: 1; min-width: 0; padding: 0.45rem 0.85rem; border: 1px solid var(--border); border-radius: 999px; background: var(--surface); color: var(--text); font-size: 0.9rem; }
.reader-search input[type="search"]:focus { outline: 2px solid var(--primary); outline-offset: 1px; border-color: var(--primary); }
.reader-search-clear { color: var(--text-muted); font-size: 0.85rem; white-space: nowrap; }

/* Reader article action row — one normalized class for <a>/<button>/<summary> */
.action-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    padding: 0.35rem 0.6rem;
    min-height: 44px;
    font: inherit;
    font-size: 0.8rem;
    line-height: 1;
    color: var(--text);
    background: var(--surface-light);
    border: 1px solid var(--border);
    border-radius: 6px;
    text-decoration: none;
    cursor: pointer;
    box-sizing: border-box;
    list-style: none;
    transition: background 0.12s ease, border-color 0.12s ease;
}
.action-btn::-webkit-details-marker { display: none; }
.action-btn:hover { background: var(--surface); border-color: var(--text-muted); }
.action-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.action-btn--primary { background: var(--primary); border-color: var(--primary); color: var(--primary-contrast); font-weight: 600; }
.action-btn--primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
.action-btn__star { color: var(--text-muted); }
.action-btn--star.is-starred { border-color: var(--accent); }
.action-btn--star.is-starred .action-btn__star { color: var(--accent); }

/* Keep scrolled-to reader cards clear of the sticky navbar */
.reader-entry { scroll-margin-top: 72px; }

/* Tier 1 — readability typography */
.reader-item-content { max-width: 65ch; font-size: 1rem; }
.reader-item-content p { margin: 0 0 0.75rem; }
.reader-item-content blockquote { margin: 0.5rem 0; padding: 0.25rem 0.9rem; border-left: 3px solid var(--border); color: var(--text-muted); }
.reader-item-content pre { background: var(--surface); border: 1px solid var(--border); padding: 0.75rem; border-radius: 6px; overflow-x: auto; font-size: 0.85rem; line-height: 1.45; }
.reader-item-content code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9em; background: var(--surface); padding: 0.1em 0.35em; border-radius: 3px; }
.reader-item-content pre code { background: none; padding: 0; font-size: 1em; }
.reader-item-content img { max-width: 100%; height: auto; border-radius: 6px; }
.reader-item-content ul, .reader-item-content ol { margin: 0.25rem 0 0.75rem 1.6rem; }
.reader-item-content li { margin-bottom: 0.25rem; }
.reader-item-content h1, .reader-item-content h2, .reader-item-content h3, .reader-item-content h4 { margin: 1rem 0 0.4rem; line-height: 1.25; }

/* Tier 1 — density toggle (compact) */
.reader[data-density="compact"] .reader-item summary { padding: 0.5rem 0.75rem; }
.reader[data-density="compact"] .reader-item-body { padding: 0 0.75rem 0.75rem; }
.reader[data-density="compact"] .reader-item-title { font-size: 0.95rem; }
.reader[data-density="compact"] .reader-item-content { font-size: 0.88rem; line-height: 1.5; }
.reader[data-density="compact"] .reader-item-list { gap: 0.4rem; }

/* Tier 1 — keyboard current-item highlight */
.reader-entry.reader-current { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 10px; }

/* Tier 1 — undo toast */
.reader-undo-toast {
    position: fixed; bottom: 1rem; left: 50%; transform: translateX(-50%);
    display: flex; align-items: center; gap: 0.75rem;
    background: var(--surface); color: var(--text);
    border: 1px solid var(--border); border-radius: 8px;
    padding: 0.6rem 0.9rem; font-size: 0.9rem;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25); z-index: 100;
}
.reader-undo-toast button { font: inherit; font-size: 0.85rem; font-weight: 600; background: none; border: none; color: var(--primary); cursor: pointer; text-decoration: underline; padding: 0.1rem 0.25rem; }

/* Tier 1 — keyboard shortcut overlay */
.reader-shortcuts { border: 1px solid var(--border); border-radius: 10px; background: var(--surface); color: var(--text); padding: 1rem 1.25rem; max-width: 340px; }
.reader-shortcuts::backdrop { background: rgba(0, 0, 0, 0.4); }
.reader-shortcuts h2 { margin: 0 0 0.5rem; font-size: 1rem; }
.reader-shortcuts h2:not(:first-child) { margin-top: 0.9rem; }
.reader-shortcuts table { border-collapse: collapse; width: 100%; }
.reader-shortcuts kbd { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background: var(--surface-light); border: 1px solid var(--border); border-bottom-width: 2px; border-radius: 4px; padding: 0.05rem 0.35rem; font-size: 0.8rem; }
.reader-shortcuts code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background: var(--surface-light); border: 1px solid var(--border); border-radius: 4px; padding: 0.05rem 0.35rem; font-size: 0.78rem; }
.reader-shortcuts td { padding: 0.3rem 0.5rem; font-size: 0.85rem; }
.reader-shortcuts td:first-child { text-align: right; white-space: nowrap; }

/* Tier 1 — toolbar right group */
.reader-toolbar-right { display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }

/* The '?' keyboard-shortcuts button is desktop-only: touch devices have no
   keyboard, and the toolbar already wraps tightly on narrow screens. */
@media (max-width: 720px) {
    .reader-shortcuts-btn { display: none; }
}

/* Tier 2 — letter avatar + fetch-error badge */
.reader-feed-avatar { display: inline-flex; align-items: center; justify-content: center; width: 1.4rem; height: 1.4rem; border-radius: 50%; background: var(--primary-wash); color: var(--primary); font-size: 0.7rem; font-weight: 700; flex-shrink: 0; }
.reader-feed-error { color: #d97706; flex-shrink: 0; }

/* Tier 2 — toggle buttons show their pressed state.
   Solid fill instead of the previous wash-tint-only treatment, to match
   .reader-tab.active's "selected" language above — the two adjacent
   toggle groups (Unread/All/Starred/Today vs. Compact/Auto-read/Full
   text) previously used different visual conventions for the same
   "currently on" state. UX audit finding 8 (2026-09-08). */
.reader-toolbar-right .btn-sm[aria-pressed="true"] {
    background: var(--primary);
    border-color: var(--primary);
    color: var(--primary-contrast);
    font-weight: 600;
}

/* Compact density: title only, no feed/author/date meta line */
.reader[data-density="compact"] .reader-item-meta { display: none; }

/* Tier 2 — OPML import on the Feeds page */
.opml-actions { display: flex; flex-direction: column; gap: 0.6rem; }
.opml-import-form { display: flex; flex-direction: column; gap: 0.4rem; }
.opml-import-form textarea { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.8rem; padding: 0.5rem; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); color: var(--text); }

/* Tier 3 — reader media, shouted badge, feeds drawer, poll pill */
.reader-item-image { max-width: 100%; height: auto; border-radius: 8px; margin-bottom: 0.6rem; display: block; }
.reader-item-audio { width: 100%; margin-bottom: 0.6rem; }
.reader-item-shouted { color: var(--primary); font-weight: 600; }
.reader-badge-delivery { text-decoration: none; font-size: 0.72rem; padding: 0.15rem 0.4rem; vertical-align: middle; }
.reader-badge-delivery:hover { opacity: 0.85; text-decoration: underline; }
.reader-save-search-btn { font-size: 0.85rem; padding: 0.4rem 0.75rem; white-space: nowrap; }
.reader-new-pill { position: fixed; top: 64px; left: 50%; transform: translateX(-50%); z-index: 110; background: var(--primary-wash); color: var(--primary); border: 1px solid var(--primary); border-radius: 999px; padding: 0.4rem 0.9rem; font-size: 0.85rem; font-weight: 600; cursor: pointer; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25); }
@media (max-width: 720px) {
    .reader-new-pill { top: 116px; }
}

/* ── Reader: bolder identity (impeccable critique fixes) ──────────────────── */
.reader-heading { font-size: 1.8rem; font-weight: 800; letter-spacing: -0.01em; }
.reader-heading::after { content: ''; display: block; width: 3rem; height: 3px; border-radius: 2px; background: var(--primary); margin-top: 0.4rem; }

/* Touch targets: WCAG 2.5.8 AA + impeccable <44px ban */
.reader-toolbar .btn-sm { min-height: 44px; }
.reader-search input[type="search"] { min-height: 44px; }

/* Action-row grouping: triage (read/star) vs cross-post (echo/shout) */
.action-group { display: inline-flex; gap: 0.4rem; align-items: center; }
.action-group--echo { margin-left: auto; padding-left: 0.6rem; border-left: 1px solid var(--border); }
@media (max-width: 720px) {
    .action-group--echo { margin-left: 0; padding-left: 0; border-left: none; }
}

/* Inline SVG icons (one stroke/weight, replaces emoji glyphs) */
.icon { width: 0.95em; height: 0.95em; flex-shrink: 0; }

/* Lazy-body loading shimmer */
.reader-item-content.is-loading { position: relative; min-height: 3rem; }
.reader-item-content.is-loading::after {
    content: ''; position: absolute; inset: 0; border-radius: 4px;
    background: linear-gradient(90deg, var(--surface-light) 25%, var(--surface) 50%, var(--surface-light) 75%);
    background-size: 200% 100%; animation: reader-shimmer 1.2s ease-in-out infinite;
}

/* Reader load more */
.reader-load-more-wrap { display: flex; justify-content: center; margin: 1.5rem 0 2rem; }
.reader-load-more { min-width: 140px; justify-content: center; font-weight: 600; }
.reader-load-more.is-loading { opacity: 0.6; pointer-events: none; }

/* Reader folders */
.reader-folder-group { margin-bottom: 0.75rem; }
.reader-folder-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.35rem 0.2rem; border-bottom: 1px solid var(--border); }
.reader-folder-toggle { display: inline-flex; align-items: center; gap: 0.35rem; background: none; border: none; color: var(--text); font-weight: 700; font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.04em; cursor: pointer; padding: 0; }
.reader-folder-toggle:hover { color: var(--primary); }
.reader-folder-arrow { font-size: 0.75rem; transition: transform 0.15s ease; display: inline-block; }
.reader-folder-meta { display: inline-flex; align-items: center; gap: 0.35rem; }
.reader-folder-mark-read { background: none; border: 1px solid transparent; color: var(--text-muted); cursor: pointer; border-radius: 4px; padding: 0.1rem 0.3rem; font-size: 0.8rem; line-height: 1; }
.reader-folder-mark-read:hover { color: var(--primary); border-color: var(--primary); background: var(--primary-wash); }
.reader-folder-group.is-collapsed .reader-feed-list { display: none; }
.reader-folder-group.is-collapsed .reader-folder-arrow { transform: rotate(-90deg); }

/* Reader Compose Desk */
.reader-compose { border: 1px solid var(--border); border-radius: 12px; background: var(--surface); color: var(--text); padding: 1.25rem 1.5rem; max-width: 580px; width: 92%; box-sizing: border-box; }
.reader-compose::backdrop { background: rgba(0, 0, 0, 0.45); }
.compose-header { margin-bottom: 1rem; }
.compose-title { margin: 0 0 0.25rem; font-size: 1.15rem; font-weight: 700; }
.compose-subtitle { margin: 0; color: var(--text-muted); font-size: 0.85rem; overflow-wrap: anywhere; }
.compose-section { margin-bottom: 1rem; display: flex; flex-direction: column; gap: 0.4rem; }
.compose-label { font-size: 0.85rem; font-weight: 600; color: var(--text); text-transform: uppercase; letter-spacing: 0.04em; }
.compose-dest-list { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.compose-dest-label { display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.35rem 0.6rem; border: 1px solid var(--border); border-radius: 6px; background: var(--surface-light); font-size: 0.85rem; cursor: pointer; user-select: none; }
.compose-dest-label:hover { border-color: var(--primary); }
.compose-dest-label:has(input:checked) { border-color: var(--primary); background: var(--primary-wash); color: var(--primary); font-weight: 600; }
.compose-dest-counter { font-size: 0.78rem; color: var(--text-muted); margin-left: 0.2rem; }
.compose-dest-counter.is-over { color: #dc2626; font-weight: 700; }
.compose-body-head { display: flex; align-items: center; justify-content: space-between; }
.compose-comment-input { flex: 1; padding: 0.35rem 0.6rem; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); color: var(--text); font-size: 0.85rem; margin-right: 0.4rem; }
.reader-compose textarea { width: 100%; box-sizing: border-box; padding: 0.6rem 0.8rem; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); color: var(--text); font-family: inherit; font-size: 0.95rem; resize: vertical; min-height: 90px; }
.reader-compose textarea:focus { outline: 2px solid var(--primary); outline-offset: 1px; border-color: var(--primary); }
.compose-media-row { display: flex; gap: 1rem; align-items: flex-start; padding: 0.6rem; border: 1px solid var(--border); border-radius: 8px; background: var(--surface-light); }
.compose-image-thumb { width: 80px; height: 80px; object-fit: cover; border-radius: 6px; border: 1px solid var(--border); flex-shrink: 0; }
.compose-media-controls { flex: 1; display: flex; flex-direction: column; gap: 0.4rem; min-width: 0; }
.compose-checkbox-inline { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; font-weight: 600; cursor: pointer; }
.compose-alt-label { display: flex; flex-direction: column; gap: 0.2rem; font-size: 0.8rem; color: var(--text-muted); font-weight: 600; }
.compose-alt-label input { padding: 0.35rem 0.6rem; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); color: var(--text); font-size: 0.85rem; width: 100%; box-sizing: border-box; }
.compose-actions { display: flex; justify-content: flex-end; align-items: center; gap: 0.5rem; margin-top: 1.25rem; }
.compose-results { margin-top: 1rem; padding: 0.6rem 0.8rem; border-radius: 8px; font-size: 0.85rem; display: flex; flex-direction: column; gap: 0.35rem; }
.compose-res-item { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.compose-res-item.is-success { color: #16a34a; }
.compose-res-item.is-error { color: #dc2626; }

/* ── A2: prefers-contrast: more ──────────────────────────────────────────────
   Increases border and text contrast when the user's OS is in high-contrast
   mode. Primarily sharpens the subtle border-on-surface aesthetic and bumps
   text weight for readability. */
@media (prefers-contrast: more) {
    body {
        font-weight: 450;
    }
    :root {
        --border: oklch(0.45 0.025 var(--hue-neutral));
    }
    :root[data-theme="light"] {
        --border: oklch(0.55 0.02 var(--hue-neutral));
    }
    .nav-logout {
        border-width: 2px;
    }
}
@keyframes reader-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }

/* Admin user-delete form: the confirm input stays narrow so the actions
   cell does not blow out; the row wraps on mobile like sibling forms. */
.admin-delete-form {
    margin-top: 0.35rem;
}
.admin-delete-form .admin-delete-input {
    flex: 0 1 12rem;
    min-width: 8rem;
    font-size: 0.8125rem;
    padding: 0.25rem 0.45rem;
}
