/* ---- Fonts: Mona Sans (GitHub, self-hosted variable — one family exposing the
   wght 200–900 + wdth 75–125 axes). Width is set per role with
   `font-variation-settings: 'wdth' N` (the font-stretch property/descriptor does
   NOT drive the axis in WebKit, so we set the axis directly):
     body + UI       wdth 100 (default — no override needed)   (was Inter)
     display titles  wdth 125 (Expanded)                       (was Sentient)
     helper + code   wdth 75  (Condensed)                      (was Geist Mono) ---- */
@font-face {
    font-family: 'Mona Sans';
    src: url('/type/MonaSansVF.woff2') format('woff2');
    font-weight: 200 900;
    font-stretch: 75% 125%;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Mona Sans';
    src: url('/type/MonaSansVF-Italic.woff2') format('woff2');
    font-weight: 200 900;
    font-stretch: 75% 125%;
    font-style: italic;
    font-display: swap;
}
/* Overpass (Google Fonts, self-hosted; trial replacement for Mona Sans as the
   body face). Weight 100-900 variable; no wdth axis, so 'wdth' overrides on
   body text (only .onboard-title) are simply ignored. Split by unicode-range
   exactly as Google serves it, so a Latin reader fetches ~39kB, not all 277kB. */
@font-face {
    font-family: 'Overpass';
    src: url('/type/Overpass-Roman-latin.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    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;
}
@font-face {
    font-family: 'Overpass';
    src: url('/type/Overpass-Roman-latin-ext.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'Overpass';
    src: url('/type/Overpass-Roman-vietnamese.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
    font-family: 'Overpass';
    src: url('/type/Overpass-Roman-cyrillic.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-family: 'Overpass';
    src: url('/type/Overpass-Roman-cyrillic-ext.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@font-face {
    font-family: 'Overpass';
    src: url('/type/Overpass-Italic-latin.woff2') format('woff2');
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
    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;
}
@font-face {
    font-family: 'Overpass';
    src: url('/type/Overpass-Italic-latin-ext.woff2') format('woff2');
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: 'Overpass';
    src: url('/type/Overpass-Italic-vietnamese.woff2') format('woff2');
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
    unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
    font-family: 'Overpass';
    src: url('/type/Overpass-Italic-cyrillic.woff2') format('woff2');
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
    font-family: 'Overpass';
    src: url('/type/Overpass-Italic-cyrillic-ext.woff2') format('woff2');
    font-weight: 100 900;
    font-style: italic;
    font-display: swap;
    unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

/* Mona Sans Mono — true monospace cut, same wght + wdth axes. */
@font-face {
    font-family: 'Mona Sans Mono';
    src: url('/type/MonaSansMonoVF.woff2') format('woff2');
    font-weight: 200 900;
    font-stretch: 75% 125%;
    font-style: normal;
    font-display: swap;
}

:root {
    /* Dark by default (cool, near-monochrome). Same philosophy as the light
       transcript island (see .transcript-col below), inverted: structure via
       hairline borders, not fills/shadows; interactive/active states use the
       near-WHITE ink (--accent === --text family) rather than a colour. */
    color-scheme: dark;
    --bg: #16181c;
    --surface: #16181c;
    --surface-warm: #23262d;
    --border: #2c313a;
    --text: #e5e8ec;
    --text-mid: #a2aab4;
    --text-soft: #5c646e;   /* dark-mode helper text (dates, handles, icons) — a touch dimmer */
    --accent: #7e6dff;        /* brand accent (soft violet) */
    --accent-hover: #6a58f0;
    --on-accent: #ffffff;     /* text/icons sitting on an --accent fill */
    --danger: #e0554d;

    /* Corner-radius scale (reinterpreted from the design: cards 8, controls/
       items 4, tiny chips 2 — tighter than the old flat 12). */
    --radius: 8px;
    --radius-sm: 4px;
    --radius-xs: 2px;
    --outline: 1px solid var(--border);
    /* On dark, shadows read as deeper black (structure still comes from borders). */
    --card-shadow: 0 1px 2px rgba(0, 0, 0, 0.25), 0 2px 6px rgba(0, 0, 0, 0.3);
    /* Composer floats above the transcript, so it gets a touch more lift than a card. */
    --composer-shadow: 0 2px 6px rgba(0, 0, 0, 0.35), 0 8px 24px rgba(0, 0, 0, 0.5);
    --offset: 12px; /* inset of the floating containers from the viewport edge */
    --avatar: 35px; /* account (sidebar) + message avatars share this; forum icon is separate */
    --measure: 850px; /* reading width of the transcript + composer (comfortable line length) */

    /* Type scale — three sizes. Title is the big display (forum name); thread
       titles and post copy are body; meta is helper. */
    --fs-title: 24px;  /* forum name, modal headings */
    --fs-body: 15px;   /* UI body copy, thread titles */
    --fs-post: 17px;   /* transcript post text — its own size, independent of --fs-body */
    --fs-helper: 12px; /* timestamps, handles, counts, hints */

    /* One Mona Sans family everywhere (body + titles); role width is applied via
       font-variation-settings 'wdth' at the point of use (see --wdth-* below).
       --font-mono covers helper text and code alike. */
    /* Overpass (body). Mona Sans's @font-face blocks and files are kept, so
       'Mona Sans' here restores the previous face. */
    --font-body: 'Overpass', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    --font-mono: 'Mona Sans Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
    /* wght/wdth axis values driven into font-variation-settings by consumers.
       Body is weight 410 / width 100 (set on `body`). */
    --wdth-title: 95;    /* titles: weight 400 (per-rule), width 95 */
    --wght-narrow: 440;  /* ex-mono roles: Mona Sans Mono at weight 440, width 90 */
    --wdth-narrow: 95;
}

/* "Mixed mode": the app shell (sidebar, header, modals) stays dark; the
   transcript + composer — where you actually read/write — become a light
   island, Slack-style. The light palette (the app's original) is scoped to
   the one column instead of the whole app; the accent vars are the same in
   both palettes, so only the neutrals are redefined here. #reaction-picker
   is included because it's a fixed-position popover invoked from a light post
   but lives outside .transcript-col in the DOM, so it wouldn't otherwise
   inherit these variables. */
.transcript-col,
#reaction-picker {
    color-scheme: light;
    --bg: #ffffff;
    --surface: #ffffff;
    --surface-warm: #f1f3f5;
    --border: #e3e8eb;
    --text: #111214;
    --text-mid: #646b74;
    --text-soft: #98a1aa;
    --danger: #c0392b;
    --card-shadow: 0 1px 2px rgba(17, 18, 20, 0.03), 0 2px 6px rgba(17, 18, 20, 0.035);
    --composer-shadow: 0 2px 6px rgba(17, 18, 20, 0.05), 0 8px 24px rgba(17, 18, 20, 0.08);
    /* Very faint edge shared by the floating transcript widgets (header pills,
       composer). */
    --hairline: rgba(17, 18, 20, 0.06);
}
.transcript-col {
    background: var(--bg);
    border-radius: var(--radius);
    /* Clip the sticky header / posts-container / composer to the rounded
       corners; each still scrolls internally via its own overflow. */
    overflow: hidden;
}

body { font-feature-settings: 'liga' 1, 'calt' 1; }

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; width: 100%; height: 100%; }
body {
    font-family: var(--font-body);
    color: var(--text);
    background: var(--bg);
    font-size: var(--fs-body);
    font-weight: 410;
    line-height: 1.6;
    letter-spacing: -0.011em;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.hidden { display: none !important; }

#app {
    width: 100%;
    height: 100%;
}

/* ---- Login ---- */
.login-screen {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(44, 42, 40, 0.2);
    backdrop-filter: blur(8px);
    z-index: 2000;
}

/* Landing variant: the login form is the whole page, not a modal over the app. */
.login-screen.landing {
    background: var(--bg);
    backdrop-filter: none;
}
.login-screen.landing .close-login-btn {
    display: none;
}

.login-container {
    width: min(380px, calc(100vw - 40px));
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
    padding: 32px;
    position: relative;
}
/* On the full-page landing the form sits on the page itself — no card. */
.login-screen.landing .login-container {
    border: none;
    box-shadow: none;
    background: transparent;
}

.close-login-btn {
    position: absolute;
    right: 14px;
    top: 14px;
    width: 28px;
    height: 28px;
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--text-soft);
    cursor: pointer;
    font-size: var(--fs-body);
    transition: color 0.2s;
}

.close-login-btn:hover {
    color: var(--text);
}

.login-container h1 {
    margin: 0;
    font-size: 28px;
    font-weight: 700;
    letter-spacing: -0.03em;
    line-height: 1.1;
}

.login-container p {
    margin: 6px 0 0;
    color: var(--text-soft);
    font-size: var(--fs-body);
}

/* ---- Buttons ---- */
#user-pill,
.btn-icon {
    width: 34px;
    height: 34px;
    border: none;
    background: transparent;
    color: var(--text-soft);
    display: grid;
    place-items: center;
    cursor: pointer;
    transition: all 0.2s;
    font-size: var(--fs-body);
}

#user-pill:hover,
.btn-icon:hover {
    background: rgba(0, 0, 0, 0.05);
    color: var(--text);
}

.pane-content {
    min-height: 0;
    overflow: auto;
}

.thread-item {
    position: relative;
    padding: 10px 20px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    background: transparent;
    display: flex;
    flex-direction: column;
    gap: 2px;
    transition: background 0.12s;
}
.thread-item:hover,
.thread-item.active,
.thread-item.active:hover { background: var(--surface-warm); }

.thread-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.thread-title {
    margin: 0;
    min-width: 0;
    flex: 1;
    font-size: var(--fs-body);
    font-weight: 400;            /* Regular */
    letter-spacing: -0.01em;
    line-height: 1.2;
    color: var(--text);
    overflow-wrap: anywhere;
}
.thread-item.unread .thread-title { font-weight: 600; }
/* Private-thread lock badge, inline before the title. */
.thread-title .thread-lock {
    display: inline-block;
    vertical-align: -1px;
    margin-right: 5px;
    color: var(--text-soft);
    flex-shrink: 0;
}

/* Private-post lock badge in the bookmarks list, same treatment as .thread-lock. */
.post-header .bookmark-private-lock {
    display: inline-block;
    vertical-align: -1px;
    color: var(--text-soft);
    flex-shrink: 0;
}

/* Private threads are text-only in Phase 1: no media attach in the composer. */
.composer-no-media .composer-attach { display: none; }
/* Compact one-line notification events ("X added you to <thread> – <forum> 2m ago"),
   distinct from the full post cards mentions render as. */
.notif-line {
    display: flex;
    align-items: flex-start;
    padding: 12px 0;
    font-size: var(--fs-body);
    line-height: 1.5;
    color: var(--text);
}
.notif-line-avatar {
    width: 20px;             /* same as the thread-card avatar */
    height: 20px;
    flex-shrink: 0;
    /* Centered in the 35px post-avatar column ((35-20)/2 = 7.5px each side), then a
       14px gap to the text — so it lines up with the post text inset (49px). */
    margin-left: 7.5px;
    margin-right: 21.5px;
    margin-top: 2px;
    border-radius: calc(var(--radius-xs) + 1px);   /* match the thread-card avatar */
    object-fit: cover;
}
.notif-line-avatar-ph { background: var(--surface-warm); border: var(--outline); }
.notif-line-body { flex: 1; min-width: 0; }
.notif-line-actor { font-weight: 600; }
.notif-line-link {
    appearance: none;
    -webkit-appearance: none;
    border: none;
    background: none;
    padding: 0;
    font: inherit;
    color: var(--accent);
    cursor: pointer;
}
.notif-line-link:hover { text-decoration: underline; }
/* Shared helper/mono text treatment: timestamps, handles, counts, hints,
   and small mono-styled controls all read at --fs-helper in --font-mono,
   narrow weight/width. Kept as one rule so the trio stays in sync. */
.notif-line-time,
.members-you,
.thread-time,
.thread-post-count,
.thread-header-stats,
.thread-share-btn,
.thread-header-edit,
.thread-admin-hide-btn,
.load-earlier button,
.post-header,
.post-time,
.replying-to,
.file-chip-name,
.file-chip-size,
.reply-btn,
.edit-btn,
.delete-btn,
.permalink-btn,
.tag-clear,
.hover-card-handle,
.quote-btn,
.mention-handle,
.composer-gate,
.form-group label,
.field-hint,
.request-date,
.error-message,
.btn-remove-image,
.fp-empty,
#user-pill,
#user-pill.logged-out,
.forum-description,
.view-toggle-btn,
.tag-row-count,
.post-moderated-bar,
.bookmark-forum-tag,
.bookmark-goto {
    font-size: var(--fs-helper); font-family: var(--font-mono); font-variation-settings: 'wght' var(--wght-narrow), 'wdth' var(--wdth-narrow);
}
.notif-line-time {
    color: var(--text-soft);
}

/* Private-thread members modal. */
.members-list { display: flex; flex-direction: column; gap: 2px; margin: 10px 0 16px; max-height: 320px; overflow-y: auto; }
.members-row { display: flex; align-items: center; gap: 10px; padding: 6px 4px; }
.members-avatar { width: 28px; height: 28px; border-radius: var(--radius-sm); object-fit: cover; flex-shrink: 0; }
.members-avatar-ph { background: var(--surface-warm); border: var(--outline); }
.members-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.members-you { color: var(--text-soft); }
.members-remove { border: none; background: transparent; color: var(--danger); font-size: var(--fs-helper); cursor: pointer; }
.members-remove:hover { text-decoration: underline; }
.members-add { display: flex; gap: 8px; margin-bottom: 14px; }
.members-add input {
    flex: 1;
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 10px 12px;
    background: var(--surface);
    color: var(--text);
    font: inherit;
}
.members-add input:focus { outline: none; border-color: var(--accent); }
.members-leave { width: 100%; color: var(--danger); }
/* Autocomplete under the members "add by handle" input (reuses .mention-dropdown's
   box). Two-class selector so it beats .mention-dropdown's own position rules,
   which otherwise win (equal specificity, defined later) and float it upward. */
.members-add-wrap { position: relative; }
.members-add-wrap .members-suggest {
    position: absolute;
    top: calc(100% + 4px);
    bottom: auto;
    left: 0;
    right: 0;
    z-index: 10;
    max-height: 220px;
    overflow-y: auto;
}

.thread-time,
.thread-post-count {
    flex-shrink: 0;
    color: var(--text-soft);
    white-space: nowrap;
}

/* Right end of the title row: the avatar stack, with an edit button that fades
   in over it on hover (author only). */
.thread-row-end {
    position: relative;
    display: flex;
    align-items: center;
    flex-shrink: 0;
}
.thread-avatar-stack {
    display: flex;
    align-items: center;
    gap: 2px;
    flex-shrink: 0;
    transition: opacity 0.15s;
}
.thread-edit-btn {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-soft);
    cursor: pointer;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s, background 0.15s, color 0.15s;
}
.thread-edit-btn svg {
    display: block;
    width: 15px; height: 15px;
    stroke: currentColor; stroke-width: 2; fill: none;
    stroke-linecap: round; stroke-linejoin: round;
}
.thread-edit-btn:hover { color: var(--text); background: rgba(0, 0, 0, 0.06); }
.thread-item.editable:hover .thread-avatar-stack { opacity: 0; }
.thread-item.editable:hover .thread-edit-btn { opacity: 1; pointer-events: auto; }
.thread-avatar {
    width: 20px;
    height: 20px;
    border-radius: calc(var(--radius-xs) + 1px);
    object-fit: cover;
    background: var(--surface-warm);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 9px;
    font-weight: 700;
    color: var(--text); /* black — a 9px initial needs the contrast */
}
/* Overflow chip: "+N" more participants. */
.thread-avatar-more {
    width: auto;
    min-width: 20px;
    padding: 0 4px;
    background: var(--text);
    color: var(--surface);
    letter-spacing: -0.02em;
}

/* ---- Posts pane ---- */
.posts-container {
    flex: 1;
    display: flex;
    flex-direction: column;
    /* We control scroll position in JS (pin-to-bottom); the browser's scroll
       anchoring would otherwise fight it, snapping back to keep the top element
       stable as images grow the content. */
    overflow-anchor: none;
}
.posts-container > * { flex-shrink: 0; }

/* Cap the conversation to a comfortable reading width, centered. The composer
   matches so it stays aligned with the messages. posts-inner fills the scroll
   viewport so the header pins to the top while only the posts hug the bottom
   (chat style) when a thread is short; when it overflows, normal scrolling. */
.posts-inner {
    width: 100%;
    max-width: var(--measure);
    margin-inline: auto;
    flex-grow: 1;
    display: flex;
    flex-direction: column;
}
/* Chat order (default): posts hug the bottom. Traditional order: top-aligned. */
.posts-inner > .posts-list { margin-top: auto; }
.posts-inner.layout-oldest > .posts-list { margin-top: 0; }

/* ---- Thread header: two glass pills fixed in the transcript's top corners ----
   #thread-float spans the top edge (outside the scroller, so posts scroll
   underneath); it's click-through, only the pills catch pointer events. */
.thread-float {
    position: absolute;
    /* Same inset as the forum pane's own padding, so the pills line up with the
       picker/account row across the app. */
    top: var(--offset); left: var(--offset); right: var(--offset);
    z-index: 5;
    display: flex;
    align-items: stretch;   /* both pills match the taller one's height */
    justify-content: space-between;
    gap: 8px;
    pointer-events: none;
}
.thread-float.suppressed { display: none; }   /* a list view (bookmarks etc.) is open */
.thread-float-pill {
    pointer-events: auto;
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    padding: 8px 10px 8px 16px;
    /* Matches the forum pane's top controls (.forum-picker-btn, .account-cluster),
       which sit at this same 12px inset inside an 8px-radius pane. */
    border-radius: var(--radius);
    background: color-mix(in srgb, var(--bg) 72%, transparent);
    -webkit-backdrop-filter: blur(12px) saturate(1.4);
    backdrop-filter: blur(12px) saturate(1.4);
    box-shadow: var(--card-shadow);
}
.thread-float-pill:empty { display: none; }   /* right pill with no controls */
/* One hairline for all three floating widgets. Outline, not border, so it adds
   no size (the posts' top padding is tuned to the pills' exact height). */
.thread-float-pill,
#post-form {
    outline: 1px solid var(--hairline);
    outline-offset: -1px;
}
.thread-float .thread-sticky-title { margin-right: 6px; }   /* air after the title */
/* The right-hand group: manage pill (owner/member/admin controls), then the
   view-controls pill, adjacent. Grouped so .thread-float's space-between keeps
   them together at the end (as three loose items the manage pill would drift
   to the middle). */
.thread-float-end { display: flex; gap: 8px; flex-shrink: 0; }
.thread-float-manage,
.thread-float-right { padding-left: 10px; }
.thread-float .thread-header-stats { flex-wrap: nowrap; gap: 10px; white-space: nowrap; }
.thread-float .thread-header-btn--icon { background: transparent; }
.thread-float .post-filter-bar { margin-top: 0; }

.thread-header-stats {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px;
    color: var(--text-soft);
}
.thread-stat { display: inline-flex; align-items: center; gap: 5px; line-height: 1; }
.thread-stat svg { display: block; flex-shrink: 0; }

/* Thread-header buttons (share, edit, members, admin hide). */
.thread-share-btn,
.thread-header-edit,
.thread-admin-hide-btn {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    appearance: none;
    -webkit-appearance: none;
    border: none;
    border-radius: var(--radius-sm);
    background: var(--surface);
    box-shadow: none;
    color: var(--text-soft);
    cursor: pointer;
    transition: color 0.15s;
}
.thread-share-btn:hover,
.thread-header-edit:hover,
.thread-admin-hide-btn:hover { color: var(--text); }
.thread-share-btn svg,
.thread-header-edit svg,
.thread-admin-hide-btn svg { display: block; }
.thread-share-btn.copied { color: var(--accent); }
/* Icon-only (square) — the labels are hidden. */
.thread-header-btn--icon { padding: 6px; }
.thread-header-btn--icon span { display: none; }

/* Compact sticky bar — revealed once the full header scrolls out of view.
   Inset var(--offset) on the sides only; it must cap the very top (top: 0) so
   the transcript can't scroll through above it. Its inner content is centred to
   the reading column so the title sits directly above the first post. */
.thread-sticky-bar {
    position: absolute;
    top: 0; left: var(--offset); right: var(--offset);
    z-index: 5;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    /* Divider aligns with .sidebar-top's: that box is 45px (36 + 8 pad-bottom +
       1 border) and sits 12px below the app top (the column's top padding), so
       its divider is at 57px. This bar starts at the top, so height = 57px. */
    height: 57px;
    /* Align the title with the posts below. Padding % resolves against the
       containing block (the full column), while the bar itself is shifted right
       by its 12px left offset — so subtract that 12px, or the content lands 12px
       past the posts. Floor 4px → 12 (offset) + 4 = 16px, matching the posts'
       16px side padding on narrow columns. */
    padding: 0 max(4px, calc((100% - var(--measure)) / 2 - 12px));
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    /* Hidden until the full header scrolls away; the observer adds .shown. */
    opacity: 0;
    transform: translateY(-100%);
    pointer-events: none;
    transition: opacity 0.18s ease, transform 0.18s ease;
}
.thread-sticky-bar.shown {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}
/* Fully hidden when the transcript isn't the active view (e.g. bookmarks open). */
.thread-sticky-bar.suppressed { display: none; }
@media (prefers-reduced-motion: reduce) {
    .thread-sticky-bar { transition: none; }
}
.thread-sticky-title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--font-mono); font-variation-settings: 'wght' var(--wght-narrow), 'wdth' var(--wdth-narrow);
    font-size: var(--fs-body);
    font-weight: 500;
    color: var(--text);
}
.post-composer #post-form { max-width: var(--measure); margin-inline: auto; }

.load-earlier {
    text-align: center;
    padding: 12px 0 4px;
}

.load-earlier button {
    background: none;
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text-soft);
    padding: 6px 14px;
    cursor: pointer;
}

.load-earlier button:hover:not(:disabled) {
    border-color: var(--accent);
    color: var(--accent);
}

.load-earlier button:disabled {
    opacity: 0.5;
    cursor: default;
}

.post {
    border: 0;
    border-radius: 0;
    background: transparent;
    padding: 10px 0;
    margin-bottom: 0;
    display: flex;
    gap: 14px;
}
/* A freshly-sent post fades/rises in as it's appended (no full re-render). */
@keyframes post-enter {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}
.post-enter-anim { animation: post-enter 0.22s ease both; }
@media (prefers-reduced-motion: reduce) {
    .post-enter-anim { animation: none; }
}

.post.permalink-target {
    background: var(--surface-warm);
    border-radius: 8px;
    padding: 14px 14px;
    margin: 0 -14px;
}

.post-avatar,
.post-avatar-placeholder {
    width: var(--avatar);
    height: var(--avatar);
    margin-top: 5px;
    border-radius: var(--radius);
    object-fit: cover;
    background: var(--surface-warm);
    flex-shrink: 0;
}

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

.post-header {
    display: flex;
    align-items: baseline;
    gap: 10px;
    color: var(--text-soft);
}

.post-author {
    color: var(--text-soft);
    font-weight: 400;   /* match the forum blurb (helper size, mono, regular) */
}

.replying-to {
    margin-left: 4px;
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    color: var(--text-soft);
    cursor: pointer;
}
.replying-to:hover { color: var(--text); text-decoration: underline; }

.post-content {
    margin-top: 3px;
    color: var(--text);
    overflow-wrap: anywhere;
    /* Reading comfort: its own size/weight, independent of --fs-body. */
    font-size: var(--fs-post);
    font-weight: 420;
    line-height: 1.5;
    letter-spacing: 0;   /* the rest of the UI inherits body's -0.011em */
}

.post-content p { margin: 0; }
.post-content p + p { margin-top: 10px; }
/* Blockquote: tight left inset + a rule in the thread-header border colour. */
.post-content blockquote {
    margin: 8px 0;
    padding-left: 12px;
    border-left: 1px solid var(--border);
}
/* Lists: drop the browser's ~40px indent to the same tight inset as the quote. */
.post-content ul,
.post-content ol { margin: 8px 0; padding-left: 12px; }
/* Near-monochrome: links carry an underline (colour no longer differentiates). */
.post-content a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--text-soft); }
.post-content a:hover { text-decoration-color: var(--text); }
.post-content pre {
    background: var(--surface-warm);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px;
    overflow: auto;
    font-size: 1em; font-family: var(--font-mono); font-variation-settings: 'wght' var(--wght-narrow), 'wdth' var(--wdth-narrow);
}
.post-content code { font-family: var(--font-mono); font-variation-settings: 'wght' var(--wght-narrow), 'wdth' var(--wdth-narrow); font-size: 1em; }

.post-media {
    --thumb-w: 240px;
    --thumb-gap: 8px;
    --thumb-h: 180px;
    margin-top: 10px;
    display: flex;
    flex-wrap: wrap;
    gap: var(--thumb-gap);
}
/* Four or more images pack into a denser grid: shorter rows than the 2–3 case,
   wrapping as needed. */
.post-media:has(> .media-item:nth-child(4)) { --thumb-h: 120px; }

/* Thumbnail: a bare button so it's keyboard-focusable and clickable. */
.media-item {
    padding: 0;
    border: none;
    background: transparent;
    cursor: zoom-in;
    border-radius: var(--radius-sm);
    overflow: hidden;
    max-width: 100%;
    line-height: 0;
}
.media-item img {
    display: block;
    border-radius: var(--radius-sm);
}

/* A lone image reads larger: up to the footprint of two thumbnails plus the gap
   wide. The image sizes itself within both caps (preserving aspect, no crop);
   the button shrink-wraps it. Portrait is capped shorter so its rendered height
   (≤512px CSS ≈ 1024px on a 2× display) doesn't exceed the 1024px thumbnail and
   get upscaled — a tall image ends up a little narrower instead of blurry. */
.media-item:only-child {
    width: auto;
    /* Cap at the two-thumbnail footprint, but never wider than the container
       (so a lone image can't bleed off a narrow / mobile viewport). */
    max-width: min(calc(var(--thumb-w) * 2 + var(--thumb-gap)), 100%);
}
.media-item:only-child img {
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 512px;
}

/* Multiple images form a justified row: every thumbnail is the same height and
   its width follows the image's own aspect ratio (square vs tall vs wide differ
   in width, not height). */
.media-item:not(:only-child) {
    height: var(--thumb-h);
    width: auto;
}
.media-item:not(:only-child) img {
    height: 100%;
    width: auto;
}
.post-media video {
    max-width: 100%;
    max-height: 320px;
    border-radius: var(--radius-sm);
    border: none;
}

/* Non-image attachments: a stack of download chips (icon + name + size). */
.post-files {
    margin-top: 10px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.file-chip {
    display: flex;
    align-items: center;
    gap: 10px;
    /* Same footprint as a lone image thumbnail. */
    width: calc(240px * 2 + 8px);
    max-width: 100%;
    padding: 8px 12px;
    /* Same treatment as the inline post editor: no border, warm fill, soft corners. */
    border: none;
    border-radius: var(--radius-sm);
    background: var(--surface-warm);
    color: var(--text);
    text-decoration: none;
    transition: background 0.12s;
}
.file-chip:hover { background: var(--border); }
.file-chip-icon { display: flex; flex-shrink: 0; color: var(--text-soft); }
.file-chip-text { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.file-chip-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.file-chip-size {
    color: var(--text-soft);
}
/* File in the composer preview reuses the chip look, sans the download link. */
.media-preview-item.media-preview-file {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    width: auto;
    height: 60px; /* match the image/video thumbnails */
    max-width: 200px;
    overflow: visible;
    padding: 6px 34px 6px 10px;
    border: var(--outline);
    background: var(--surface);
}
.media-preview-file .file-chip-icon { color: var(--text-soft); flex-shrink: 0; }
.media-preview-file .file-chip-text { min-width: 0; }
.media-preview-file .file-chip-name { font-size: var(--fs-helper); }
/* Lighter remove control against the pale chip (not the dark image overlay). */
.media-preview-file .remove-media {
    background: var(--surface-warm);
    color: var(--text-soft);
}
.media-preview-file .remove-media:hover { background: var(--border); }

/* Lightbox: full-size image over a dimmed backdrop. */
.lightbox {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 32px;
    /* Same glassmorphism as the modals/popovers. */
    background: rgba(44, 42, 40, 0.2);
    backdrop-filter: blur(8px);
    cursor: zoom-out;
}
.lightbox img {
    max-width: 100%;
    max-height: 100%;
    border-radius: 6px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
    cursor: default;
}

/* Composer busy state: locked + spinner while media processes. */
.post-composer.busy { opacity: 0.65; }
.composer-spinner {
    width: 18px;
    height: 18px;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
    align-self: center;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Extra breathing room when the actions sit directly under attached media/files. */
.post-media + .post-actions,
.post-files + .post-actions { padding-top: 10px; }

/* Inline post editor — a distinct, obviously-editable box (filled background +
   rounded corners). Height is set from scrollHeight in JS so it fits the
   content and grows as you type. */
.post-edit-input {
    display: block;
    width: 100%;
    box-sizing: border-box;
    margin-top: 6px;
    padding: 10px 12px;
    border: none;
    border-radius: var(--radius-sm);
    background: var(--surface-warm);
    resize: none;
    overflow-y: hidden;
    font: inherit;
    font-size: var(--fs-body);
    line-height: 1.5;
    color: var(--text);
}
.post-edit-input:focus { outline: none; }

/* Small button variant — helper-size, tight padding. .btn.btn-sm so it beats
   the base .btn (equal specificity would otherwise let .btn win by order). */
.btn.btn-sm {
    padding: 4px 12px;
    font-size: var(--fs-helper);
    font-weight: 500;
}
.btn:disabled { opacity: 0.5; cursor: default; }
.post-edit-actions {
    display: flex;
    justify-content: flex-start;   /* left-aligned under the box */
    gap: 8px;
    margin-top: 8px;
}

/* Ease into/out of the inline editor so the swap isn't jarring. */
.post-edit-input,
.post-edit-actions,
.post.editor-exit .post-content { animation: edit-in 0.16s ease both; }
@keyframes edit-in {
    from { opacity: 0; transform: translateY(-3px); }
    to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
    .post-edit-input,
    .post-edit-actions,
    .post.editor-exit .post-content { animation: none; }
}

.reply-btn,
.edit-btn,
.delete-btn,
.permalink-btn {
    border: none;
    background: transparent;
    color: var(--text-soft);
    border-radius: 0;
    padding: 0;
    font-weight: 430;
    cursor: pointer;
    transition: color 0.15s;
    text-transform: lowercase;
}

.reply-btn:hover,
.edit-btn:hover,
.permalink-btn:hover {
    color: var(--text);
}

.delete-btn:hover {
    color: var(--danger);
}

/* Inline #hashtag inside post content */
.hashtag {
    color: var(--accent);
    font-weight: 500;
    cursor: pointer;
}
.hashtag:hover { text-decoration: underline; }

/* Tags: filter bar above the thread list + chips on threads */
.tag-filter-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    /* The pane (#threads-list) already adds 6px around its content, so 6px on
       top/sides yields an even ~12px there. The bottom gets no pane padding
       (thread rows follow), so it needs the full 12px itself. */
    padding: 6px 6px 12px;
}
.tag-clear {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    font-weight: 500;
    color: var(--accent);
    background: transparent;
    border: 1px solid var(--accent);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

/* Bookmark action button (active = saved) */
.bookmark-btn.active {
    color: var(--accent);
    font-weight: 600;
}


/* Profile hover card */
.hover-card {
    position: fixed;
    z-index: 300;
    width: 300px;
    max-width: calc(100vw - 16px);
    padding: 14px 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
    font-size: var(--fs-body);
}
.hover-card-top { display: flex; align-items: center; gap: 12px; }
.hover-card-avatar {
    width: 52px;
    height: 52px;
    border-radius: var(--radius);
    object-fit: cover;
    flex-shrink: 0;
}
.hover-card-avatar-ph { background: var(--border); }
.hover-card-id { min-width: 0; }
.hover-card-name { font-weight: 700; line-height: 1.2; }
.hover-card-handle { color: var(--text-soft); }
.hover-card-bio {
    margin-top: 10px;
    line-height: 1.45;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}
.hover-card-bio a {
    color: var(--accent);
    text-decoration: none;
}
.hover-card-bio a:hover { text-decoration: underline; }
[data-actor] { cursor: pointer; }

/* Floating "Quote" button over a text selection */
.quote-btn {
    position: fixed;
    transform: translateX(-50%);
    z-index: 200;
    padding: 6px 12px;
    font-weight: 500;
    color: var(--on-accent);
    background: var(--accent);
    border: none;
    border-radius: 999px;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
    cursor: pointer;
    white-space: nowrap;
}
.quote-btn:hover { background: var(--accent-hover); }

/* @mention autocomplete dropdown — pops up above the composer input */
.mention-dropdown {
    position: absolute;
    left: 40px;
    right: 40px;
    bottom: calc(100% - 8px);
    max-height: 240px;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.12);
    z-index: 50;
    padding: 4px;
}
.mention-option {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 8px;
    cursor: pointer;
}
.mention-option.active,
.mention-option:hover { background: var(--surface-warm); }
.mention-avatar { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.mention-label { display: flex; gap: 6px; align-items: baseline; min-width: 0; }
.mention-name { font-weight: 500; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mention-handle { color: var(--text-soft); }

/* Composer bar: media preview stacked above the input row. */
#post-form {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-width: var(--measure);
    margin-inline: auto;
    padding: 6px;
    box-shadow: var(--composer-shadow);
    border-radius: var(--radius);
    background: var(--surface);
}
/* Markdown quick-format buttons above the input row. */
.composer-toolbar {
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 0 2px 4px;
}
.composer-md-btn {
    display: grid;
    place-items: center;
    width: 28px;
    height: 26px;
    padding: 0;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-soft);
    cursor: pointer;
}
.composer-md-btn:hover { background: var(--surface-warm); color: var(--text); }

.composer-row {
    display: flex;
    flex-direction: row;
    align-items: flex-end;
    gap: 4px;
}
#post-content {
    flex: 1;
    min-width: 0;
    border: none;
    border-radius: 0;
    padding: 6px;
    min-height: 36px;         /* one line + padding; no fixed height, so the
                                 auto-resize doesn't jump on first keystroke */
    max-height: 160px;
    resize: none;
    overflow-y: hidden;
    background: transparent;
    font: inherit;
    font-size: var(--fs-body);
    line-height: 1.4;
}
#post-content:focus { outline: none; }
#post-content::placeholder { color: var(--text-soft); }

.form-group input:focus,
.form-group textarea:focus,
.form-group select:focus {
    outline: none;
    border-color: var(--accent);
}

/* Thumbnails sit inside the composer bar, above the input row. */
.media-preview {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.media-preview:empty { display: none; }

.media-preview-item {
    width: 60px;
    height: 60px;
    border-radius: var(--radius-sm);
    overflow: hidden;
    position: relative;
}

.media-preview-item img,
.media-preview-item video {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Rounded-square remove control, inset from the corner like the user bar. */
.media-preview-item .remove-media {
    position: absolute;
    right: 3px;
    top: 3px;
    width: 25px;
    height: 25px;
    display: grid;
    place-items: center;
    border: none;
    border-radius: var(--radius-sm);
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    cursor: pointer;
    padding: 0;
    line-height: 1;
    font-size: var(--fs-body);
    font-family: var(--font-mono); font-variation-settings: 'wght' var(--wght-narrow), 'wdth' var(--wdth-narrow);
}
.media-preview-item .remove-media:hover { background: rgba(0, 0, 0, 0.72); }

.composer-icon-btn {
    flex: none;
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-soft);
    cursor: pointer;
    padding: 0;
    transition: color 0.15s, background 0.15s;
}

.composer-icon-btn:hover {
    color: var(--text);
    background: rgba(0, 0, 0, 0.05);
}

.composer-icon-btn svg {
    width: 20px;
    height: 20px;
    stroke: currentColor;
    stroke-width: 1.75;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* Filled send button — the plane icon (previously hidden). */
.composer-send-btn {
    flex: none;
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    border: none;
    border-radius: var(--radius-sm);
    background: var(--accent);
    color: var(--on-accent);
    cursor: pointer;
    padding: 0;
    transition: background 0.15s;
}

.composer-send-btn:hover {
    background: var(--accent-hover);
}

.composer-send-btn svg {
    display: block;
    width: 18px;
    height: 18px;
    stroke: currentColor;
    stroke-width: 1.9;
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
    position: relative;
    right: 1px;              /* optical centering — the plane leans right */
}

/* Logged-out / non-member: the same bar as the composer, with the prompt text
   sitting inside it. */
.composer-gate {
    flex: none;
    box-sizing: border-box;
    width: min(var(--measure), 100% - 28px);
    margin: 0 auto 12px;      /* bottom aligns with the forum card + composer */
    padding: 14px 16px;
    box-shadow: var(--card-shadow);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--text-soft);
    text-align: center;
}
/* "Log in" link inside the gate — triggers the login popover. */
.gate-login-link {
    border: none;
    background: none;
    padding: 0;
    font: inherit;
    color: var(--text);
    text-decoration: underline;
    text-underline-offset: 2px;
    text-decoration-color: var(--text-soft);
    cursor: pointer;
}
.gate-login-link:hover { text-decoration-color: var(--text); }

/* ---- Forms / buttons ---- */
.form-group { margin-bottom: 14px; }
.form-group label {
    display: block;
    margin-bottom: 5px;
    color: var(--text); /* black — form labels stay high-contrast */
    font-weight: 500;
}

/* Membership toggle in the forum modal */
.form-check { padding-top: 8px; }
.form-check .check-label {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px;
    font-weight: 500;
    color: var(--text);
    cursor: pointer;
}
/* Custom checkbox that matches the text inputs/selects: bordered box on the same
   surface, filling with the accent + a checkmark when checked. */
.form-check .check-label input[type="checkbox"] {
    appearance: none;
    -webkit-appearance: none;
    width: 20px;
    height: 20px;
    flex-shrink: 0;
    margin: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    cursor: pointer;
    position: relative;
    transition: background 0.12s, border-color 0.12s;
}
.form-check .check-label input[type="checkbox"]:hover { border-color: var(--text-soft); }
.form-check .check-label input[type="checkbox"]:checked {
    background: var(--accent);
    border-color: var(--accent);
}
.form-check .check-label input[type="checkbox"]:checked::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    width: 5px;
    height: 9px;
    border: solid var(--on-accent);
    border-width: 0 2px 2px 0;
    /* Center the checkmark's box, then nudge up slightly so the rotated tick sits
       optically centered (the long leg hangs down-right). */
    transform: translate(-50%, -60%) rotate(45deg);
}
.form-check .check-label input[type="checkbox"]:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.field-hint {
    margin: 0;
    color: var(--text-soft);
}

/* Join-requests list (creator) */
/* Join-requests tab: one row per pending request. */
.request-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 6px;
}
.request-row + .request-row { border-top: 1px solid var(--border); }
.request-who { display: flex; align-items: center; gap: 10px; min-width: 0; }
.request-avatar { width: 34px; height: 34px; border-radius: var(--radius-sm); object-fit: cover; flex-shrink: 0; }
.request-meta { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.request-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.request-date { color: var(--text-soft); }
.request-actions { display: flex; gap: 6px; flex-shrink: 0; }

.form-group input[type="text"],
.form-group input[type="email"],
.form-group input[type="password"],
.form-group textarea,
.form-group select,
.form-group input[type="file"] {
    width: 100%;
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 10px 12px;
    background: var(--surface);
    color: var(--text);
    font: inherit;
    transition: border-color 0.2s;
}
/* Strip the native select chrome so it matches the text inputs (padding, height,
   and — crucially in dark mode — background), then draw our own caret. */
.form-group select {
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    padding-right: 34px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%239aa2ac' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
}

.btn {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);   /* match the post/send button (was a full pill) */
    padding: 8px 18px;
    font: inherit;
    font-size: var(--fs-body);
    font-weight: 500;
    letter-spacing: -0.01em;
    cursor: pointer;
    background: transparent;
    color: var(--text);
    transition: all 0.15s;
}

.btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

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

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


.error-message {
    margin-top: 8px;
    color: var(--danger);
    display: none;
}

.error-message.show { display: block; }

.empty-state {
    color: var(--text-soft);
    font-size: var(--fs-body);
    padding: 24px 20px;
}

/* Empty-thread state, rendered as a message row with the cactus inline. */
.empty-post-text { color: var(--text-soft); }

/* First-run onboarding — replaces the transcript when you belong to no forums. */
.onboard-wrap {
    min-height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 48px 24px;
    box-sizing: border-box;
}
.onboard-card {
    max-width: 360px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 14px;
}
.onboard-icon {
    width: 52px;
    height: 52px;
    display: grid;
    place-items: center;
    border-radius: var(--radius);
    background: rgba(126, 109, 255, 0.14);   /* --accent at 14% */
    color: var(--accent);
}
.onboard-icon svg { width: 26px; height: 26px; }
.onboard-title {
    margin: 0;
    font-family: var(--font-body);
    font-variation-settings: 'wdth' var(--wdth-title);
    font-feature-settings: 'ss05' 1;
    font-weight: 400;
    font-size: 28px;
    letter-spacing: -0.02em;
    color: var(--text);
}
.onboard-sub {
    margin: 0;
    font-size: var(--fs-body);
    line-height: 1.55;
    color: var(--text-mid);
}
.onboard-btn { margin-top: 6px; }

/* ---- Modals ---- */
.modal {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(44, 42, 40, 0.2);
    backdrop-filter: blur(8px);
    z-index: 1900;
}

.modal-content {
    width: min(480px, calc(100vw - 40px));
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08);
    padding: 28px;
}

/* Close X exists only on the mobile full-screen sheet (see the media query).
   Desktop uses Cancel + Esc + outside-click. */
.modal-close { display: none; }

/* Match the forum-title treatment (.forum-info-top h2). */
.modal-content h2 {
    margin: 0 0 16px;
    font-size: var(--fs-title);
    font-weight: 400;            /* Regular */
    letter-spacing: -0.02em;
    line-height: 1.1;
    color: var(--text);
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 14px;
}

/* Existing forum image + its two-stage remove control (edit mode). */
.image-preview-current {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 8px;
}
.image-preview-icon {
    width: 64px;
    height: 64px;
    object-fit: cover;
    border-radius: var(--radius-sm);
}
.image-preview-banner {
    height: 56px;
    max-width: 180px;
    object-fit: cover;
    border-radius: var(--radius-sm);
}
.btn-remove-image {
    flex-shrink: 0;
    padding: 5px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--danger);
    cursor: pointer;
    transition: all 0.15s;
}
.btn-remove-image:hover { border-color: var(--danger); }
.btn-remove-image.armed {
    background: var(--danger);
    border-color: var(--danger);
    color: #fff;
}

/* ---- @mentions ---- */
.mention {
    color: var(--text);
    background: var(--surface-warm);
    border-radius: 4px;
    padding: 0 3px;
    font-weight: 600;
}

/* ---- Notification bell ---- */
/* The bell is a .btn-icon; it only needs to anchor its unread badge. Size,
   colour, hover, and transition all come from .btn-icon so it stays identical
   to the other bar buttons. */
/* The bell widens to seat its unread badge inline — to the right of the glyph,
   vertically centred — instead of floating the badge over the icon. With no
   badge (hidden) it stays a plain 28px icon button like its neighbours: 5px
   padding + 18px icon each side = 28px. */
.account-cluster #notif-bell {
    width: auto;
    min-width: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 0 5px;
}

/* Presence dot — a small fixed circle that just signals "unread notifications",
   no count. Fixed width == height + 50% radius means it's always a true circle. */
.notif-badge {
    width: 6px;
    height: 6px;
    flex-shrink: 0;
    padding: 0;
    background: var(--danger);
    border-radius: 50%;
    font-size: 0;   /* never render a number */
}


/* =====================================================================
   Layout v2 — inset floating cards, shared outline/radius, icon controls.
   Overrides earlier layout rules whose elements still exist.
   ===================================================================== */

/* Shared treatment: one corner radius + surface everywhere, flat (no card
   shadow — the picker menu adds its own). */
/* appearance:none so the <button> variants (picker, user pill) drop the OS's
   native control bezel/shadow, which the border used to hide. */
.outlined { appearance: none; -webkit-appearance: none; border: none; border-radius: var(--radius); background: var(--surface); }

/* Type scale — three sizes only. */
h1, h2 { font-size: var(--fs-title); font-weight: 600; letter-spacing: -0.02em; }

.main-app { height: 100%; padding: 0; display: flex; flex-direction: column; }
.app-shell {
    flex: 1;
    min-height: 0;
    display: grid;
    grid-template-columns: 340px minmax(0, 1fr);
    /* Both columns float as inset, rounded panes with equal spacing from the
       browser edge and from each other — the gap doubles as the divider that
       used to be .sidebar-col's right border. The backdrop showing through the
       gap is the dark theme's highlight colour (its navbar hover tint), not
       the base --bg, so the seam reads as a deliberate surface, not a void. */
    gap: var(--offset);
    padding: var(--offset);
    background: var(--surface-warm);
}

/* Left column: account/picker strip stacked above the forum card */
.sidebar-col {
    display: flex;
    flex-direction: column;
    /* Optically tighter than the 12px window insets: an equal vertical gap
       reads as larger than the horizontal one, so 8px looks balanced. */
    gap: 8px;
    /* Offset on all sides so content clears the window edge (left) and the right
       border, and the top/bottom edges — the old page padding, moved inward. */
    padding: var(--offset);
    min-height: 0;
    background: var(--bg);
    border-radius: var(--radius);
}
.sidebar-top {
    flex: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    min-height: 36px;
    /* Breathing room below the controls so they don't sit flush on the divider. */
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border);  /* trial: like the thread header */
}
.sidebar-top .forum-picker { flex: 1; min-width: 0; }
.sidebar-top .forum-picker-btn { max-width: none; width: 100%; }
/* Account controls (bookmarks, bell, avatar) share the dropdown's treatment:
   a flat bar the same height as the forum picker. */
.account-cluster {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    height: 36px;                 /* match .forum-picker-btn */
    padding: 3px;                 /* uniform inset around the controls */
    border-radius: var(--radius);
    background: var(--surface);
}
/* All three controls: identical size + centering so nothing smushes or offsets
   (the bell's flex layout was crushing its icon to 10px wide). 3px padding +
   1px border in the 36px bar leaves 28px. */
.account-cluster .btn-icon,
.account-cluster #user-pill {
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    padding: 0;                 /* kill the default <button> padding that offset the icons */
    display: grid;
    place-items: center;
    /* Concentric with the 8px bar: inset ~4px (border + padding) → 4px radius. */
    border-radius: var(--radius-sm);
}
.account-cluster #user-pill img { border-radius: var(--radius-sm); }
.account-cluster .btn-icon svg { width: 18px; height: 18px; flex-shrink: 0; }
/* Active state (e.g. bookmarks view open): the filled icon takes the full text colour. */
.account-cluster .btn-icon.active { color: var(--text); }
/* Logged out shows only the "Log In" button — no bar chrome around it. */
.account-cluster:has(#user-pill.logged-out) {
    height: auto;
    padding: 0;
    border: none;
    background: transparent;
}
.account-cluster:has(#user-pill.logged-out) #user-pill {
    width: auto;
    height: 34px;
}

/* ---- Forum picker (custom dropdown) ---- */
.forum-picker { position: relative; }
.forum-picker-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 36px;
    /* Tight left so the avatar sits at the same 3px inset as the user-bar
       avatar; roomy right so the chevron clears the edge. */
    padding: 0 12px 0 3px;
    font: inherit;
    font-family: var(--font-mono); font-variation-settings: 'wght' var(--wght-narrow), 'wdth' var(--wdth-narrow);
    font-size: var(--fs-body);
    font-weight: 400;               /* body text weight */
    letter-spacing: -0.01em;
    color: var(--text);
    cursor: pointer;
    max-width: 300px;
}
.forum-picker-btn:hover { background: var(--surface-warm); }
/* Match the user-bar avatar: same 28px size + 4px radius. */
.forum-picker-avatar { width: 28px; height: 28px; border-radius: var(--radius-sm); object-fit: cover; flex-shrink: 0; }
/* Keep the name hugging the avatar (natural width, left aligned — the button's
   default text-align is center), truncating if long. */
#forum-picker-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; }
/* No avatar (e.g. "Select forum"): give the text the usual left breathing room. */
.forum-picker-avatar.hidden + #forum-picker-label { margin-left: 9px; }
/* Push the chevron to the far right, clear of the name. */
.forum-picker-chevron { margin-left: auto; color: var(--text-soft); flex-shrink: 0; }
.forum-picker-menu {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 200;
    width: 260px;
    max-width: 80vw;
    padding: 6px;
    box-shadow: var(--card-shadow);
}
.fp-list { display: flex; flex-direction: column; gap: 2px; max-height: 320px; overflow-y: auto; }
.fp-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 7px 10px;
    border: none;
    border-radius: 8px;
    background: transparent;
    font: inherit;
    font-family: var(--font-mono); font-variation-settings: 'wght' var(--wght-narrow), 'wdth' var(--wdth-narrow);
    font-size: var(--fs-body);
    text-align: left;
    cursor: pointer;
    color: var(--text);
}
.fp-item:hover { background: var(--surface-warm); }
.fp-item.active { font-weight: 600; }
/* Same avatar treatment as the picker button / user bar: 28px, 4px radius. */
.fp-item-avatar { width: 28px; height: 28px; border-radius: var(--radius-sm); object-fit: cover; flex-shrink: 0; }
.fp-item-avatar-ph { background: var(--surface-warm); border: var(--outline); }
.fp-item-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fp-empty { margin: 6px 10px; color: var(--text-soft); }
.fp-create {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    margin-top: 6px;
    padding: 9px 10px;
    border: none;
    border-top: var(--outline);
    border-radius: 0 0 8px 8px;
    background: transparent;
    font: inherit;
    font-family: var(--font-mono); font-variation-settings: 'wght' var(--wght-narrow), 'wdth' var(--wdth-narrow);
    font-size: var(--fs-body);
    font-weight: 500;
    color: var(--text);
    cursor: pointer;
}
.fp-create:hover { background: var(--surface-warm); }

/* Account pill: avatar (logged in) or "Log In" (logged out). Size + radius come
   from .account-cluster #user-pill above (28px, --radius-sm). */
#user-pill {
    padding: 0;
    overflow: hidden;
    background: var(--text);
    color: var(--surface);
    font-weight: 700;
}
#user-pill img { width: 100%; height: 100%; object-fit: cover; }
/* Only the logged-out text state grows to fit its label. */
#user-pill.logged-out {
    width: auto;
    padding: 0 14px;
    background: var(--text);
    color: var(--surface);
    border: none;
    font-weight: 600;
}
.btn-icon { border-radius: var(--radius); }

/* ---- Forum card ---- */
.forum-card {
    flex: 1;              /* fill the column's full height, even with few threads */
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}
.forum-card-header { flex: none; }
.forum-banner {
    height: 90px;
    flex: none;
    border-radius: var(--radius-sm);
    background-size: cover;
    background-position: center;
    background-color: var(--surface-warm);
}
.forum-banner.hidden { display: none; }

/* Forum icon — a squared "profile" avatar stacked above the title. When a
   banner is present it overlaps the banner's lower edge (Twitter style). */
.forum-heading-image {
    display: block;
    width: 52px;
    height: 52px;
    margin: 20px 0 5px 20px;
    border-radius: var(--radius-sm);
    /* outline (not border) -- it paints outside the box without taking part
       in layout sizing, so the avatar stays 52x52 and the ring doesn't eat
       into or enlarge it. */
    outline: 4px solid var(--surface);
    outline-offset: 0;
    object-fit: cover;
    background: var(--surface-warm);
}
.forum-heading-image.hidden { display: none; }
.forum-card-header.has-banner .forum-heading-image { margin-top: -27px; }

.forum-info {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px 20px 20px;
}
/* With no avatar above it (banner or not), the title needs its own top
   breathing room rather than the 10px meant to sit under the avatar. */
.forum-heading-image.hidden + .forum-info {
    padding-top: 20px;
}
.forum-info-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.forum-info-top h2 {
    margin: 0;
    min-width: 0;
    font-family: var(--font-body); font-variation-settings: 'wdth' 100; font-feature-settings: 'ss05' 1;
    font-size: 32px;
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1;
    color: var(--text);
    overflow-wrap: anywhere;
}
.forum-description {
    margin: 0;
    color: var(--text);
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.forum-actions { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.forum-actions .btn-icon { width: 30px; height: 30px; position: relative; }

/* Threads / Tags — underlined text tabs, with the "new thread" button pinned
   to the far right of the row. */
.view-toggle {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 0 20px;
    border-bottom: var(--outline);
}
.view-toggle .btn-icon {
    margin-left: auto;
    align-self: center;
    width: 28px;
    height: 28px;
}
.view-toggle-btn {
    padding: 8px 0;
    margin-bottom: -1px;                 /* sit on the container's bottom border */
    border: none;
    border-bottom: 2px solid transparent;
    background: transparent;
    font: inherit;
    color: var(--text-soft);
    cursor: pointer;
}
.view-toggle-btn:hover { color: var(--text); }
.view-toggle-btn.active { color: var(--text); border-bottom-color: var(--text); }

.forum-card-body { flex: 1; min-height: 0; display: flex; flex-direction: column; }
/* Full-width rows now that the card isn't a floating container: the list spans
   edge-to-edge (no side inset). */
.forum-card-body > .pane-content { flex: 1; min-height: 0; overflow-y: auto; padding: 6px 0; }

/* Tags view rows */
.tag-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 10px 12px;
    border: none;
    border-radius: 8px;
    background: transparent;
    font: inherit;
    font-size: var(--fs-body);
    cursor: pointer;
    color: var(--text);
}
.tag-row:hover { background: var(--surface-warm); }
.tag-row-name { font-weight: 500; }
.tag-row-count { color: var(--text-soft); font-variant-numeric: tabular-nums; }

/* Thread items inside the card (tighten to card padding) */
.forum-card-body .thread-item + .thread-item { margin-top: 2px; }

/* ---- Transcript — no card; content sits directly in the space ---- */
.transcript-col {
    display: flex;
    flex-direction: column;
    min-height: 0;
    position: relative;   /* anchor the compact thread header + new-posts pill */
}

/* "New posts" pill — floats above the composer when new posts land while the
   reader is scrolled up. Its `bottom` is set in JS to clear the composer. */
.new-posts-pill {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    z-index: 40;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    border: none;
    border-radius: 999px;
    background: var(--accent);
    color: var(--on-accent);
    font-size: var(--fs-helper);
    font-weight: 500;
    cursor: pointer;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
}
.new-posts-pill svg { display: block; }
.new-posts-pill:hover { background: var(--accent-hover); }
.transcript-col > .posts-container {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;       /* vertical scroll only — no sideways drift */
    /* Top padding clears the fixed header pills (12px inset + 42px pill) with a
       16px gap, so the first post isn't hidden underneath them when scrolled up. */
    padding: 70px 16px 12px;
}

/* Icon post actions */
.post-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;  /* controls left, reactions right */
    gap: 8px;
    margin-top: 0;
}
.post-actions-controls { display: flex; align-items: center; gap: 2px; }
.post-reactions { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 4px; }

/* Applied reactions: emoji + count as plain text (no pill), in the same soft
   color as the post author; your own reactions read a touch darker. */
.reaction-chip {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 4px;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-soft);
    font-size: var(--fs-helper);
    line-height: 1.5;
    cursor: pointer;
}
.reaction-chip .reaction-emoji { font-size: 13px; line-height: 1; }
.reaction-chip .reaction-count { font-family: var(--font-mono); font-variation-settings: 'wght' var(--wght-narrow), 'wdth' var(--wdth-narrow); }
.reaction-chip:hover { background: var(--surface-warm); color: var(--text); }
.reaction-chip.reacted { color: var(--text); }
/* Safari renders color emoji larger than other browsers at the same font-size.
   The -webkit-named-image() query matches Safari only (not Chrome/Firefox), so
   shrink the reaction emoji there to match. */
@supports (background: -webkit-named-image(i)) {
    .reaction-chip .reaction-emoji { font-size: 11px; }
}

/* Shared emoji picker (positioned in JS next to the clicked React button). */
.reaction-picker {
    position: fixed;
    z-index: 1600;
    display: flex;
    gap: 2px;
    padding: 5px;
    border-radius: 999px;
    background: var(--surface);
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.16);
}
.emoji-opt {
    border: none;
    background: transparent;
    cursor: pointer;
    font-size: 20px;
    line-height: 1;
    padding: 4px 6px;
    border-radius: var(--radius-sm);
    transition: transform 0.1s;
}
.emoji-opt:hover { background: var(--surface-warm); transform: scale(1.2); }

.post-action {
    display: grid;
    place-items: center;
    width: 30px; height: 30px;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--text-soft);
    cursor: pointer;
}
.post-action:hover { background: var(--surface-warm); color: var(--text); }
.post-action.bookmark-btn.active { color: var(--text); }
/* Moderation actions turn danger-colored on hover to signal their weight. */
.post-action.mod-hide-btn:hover,
.post-action.mod-ban-btn:hover { color: var(--danger); }

/* Collapsed rendering of a moderated post (creator-only view). */
.post--moderated .post-body { min-width: 0; }
.post-moderated-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    height: var(--avatar); /* match the post avatar's height exactly */
    margin-top: 3px;        /* and its 3px top offset, so the two line up */
    padding: 0 10px;
    border-radius: var(--radius-sm);
    background: var(--surface-warm);
    color: var(--text-soft);
}
.post-moderated-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mod-expand-btn,
.mod-undo-btn {
    flex-shrink: 0;
    border: none;
    background: transparent;
    padding: 0;
    font: inherit;
    color: var(--text-soft);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.mod-expand-btn:hover { color: var(--text); }
.mod-undo-btn:hover { color: var(--danger); }
.post-moderated-content { margin-top: 8px; }

/* Composer: full width of the transcript. No top padding so messages scroll
   right underneath; bottom padding aligns its bar with the forum card. */
.post-composer { flex: none; border-top: none; padding: 0 14px 12px; background: transparent; position: relative; }

/* ---- Bookmarks + mentions views (in the transcript column) ---- */
/* Transcript-column list views (bookmarks, mentions): a scrolling big header
   that collapses into the shared .thread-sticky-bar, over a reading-width list —
   same treatment as an open thread. */
.list-view {
    position: relative;        /* anchor the compact sticky bar */
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.list-scroll {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    /* The compact bar is pinned (always shown) and 57px tall — clear it, plus a
       12px gap so the first row sits below its divider like the sidebar does. */
    padding: 69px 16px 16px;
}
.list-inner { max-width: var(--measure); margin-inline: auto; }
/* Empty views ("No bookmarks yet." / "No notifications yet.") read centred. */
.list-scroll .empty-state { text-align: center; }
/* Bookmarks render as .post, so they inherit the transcript's 18px 0 rhythm and
   its no-divider rule; only the reading-width centring is bookmark-specific. */
.bookmark-msg {
    max-width: var(--measure);      /* match the thread transcript's reading width */
    margin-inline: auto;
}
.bookmark-forum-tag {
    padding: 1px 8px;
    border-radius: var(--radius-sm);
    color: var(--text-soft);
    background: var(--surface-warm);
}
.bookmark-goto {
    display: inline-block;
    margin-top: 8px;
    padding: 0;
    border: none;
    background: none;
    font: inherit;
    font-weight: 500;
    color: var(--text-soft);
    cursor: pointer;
}
.bookmark-goto:hover { text-decoration: underline; }

/* ============================================================
   Mobile: the sidebar column becomes an off-canvas drawer, the
   transcript goes full-width, and a top bar carries the ☰ toggle.
   ============================================================ */

/* Mobile-only chrome is hidden on desktop. */
.mobile-topbar { display: none; }
.drawer-backdrop { display: none; }
/* Drawer-close (X) lives in the sidebar-top, which is visible on desktop too —
   so it must be explicitly hidden until the mobile layout kicks in. */
.drawer-close-btn { display: none; }

.mobile-topbar-icon {
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    border-radius: var(--radius-sm);
    object-fit: cover;
    background: var(--surface-warm);
}

.mobile-topbar-btn {
    flex-shrink: 0;
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    padding: 0;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text);
    cursor: pointer;
}
.mobile-topbar-btn:hover { background: var(--surface-warm); }
.mobile-topbar-title {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
    color: var(--text);
}

/* Tablet + narrower: a touch more side breathing room for the transcript.
   (The header-peek fix lives in the base rule above — it applies at all widths.) */
@media (max-width: 1024px) {
    .transcript-col > .posts-container { padding-left: 20px; padding-right: 20px; }
}

@media (max-width: 768px) {
    /* Single column; the transcript reaches both edges — no floating-pane
       inset/gap/rounding at this width, that's a desktop-only treatment. */
    .app-shell {
        grid-template-columns: minmax(0, 1fr);
        gap: 0;
        padding: 0;
        background: var(--bg);
    }
    .transcript-col {
        border-radius: 0;
    }

    /* Sidebar -> full-screen forum panel, slid in from the left. */
    .sidebar-col {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        width: 100%;
        z-index: 1500;
        padding: var(--offset);
        overflow-y: auto;
        background: var(--bg);
        border-radius: 0;
        transform: translateX(-100%);
        transition: transform 0.25s ease;
    }
    .app-shell.drawer-open .sidebar-col { transform: translateX(0); }
    /* The X (back-to-thread) sits next to the picker + user bar in the header. */
    .drawer-close-btn {
        display: grid;
        place-items: center;
        flex-shrink: 0;
        width: 36px;
        height: 36px;
        color: var(--text-soft);
        cursor: pointer;
    }
    .drawer-close-btn:hover { color: var(--text); }

    /* Backdrop behind the open drawer. */
    .drawer-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        z-index: 1400;
        background: rgba(0, 0, 0, 0.35);
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.25s ease;
    }
    .app-shell.drawer-open .drawer-backdrop {
        opacity: 1;
        pointer-events: auto;
    }

    /* Top bar with the drawer toggle sits above the transcript. */
    .mobile-topbar {
        display: flex;
        align-items: center;
        gap: 10px;
        position: sticky;
        top: 0;
        z-index: 60;
        padding: 8px 12px;
        background: var(--bg);
        border-bottom: 1px solid var(--border);
    }

    /* The transcript no longer needs its big top inset — the bar provides it. */
    .transcript-col > .posts-container { padding-top: 16px; }

    /* Kill the in-transcript thread header (and the list views' sticky bars) on
       mobile — the top bar carries "[icon] Forum – Thread" instead. */
    .thread-float,
    .thread-sticky-bar { display: none; }

    /* Modals become full-screen sheets: edge-to-edge, full height, scrollable,
       no float/rounded card. The backdrop blur is moot since the sheet covers it. */
    .modal { align-items: stretch; justify-content: stretch; backdrop-filter: none; }
    .modal-content {
        width: 100%;
        max-width: none;
        border: none;
        border-radius: 0;
        box-shadow: none;
        overflow-y: auto;
        padding: 20px;
        /* Clear the notch / home indicator on phones. */
        padding-top: max(20px, env(safe-area-inset-top));
        padding-bottom: max(20px, env(safe-area-inset-bottom));
    }
    /* Close affordance for the full-screen sheet: pinned top-right, stays put
       as the form scrolls. */
    .modal-close {
        display: grid;
        place-items: center;
        position: sticky;
        top: 0;
        margin-left: auto;      /* right-align in the content column */
        margin-bottom: 4px;
        width: 40px;
        height: 40px;
        border: none;
        border-radius: var(--radius-sm);
        background: var(--surface);
        color: var(--text-soft);
        font-size: 26px;
        line-height: 1;
        cursor: pointer;
        z-index: 2;
    }
    .modal-close:hover { color: var(--text); }
}

/* Account view (list-view content) */
.account-identity {
    font-weight: 500;
    color: var(--text);
    margin: 0 0 12px;
}
.account-admin-link {
    display: inline-block;
    margin: 0 0 12px;
    color: var(--accent);
    font-weight: 500;
}
.account-section-title {
    font-size: var(--fs-body);
    font-weight: 500;
    color: var(--text-soft);
    margin: 20px 0 8px;
}
.account-space-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
}
.account-space-name { flex: 1; color: var(--text); }
.account-hidden-badge,
.account-upgrade-badge {
    font-size: var(--fs-helper);
    padding: 2px 8px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    color: var(--text-soft);
    white-space: nowrap;
}
.account-upgrade-badge { color: var(--accent); border-color: var(--accent); }

/* Standalone admin dashboard (frontend/admin.html) */
.admin-page {
    max-width: var(--measure);
    margin: 0 auto;
    padding: 24px 16px 60px;
}
.admin-header {
    display: flex;
    align-items: baseline;
    gap: 12px;
    margin-bottom: 24px;
}
.admin-header a { color: var(--accent); font-weight: 600; text-decoration: none; }
.admin-header h1 { font-size: var(--fs-title); font-weight: 400; margin: 0; color: var(--text); }
.admin-unauthorized { color: var(--text-soft); }
.admin-stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 12px;
    margin-bottom: 32px;
}
.admin-stat-card {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 14px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
.admin-stat-value { font-size: var(--fs-title); font-weight: 600; color: var(--text); }
.admin-stat-label { font-size: var(--fs-helper); color: var(--text-soft); }
.admin-spaces-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--fs-body);
}
.admin-spaces-table th,
.admin-spaces-table td {
    text-align: left;
    padding: 8px 10px;
    border-bottom: 1px solid var(--border);
}
.admin-spaces-table th { color: var(--text-soft); font-weight: 500; font-size: var(--fs-helper); }
.admin-badge-hidden { color: var(--danger); }
.admin-badge-visible { color: var(--text-soft); }
.admin-actions-cell { display: flex; gap: 8px; }
.admin-actions-cell button { padding: 4px 10px; font-size: var(--fs-helper); }

/* Thread-header "Links / Media" filter */
.post-filter-bar {
    display: flex;
    gap: 6px;
    margin-top: 10px;
}
.post-filter-btn {
    appearance: none;
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-soft);
    padding: 3px 12px;
    border-radius: var(--radius-sm);
    font-size: var(--fs-helper);
    cursor: pointer;
}
.post-filter-btn:hover { color: var(--text); }
.post-filter-btn.active {
    color: var(--accent);
    border-color: var(--accent);
}
#load-earlier-filtered-btn {
    appearance: none;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-soft);
    padding: 5px 14px;
    border-radius: var(--radius-sm);
    font-size: var(--fs-helper);
    cursor: pointer;
    margin-top: 10px;
}
#load-earlier-filtered-btn:hover { color: var(--text); }
