/* Typography (visual polish pass, roadmap items 49-51): Barlow replaces the old bare
   system-font stack for body/UI text everywhere -- Anton stays reserved for the wordmark and
   major (theme-driven, via --rb-heading-font) page headings only, never body text, matching the
   convention already established on the mobile app. IBM Plex Mono is used for small meta text
   (timestamps, category/type labels, post metadata) -- see the rule near the bottom of this file.
   All three load from a single Google Fonts <link> in base.html. This is a sitewide change, so it
   also reaches the anonymous pre-login view -- deliberate: fonts are explicitly outside the theme
   system's protected "pixel-identical colors" concern (see CLAUDE.md's "App shell & typography"
   section for the full reasoning), unlike --rb-bg/--rb-text/etc., which stay untouched for an
   anonymous request. */
:root {
    --rb-body-font: 'Barlow', -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --rb-mono-font: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    /* App shell chrome (roadmap items 49/50): a subtle tint of --rb-bg toward --rb-text, not a
       hardcoded color -- the same color-mix()-toward-text-color trick already used below by
       .composer textarea's background etc. Mixing toward --rb-text (rather than a fixed
       black/white) is direction-agnostic: --rb-text is always chosen to contrast against --rb-bg,
       so this always shifts the shell a little *toward* that contrast regardless of whether the
       active theme is light or dark -- the CSS equivalent of the mobile app's
       deriveSurfaceVariant() (RideBuddy/.../ui/theme/Theme.kt), which does the same lerp-toward-
       black-or-white-by-luminance trick in Kotlin, just computed a different way. See CLAUDE.md's
       "App shell & typography" section for the full reasoning. */
    --rb-shell-bg: color-mix(in srgb, var(--rb-bg, #15141a) 90%, var(--rb-text, #edeae3) 10%);
    --rb-shell-border: color-mix(in srgb, var(--rb-text, #edeae3) 14%, transparent);
}

body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--rb-bg, #15141a);
    color: var(--rb-text, #edeae3);
    font-family: var(--rb-body-font);
}

main {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
}

h1 {
    font-size: 2.5rem;
    margin-bottom: 0.5rem;
    font-family: var(--rb-heading-font, inherit);
    text-wrap: balance;
}

h2 {
    font-size: 1.2rem;
    font-weight: 700;
    margin: 0 0 0.25rem;
    text-wrap: balance;
}

@media (max-width: 480px) {
    h1 {
        font-size: 2rem;
    }
}

p {
    color: var(--rb-label, #a39fae);
}

.site-nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 1rem 1.5rem;
}

.site-nav a, .site-nav button {
    color: var(--rb-accent, #edeae3);
    background: none;
    border: none;
    font: inherit;
    text-decoration: none;
    cursor: pointer;
}

/* Wordmark stays Anton regardless of the rider's theme font choice -- brand identity, not a
   theme-driven heading (see the typography note above :root). Higher specificity than the plain
   `.site-nav a` rule above (a.site-nav__brand beats a bare class), so this only overrides
   font-family/letter-spacing without touching that rule's color/cursor/etc. */
.site-nav a.site-nav__brand {
    font-family: 'Anton', -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    letter-spacing: 0.02em;
}

.error {
    color: var(--rb-accent, #ff6b6b);
}

/* Visible, accent-colored focus states sitewide (visual polish pass) -- browsers' default focus
   ring doesn't track a rider's theme and can be hard to see against some custom backgrounds. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--rb-accent, #edeae3);
    outline-offset: 2px;
}

/* Shared hover state for the "outline button" pattern used across the composer, chat, forum, and
   settings forms (border + accent text on transparent background) -- a light accent-tinted fill on
   hover, matching the reaction/filter-chip/thread-list hover treatments already in this file. */
.composer button[type="submit"]:hover:not(:disabled),
.chat-composer button:hover:not(:disabled),
.report-form__row button[type="submit"]:hover:not(:disabled),
.forum-toolbar button:hover:not(:disabled),
.new-thread-form__row button[type="submit"]:hover:not(:disabled),
.settings-save-row button:hover:not(:disabled),
.load-earlier-btn:hover:not(:disabled),
.delete-btn:hover {
    background: color-mix(in srgb, var(--rb-accent, #edeae3) 14%, transparent);
}

/* Timeline: shared layout for the feed page and the preferences page. Both are <main> elements,
   so they must explicitly override the bare `main` rule above (which centers/shrinks its
   content) -- `.timeline-page`/`.timeline-preferences-page` win on specificity since they're
   class selectors on the same element. Messaging's `.messages-page`/`.chat-page` (below) need the
   exact same override for the exact same reason, so they share this rule. */
.timeline-page,
.timeline-preferences-page,
.messages-page,
.chat-page,
.profile-page,
.forum-page,
.forum-thread-page {
    width: 100%;
    max-width: 640px;
    margin: 0 auto;
    padding: 0 1.5rem 3rem;
    /* box-sizing:border-box (added alongside the app shell, roadmap items 49-51): without it,
       width:100% + this rule's own horizontal padding add up to more than 100% of the available
       width under the default content-box model, causing real horizontal page overflow at narrow
       viewports -- caught live while verifying the new mobile drawer layout (a pre-existing gap in
       this rule, not something the shell introduced, but now visibly relevant since the shell's
       mobile breakpoint is the first place this file specifically calls out testing at). */
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    text-align: left;
}

.timeline-page {
    gap: 1.5rem;
}

/* Timeline: composer */
.composer {
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 15%, transparent);
    border-radius: 12px;
    padding: 1rem;
}

.composer form {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.composer textarea {
    width: 100%;
    box-sizing: border-box;
    resize: vertical;
    min-height: 4.5rem;
    padding: 0.6rem;
    border-radius: 8px;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    background: color-mix(in srgb, var(--rb-bg, #15141a) 92%, var(--rb-text, #edeae3) 8%);
    color: var(--rb-text, #edeae3);
    font: inherit;
}

.composer__meta {
    display: flex;
    justify-content: flex-end;
}

.composer__char-count {
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

.composer__row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: flex-end;
}

.composer__field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

.composer__field select,
.composer__field input[type="file"] {
    font: inherit;
    color: var(--rb-text, #edeae3);
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 6px;
    padding: 0.35rem 0.5rem;
}

.composer button[type="submit"] {
    align-self: flex-end;
    background: transparent;
    color: var(--rb-accent, #edeae3);
    border: 1px solid var(--rb-accent, #edeae3);
    border-radius: 8px;
    padding: 0.5rem 1.25rem;
    font-weight: 600;
    cursor: pointer;
}

.composer button[type="submit"]:disabled {
    opacity: 0.6;
    cursor: default;
}

/* Timeline: feed */
.feed-section {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.feed-section__link {
    align-self: flex-end;
    font-size: 0.85rem;
}

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

.feed-sentinel {
    height: 1px;
}

.feed-skeleton {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.feed-skeleton__card {
    height: 5.5rem;
    border-radius: 12px;
    background: linear-gradient(
        90deg,
        color-mix(in srgb, var(--rb-text, #edeae3) 6%, transparent) 25%,
        color-mix(in srgb, var(--rb-text, #edeae3) 12%, transparent) 37%,
        color-mix(in srgb, var(--rb-text, #edeae3) 6%, transparent) 63%
    );
    background-size: 400% 100%;
    animation: feed-skeleton-shimmer 1.4s ease infinite;
}

@keyframes feed-skeleton-shimmer {
    0% { background-position: 100% 50%; }
    100% { background-position: 0 50%; }
}

.post-card {
    position: relative;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 12%, transparent);
    border-radius: 12px;
    padding: 1rem;
}

.post-card__header {
    display: flex;
    justify-content: space-between;
    gap: 0.5rem;
    padding-right: 1.75rem;
    font-size: 0.85rem;
    margin-bottom: 0.5rem;
}

.post-card__author {
    font-weight: 600;
    color: var(--rb-text, #edeae3);
}

.post-card__meta {
    color: var(--rb-label, #a39fae);
}

.post-card__content {
    margin: 0 0 0.75rem;
    color: var(--rb-text, #edeae3);
    white-space: pre-wrap;
    word-break: break-word;
}

.post-card__image {
    display: block;
    max-width: 100%;
    max-height: 420px;
    width: auto;
    height: auto;
    border-radius: 8px;
    margin-bottom: 0.75rem;
    object-fit: contain;
}

.post-card__reactions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.reaction-btn {
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 999px;
    background: transparent;
    color: var(--rb-text, #edeae3);
    padding: 0.2rem 0.6rem;
    font-size: 0.95rem;
    cursor: pointer;
}

.reaction-btn--active {
    border-color: var(--rb-accent, #edeae3);
    background: color-mix(in srgb, var(--rb-accent, #edeae3) 18%, transparent);
}

/* Timeline: per-post Delete/Report action control -- absolutely positioned within .post-card
   (position: relative above) so it sits inset top-right without disturbing the header's existing
   author/meta space-between layout; .post-card__header's padding-right above keeps a long meta
   string (e.g. "3h ago · Group Name") from running underneath it. */
.post-card__actions {
    position: absolute;
    top: 1rem;
    right: 1rem;
}

.post-card__actions-toggle {
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 999px;
    background: transparent;
    color: var(--rb-label, #a39fae);
    width: 1.75rem;
    height: 1.75rem;
    line-height: 1;
    font-size: 1rem;
    cursor: pointer;
}

.post-card__actions-menu {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 0.25rem;
    display: flex;
    flex-direction: column;
    min-width: 7rem;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 8px;
    background: color-mix(in srgb, var(--rb-bg, #15141a) 96%, var(--rb-text, #edeae3) 4%);
    box-shadow: 0 4px 12px color-mix(in srgb, black 25%, transparent);
    overflow: hidden;
    z-index: 5;
}

.post-card__actions-item {
    border: none;
    background: transparent;
    color: var(--rb-text, #edeae3);
    text-align: left;
    padding: 0.5rem 0.75rem;
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
}

.post-card__actions-item:hover {
    background: color-mix(in srgb, var(--rb-text, #edeae3) 10%, transparent);
}

.post-card__actions-reported {
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

.post-card__actions-menu[hidden] {
    display: none;
}

/* Timeline: report form, opened in place of the "..." control by the Report menu item. */
.report-form {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 0.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    width: 14rem;
    max-width: calc(100vw - 3rem);
    padding: 0.75rem;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 8px;
    background: color-mix(in srgb, var(--rb-bg, #15141a) 96%, var(--rb-text, #edeae3) 4%);
    box-shadow: 0 4px 12px color-mix(in srgb, black 25%, transparent);
    z-index: 5;
}

.report-form__field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

.report-form__field select,
.report-form__field textarea {
    font: inherit;
    color: var(--rb-text, #edeae3);
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 6px;
    padding: 0.35rem 0.5rem;
    resize: vertical;
}

.report-form__row {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
}

.report-form__row button {
    font: inherit;
    font-size: 0.8rem;
    border-radius: 6px;
    padding: 0.35rem 0.6rem;
    cursor: pointer;
}

.report-form__row button[type="submit"] {
    background: transparent;
    color: var(--rb-accent, #edeae3);
    border: 1px solid var(--rb-accent, #edeae3);
    font-weight: 600;
}

.report-form__row button[type="submit"]:disabled {
    opacity: 0.6;
    cursor: default;
}

.report-form__cancel {
    background: transparent;
    color: var(--rb-label, #a39fae);
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
}

.report-form__error {
    margin: 0;
    font-size: 0.8rem;
}

/* timeline.js toggles these elements with the plain `hidden` attribute (feed-skeleton,
   feed, composer-group-field before its first "audience=GROUP" selection). The UA stylesheet's
   own `[hidden] { display: none }` rule has the same specificity as a single class selector, so
   without this, whichever rule happens to come later in the cascade wins -- `.feed-skeleton`/
   `.feed`/`.composer__field`'s own `display: flex` above was silently beating it and leaving
   these visible. `[hidden]` here has higher specificity (class + attribute) than any of those, so
   it always wins regardless of source order. Caught live: the Group field rendered even with
   Audience set to Public, and the skeleton shimmer never disappeared once the feed loaded. */
.feed-skeleton[hidden],
.feed[hidden],
.composer__field[hidden] {
    display: none;
}

/* Timeline: mute/filter preferences */
.back-link {
    display: inline-block;
    margin-bottom: 1.5rem;
}

.mute-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.mute-list__item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 12%, transparent);
    border-radius: 8px;
    padding: 0.5rem 0.75rem;
}

.mute-list__item button {
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    background: transparent;
    color: var(--rb-text, #edeae3);
    border-radius: 6px;
    padding: 0.25rem 0.6rem;
    cursor: pointer;
}

.muted-note {
    font-size: 0.85rem;
    color: var(--rb-label, #a39fae);
}

.filter-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0.75rem 0;
}

.filter-chip {
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    background: transparent;
    color: var(--rb-text, #edeae3);
    border-radius: 999px;
    padding: 0.3rem 0.8rem;
    cursor: pointer;
}

.filter-chip--active {
    border-color: var(--rb-accent, #edeae3);
    background: color-mix(in srgb, var(--rb-accent, #edeae3) 18%, transparent);
}

/* Messaging: thread list + start-new-conversation list (pages/templates/pages/messages.html) --
   same list-item/border/`color-mix()` token approach as .mute-list above. */
.messages-page {
    gap: 1.5rem;
}

.thread-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.thread-list__item a {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.75rem;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 12%, transparent);
    border-radius: 8px;
    padding: 0.6rem 0.85rem;
    color: var(--rb-text, #edeae3);
    text-decoration: none;
}

.thread-list__item a:hover {
    background: color-mix(in srgb, var(--rb-text, #edeae3) 6%, transparent);
}

.thread-list__name {
    font-weight: 600;
}

.thread-list__meta {
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

/* Messaging: one conversation (pages/templates/pages/chat_thread.html). */
.chat-page {
    gap: 1rem;
}

.chat-section {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.load-earlier-btn {
    align-self: center;
    background: transparent;
    color: var(--rb-accent, #edeae3);
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 999px;
    padding: 0.35rem 0.9rem;
    font-size: 0.85rem;
    cursor: pointer;
    display: inline-block;
}

.load-earlier-btn:disabled {
    opacity: 0.6;
    cursor: default;
}

/* Sets its own `display` at the same class-selector specificity as [hidden] -- same reasoning
   documented above for .feed/.feed-skeleton/.composer__field/.chat-messages. */
.load-earlier-btn[hidden] {
    display: none;
}

.chat-messages {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

/* #chat-skeleton reuses .feed-skeleton (see below), whose own [hidden] override already applies;
   .chat-messages needs its own since it sets display: flex at the same class-selector
   specificity as [hidden], same reasoning as .feed/.feed-skeleton documented above. */
.chat-messages[hidden] {
    display: none;
}

.chat-bubble {
    align-self: flex-start;
    max-width: 75%;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 15%, transparent);
    border-radius: 12px;
    padding: 0.5rem 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
}

.chat-bubble--own {
    align-self: flex-end;
    border-color: var(--rb-accent, #edeae3);
    background: color-mix(in srgb, var(--rb-accent, #edeae3) 14%, transparent);
}

.chat-bubble__text {
    margin: 0;
    color: var(--rb-text, #edeae3);
    white-space: pre-wrap;
    word-break: break-word;
}

.chat-bubble__text--error {
    font-style: italic;
    color: var(--rb-label, #a39fae);
}

.chat-bubble__time {
    align-self: flex-end;
    font-size: 0.7rem;
    color: var(--rb-label, #a39fae);
}

.chat-composer {
    display: flex;
    gap: 0.6rem;
    align-items: flex-end;
}

.chat-composer textarea {
    flex: 1;
    box-sizing: border-box;
    resize: vertical;
    min-height: 3rem;
    padding: 0.6rem;
    border-radius: 8px;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    background: color-mix(in srgb, var(--rb-bg, #15141a) 92%, var(--rb-text, #edeae3) 8%);
    color: var(--rb-text, #edeae3);
    font: inherit;
}

.chat-composer button {
    background: transparent;
    color: var(--rb-accent, #edeae3);
    border: 1px solid var(--rb-accent, #edeae3);
    border-radius: 8px;
    padding: 0.5rem 1.25rem;
    font-weight: 600;
    cursor: pointer;
}

.chat-composer button:disabled {
    opacity: 0.6;
    cursor: default;
}

/* forum_thread.html reuses .chat-composer for its reply form and toggles it with the plain
   `hidden` attribute while the thread is still loading (chat_thread.html's own #chat-composer is
   never hidden, so this override wasn't needed until now) -- same class-selector-vs-[hidden]
   specificity fix as .feed/.feed-skeleton/.composer__field/.load-earlier-btn/.chat-messages above. */
.chat-composer[hidden] {
    display: none;
}

/* Profile stats (roadmap items 16/19): lifetime mileage + states-visited badges. Read-only, so no
   form/composer rules needed here -- just the skeleton (reuses .feed-skeleton), an error message
   (reuses .error), and a small stat-card grid. */
.profile-page {
    gap: 1.5rem;
}

.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1rem;
}

.stat-grid[hidden] {
    display: none;
}

.stat-card {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 15%, transparent);
    border-radius: 12px;
    padding: 1rem;
}

.stat-card__label {
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

.stat-card__value {
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--rb-text, #edeae3);
}

.stat-card__badge {
    margin: 0;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--rb-accent, #edeae3);
}

.state-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin-top: 0.25rem;
}

.state-badge {
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 6px;
    padding: 0.15rem 0.45rem;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--rb-text, #edeae3);
}

/* Forum (roadmap item 48): thread list, new-thread composer, thread detail + flat replies. Same
   --rb-*/color-mix() token approach as Timeline/Messaging above -- no hardcoded colors, so a
   rider's reflected theme (see "Rider website login & theme reflection" in CLAUDE.md) still
   applies here. */
.forum-page {
    gap: 1.25rem;
}

.forum-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 0.75rem;
}

.forum-toolbar__field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

.forum-toolbar__field select {
    font: inherit;
    color: var(--rb-text, #edeae3);
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 6px;
    padding: 0.35rem 0.5rem;
}

.forum-toolbar button,
.new-thread-form__row button[type="submit"] {
    background: transparent;
    color: var(--rb-accent, #edeae3);
    border: 1px solid var(--rb-accent, #edeae3);
    border-radius: 8px;
    padding: 0.5rem 1.1rem;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

.new-thread-form {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 15%, transparent);
    border-radius: 12px;
    padding: 1rem;
}

.new-thread-form[hidden] {
    display: none;
}

.new-thread-form__field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

.new-thread-form__field input,
.new-thread-form__field select,
.new-thread-form__field textarea {
    font: inherit;
    color: var(--rb-text, #edeae3);
    background: color-mix(in srgb, var(--rb-bg, #15141a) 92%, var(--rb-text, #edeae3) 8%);
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 6px;
    padding: 0.4rem 0.6rem;
    resize: vertical;
}

.new-thread-form__row {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
}

.new-thread-form__row button[type="button"] {
    background: transparent;
    color: var(--rb-label, #a39fae);
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 8px;
    padding: 0.5rem 1.1rem;
    font: inherit;
    cursor: pointer;
}

.forum-thread-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.forum-thread-list[hidden] {
    display: none;
}

.forum-thread-card__link {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 12%, transparent);
    border-radius: 10px;
    padding: 0.75rem 0.9rem;
    color: var(--rb-text, #edeae3);
    text-decoration: none;
}

.forum-thread-card__link:hover {
    background: color-mix(in srgb, var(--rb-text, #edeae3) 6%, transparent);
}

.forum-thread-card__title {
    font-weight: 600;
}

.forum-thread-card__meta {
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

.forum-category-badge {
    align-self: flex-start;
    border: 1px solid color-mix(in srgb, var(--rb-accent, #edeae3) 40%, transparent);
    color: var(--rb-accent, #edeae3);
    border-radius: 999px;
    padding: 0.1rem 0.55rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

/* Forum thread detail page */
.forum-thread-page {
    gap: 1.25rem;
}

.thread-detail {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 15%, transparent);
    border-radius: 12px;
    padding: 1.25rem;
}

.thread-detail[hidden] {
    display: none;
}

.thread-detail__meta {
    margin: 0;
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

.thread-detail__body {
    margin: 0;
    color: var(--rb-text, #edeae3);
    white-space: pre-wrap;
    word-break: break-word;
}

.reply-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

.reply-card {
    position: relative;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 12%, transparent);
    border-radius: 10px;
    padding: 0.75rem 0.9rem;
}

.reply-card__meta {
    margin: 0 0 0.3rem;
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

.reply-card__body {
    margin: 0;
    color: var(--rb-text, #edeae3);
    white-space: pre-wrap;
    word-break: break-word;
}

.delete-btn {
    background: transparent;
    color: var(--rb-accent, #edeae3);
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 6px;
    padding: 0.35rem 0.75rem;
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
}

.delete-btn--small {
    margin-top: 0.4rem;
    padding: 0.2rem 0.55rem;
    font-size: 0.75rem;
}

.delete-btn[hidden] {
    display: none;
}

/* Profile page editable sections (Personal Information / Message Templates / Theme / Emergency
   Contacts, added 2026-08-31) -- same --rb-*/color-mix() token approach as every other page in
   this file, and the same .new-thread-form__field-style label+input pattern Forum already
   established, generalized into a reusable .settings-field so this page doesn't invent a fourth
   near-identical input style. */
.settings-form {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

/* Same class-selector-vs-[hidden]-specificity fix already documented several times in this file
   (.feed/.feed-skeleton/.composer__field/.load-earlier-btn/.chat-messages/.new-thread-form/
   .chat-composer/.delete-btn) -- .settings-form's own `display: flex` above would otherwise beat
   the UA stylesheet's `[hidden] { display: none }` at equal specificity, since this rule is
   declared later in the cascade. */
.settings-form[hidden] {
    display: none;
}

.settings-section {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 15%, transparent);
    border-radius: 12px;
    padding: 1rem;
}

.settings-section h2 {
    margin: 0;
    font-size: 1.1rem;
}

.settings-field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    font-size: 0.8rem;
    color: var(--rb-label, #a39fae);
}

.settings-field input[type="text"],
.settings-field input[type="number"],
.settings-field select,
.settings-field textarea {
    font: inherit;
    color: var(--rb-text, #edeae3);
    background: color-mix(in srgb, var(--rb-bg, #15141a) 92%, var(--rb-text, #edeae3) 8%);
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 6px;
    padding: 0.4rem 0.6rem;
    resize: vertical;
}

.settings-field--checkbox {
    flex-direction: row;
    align-items: center;
    gap: 0.5rem;
    color: var(--rb-text, #edeae3);
    font-size: 0.9rem;
}

.settings-field--checkbox input[type="checkbox"] {
    width: 1rem;
    height: 1rem;
}

.settings-field--color input[type="color"] {
    width: 3.5rem;
    height: 2rem;
    padding: 0.1rem;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 20%, transparent);
    border-radius: 6px;
    background: transparent;
    cursor: pointer;
}

.settings-field-row {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
}

.settings-field-row > .settings-field {
    flex: 1 1 10rem;
}

/* Same [hidden]-specificity fix as .settings-form above -- #custom-theme-fields/#custom-theme-colors
   are toggled with the plain hidden attribute in profile.js's updateCustomThemeVisibility(). */
.settings-field-row[hidden] {
    display: none;
}

.settings-save-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.settings-save-row button {
    background: transparent;
    color: var(--rb-accent, #edeae3);
    border: 1px solid var(--rb-accent, #edeae3);
    border-radius: 8px;
    padding: 0.5rem 1.1rem;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

.settings-save-row button:disabled {
    opacity: 0.6;
    cursor: default;
}

.settings-save-status {
    font-size: 0.85rem;
    color: var(--rb-text, #edeae3);
}

.settings-save-status--error {
    color: var(--rb-accent, #edeae3);
    font-weight: 600;
}

.contact-list {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.contact-list[hidden] {
    display: none;
}

.contact-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.75rem;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 12%, transparent);
    border-radius: 10px;
    padding: 0.75rem;
}

.contact-row .settings-field {
    flex: 1 1 9rem;
}

.contact-row .settings-field--checkbox {
    flex: 0 0 auto;
}

/* Small meta text -- timestamps, category/type labels, post metadata -- gets IBM Plex Mono
   (visual polish pass, roadmap items 49-51): a technical, telemetry-adjacent feel fitting a
   motorcycle app, and a clear typographic distinction from body copy. --rb-mono-font is defined
   near the top of this file alongside --rb-body-font. */
.post-card__meta,
.thread-list__meta,
.forum-thread-card__meta,
.thread-detail__meta,
.reply-card__meta,
.state-badge,
.forum-category-badge,
.composer__char-count,
.chat-bubble__time,
.stat-card__label {
    font-family: var(--rb-mono-font);
}

/* ==========================================================================
   App shell: persistent header + sidebar (roadmap items 49/50)
   ==========================================================================
   Fixed ~64px header (wordmark + account/logout) and fixed ~240px left sidebar (Timeline/
   Messages/Forum/Profile/Marketplace/Help), both position:fixed so they stay in place while the
   page scrolls under/beside them -- the normal document scroll is the only scroll container
   (no nested overflow div), matching this repo's preference for the simplest mechanism that
   works. .app-content offsets around both via margin. Collapses to a hamburger-triggered drawer
   under the mobile breakpoint (see the media query below) -- a bottom tab bar was considered and
   rejected: 6 items (including two disabled ones) reads cramped as icon-only tabs, and a drawer
   reuses the exact same nav markup/active-state CSS as desktop with no duplication. */
.app-shell {
    min-height: 100vh;
}

.app-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: 64px;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0 1.25rem;
    background: var(--rb-shell-bg);
    border-bottom: 1px solid var(--rb-shell-border);
    box-sizing: border-box;
}

.app-header__menu-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    border: none;
    border-radius: 6px;
    background: transparent;
    color: var(--rb-text, #edeae3);
    cursor: pointer;
}

.app-header__menu-toggle:hover {
    background: color-mix(in srgb, var(--rb-text, #edeae3) 10%, transparent);
}

.app-header__menu-toggle svg {
    width: 1.5rem;
    height: 1.5rem;
}

.app-header__brand {
    font-family: 'Anton', -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    font-size: 1.35rem;
    letter-spacing: 0.02em;
    color: var(--rb-text, #edeae3);
    text-decoration: none;
    white-space: nowrap;
}

.app-header__account {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    margin-left: auto;
    font-size: 0.9rem;
}

.app-shell-scrim {
    position: fixed;
    inset: 0;
    top: 64px;
    background: color-mix(in srgb, black 55%, transparent);
    z-index: 35;
}

.app-shell-scrim[hidden] {
    display: none;
}

.app-sidebar {
    position: fixed;
    top: 64px;
    bottom: 0;
    left: 0;
    width: 240px;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 1rem 0.75rem;
    background: var(--rb-shell-bg);
    border-right: 1px solid var(--rb-shell-border);
    overflow-y: auto;
    z-index: 38;
    box-sizing: border-box;
}

.app-sidebar__link {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0.75rem;
    border-radius: 8px;
    color: var(--rb-text, #edeae3);
    text-decoration: none;
    font-size: 0.95rem;
}

.app-sidebar__link:hover {
    background: color-mix(in srgb, var(--rb-text, #edeae3) 8%, transparent);
}

.app-sidebar__icon {
    flex: none;
    width: 1.25rem;
    height: 1.25rem;
}

/* Active nav item (matched per-page in base.html via request.resolver_match.url_name) uses the
   rider's accent color -- both the text/icon color and a left-edge indicator bar. */
.app-sidebar__link--active {
    color: var(--rb-accent, #edeae3);
    background: color-mix(in srgb, var(--rb-accent, #edeae3) 14%, transparent);
    font-weight: 600;
}

.app-sidebar__link--active::before {
    content: "";
    position: absolute;
    left: -0.75rem;
    top: 0.35rem;
    bottom: 0.35rem;
    width: 3px;
    border-radius: 999px;
    background: var(--rb-accent, #edeae3);
}

/* Marketplace/Help -- no real page yet, shown disabled/"Coming Soon" rather than a dead link. */
.app-sidebar__link--disabled {
    color: var(--rb-label, #a39fae);
    cursor: default;
    opacity: 0.65;
}

/* Log Out -- pinned to the bottom of the sidebar (not the header, moved per direct request) via
   flex margin-top: auto on the wrapping form, not markup order, so it stays last even as more
   nav items are added above it. */
.app-sidebar__logout {
    margin-top: auto;
    padding-top: 0.5rem;
    border-top: 1px solid var(--rb-shell-border);
}

.app-sidebar__link--button {
    width: 100%;
    background: none;
    border: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.app-sidebar__badge {
    margin-left: auto;
    font-family: var(--rb-mono-font);
    font-size: 0.65rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 0.15rem 0.4rem;
    border-radius: 999px;
    border: 1px solid color-mix(in srgb, var(--rb-text, #edeae3) 25%, transparent);
    color: var(--rb-label, #a39fae);
}

.app-content {
    margin-left: 240px;
    padding-top: 64px;
    min-height: 100vh;
    box-sizing: border-box;
}

@media (max-width: 768px) {
    .app-header__menu-toggle {
        display: inline-flex;
    }

    .app-sidebar {
        width: min(80vw, 280px);
        transform: translateX(-100%);
        transition: transform 0.2s ease;
        box-shadow: 4px 0 16px color-mix(in srgb, black 35%, transparent);
    }

    .app-sidebar.is-open {
        transform: translateX(0);
    }

    .app-content {
        margin-left: 0;
    }
}

/* ==========================================================================
   Timeline compose FAB (roadmap item 51)
   ==========================================================================
   The composer used to sit at the top of the Timeline page and scroll with the feed. It now
   opens from a fixed circular button, bottom-right, using the rider's accent color -- genuinely
   fixed-position (no ancestor sets transform/filter, which would otherwise re-scope `position:
   fixed`), so it never moves during a feed scroll. The composer itself lives inside a native
   <dialog> (open/close mechanics in static/js/shell.js) rather than a hand-rolled modal --
   zero-dependency, and <dialog> gives real focus-trapping/Escape-to-close/top-layer stacking for
   free. */
.compose-fab {
    position: fixed;
    right: 1.5rem;
    bottom: 1.5rem;
    width: 3.5rem;
    height: 3.5rem;
    border-radius: 50%;
    border: none;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--rb-accent, #d32f2f);
    color: #fff;
    box-shadow: 0 6px 18px color-mix(in srgb, black 35%, transparent);
    cursor: pointer;
    z-index: 25;
}

.compose-fab svg {
    width: 1.5rem;
    height: 1.5rem;
}

.compose-fab:hover {
    filter: brightness(1.08);
}

.compose-dialog {
    border: none;
    padding: 0;
    background: transparent;
    max-width: min(92vw, 34rem);
    width: 100%;
    margin: auto;
}

.compose-dialog::backdrop {
    background: color-mix(in srgb, black 55%, transparent);
}

.compose-dialog[open] {
    display: block;
}

.compose-dialog .composer {
    max-height: 85vh;
    overflow-y: auto;
    box-sizing: border-box;
    background: var(--rb-bg, #15141a);
    box-shadow: 0 12px 32px color-mix(in srgb, black 40%, transparent);
}

.compose-dialog__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.5rem;
}

.compose-dialog__header h2 {
    margin: 0;
}

.compose-dialog__close {
    flex: none;
    border: none;
    background: transparent;
    color: var(--rb-label, #a39fae);
    width: 1.75rem;
    height: 1.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    cursor: pointer;
}

.compose-dialog__close:hover {
    background: color-mix(in srgb, var(--rb-text, #edeae3) 10%, transparent);
}

.compose-dialog__close svg {
    width: 1.1rem;
    height: 1.1rem;
}

/* Timeline needs extra bottom clearance so the FAB never sits on top of the last feed card. */
.timeline-page {
    padding-bottom: 6rem;
}
