/* campfire.css: Campfire room and dock. */
/* --- Campfire --------------------------------------------------------------
   The shared room is deliberately warmer than private Comms Relay without becoming
   a separate visual language. The ember gradient gives the public surface a clear
   home, while the transcript remains calm enough to scan at speed. */
.campfire-page .page-main,
.campfire-page main { isolation: isolate; }

.campfire-page .page-container {
    display: flex;
    flex-direction: column;
    height: calc(100vh - var(--header-height));
    height: calc(100dvh - var(--header-height));
}
/* Fills the main content area (everything right of the sidebar), edge to edge, rather
   than sitting as a card centered inside the usual max-width gutter: a chat room reads
   better with the space than a form/article page does. `body.campfire-page .site-body
   > .page-container` (not the plain `.campfire-page .page-container` above) is
   deliberate: Frontier restyles `.page-container` at (0,3,1) specificity
   (`body.interface-frontier .site-body > .page-container`, several breakpoints, see
   ~line 14320) with its own max-width/padding, which otherwise wins over a plain
   two-class campfire selector regardless of source order. Matching that specificity and
   sitting later in the file settles the tie in Campfire's favor at every breakpoint,
   Frontier included. */
body.campfire-page .site-body > .page-container {
    max-width: none;
    padding: 0;
}
.campfire-app {
    --campfire-accent: #e99252;
    --campfire-glow: rgb(233 146 82 / 11%);
    position: relative;
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
    background: color-mix(in srgb, var(--bg-surface) 96%, var(--campfire-accent));
}
.campfire-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 18px;
    border-bottom: 1px solid var(--border-subtle);
    background: linear-gradient(105deg, rgb(233 146 82 / 12%), transparent 58%);
}
.campfire-bar__id { display: inline-flex; align-items: center; gap: 10px; min-width: 0; }
.campfire-bar__title { margin: 0; font-family: var(--font-display, inherit); font-size: 1.1rem; white-space: nowrap; }
.campfire-bar__status { color: var(--text-muted); font-size: .68rem; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; white-space: nowrap; }
.campfire-bar__meta { display: inline-flex; align-items: center; gap: 9px; min-width: 0; color: var(--text-muted); font-size: .76rem; }
.campfire-bar__welcome { overflow: hidden; max-width: 360px; text-overflow: ellipsis; white-space: nowrap; }
.campfire-bar__chip { padding: 3px 9px; border: 1px solid var(--border-subtle); border-radius: 999px; white-space: nowrap; }
/* Mixing the brand orange toward the theme's own text keeps it warm and on-brand
   while staying above 4.5:1 on the light palettes, where raw accent-on-white fails. */
.campfire-bar__staff { padding: 3px 9px; border-radius: 999px; color: color-mix(in srgb, var(--campfire-accent) 52%, var(--text-primary)); font-weight: 600; white-space: nowrap; }
.campfire-live-dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 999px;
    background: #f6a65a;
    box-shadow: 0 0 0 4px rgb(246 166 90 / 12%), 0 0 16px rgb(246 166 90 / 60%);
}
.campfire-live-dot.is-quiet { background: var(--text-muted); box-shadow: none; }
.campfire-live-dot.is-live { background: #75d69a; box-shadow: 0 0 0 4px rgb(117 214 154 / 12%), 0 0 16px rgb(117 214 154 / 52%); }
.campfire-live-dot.is-polling { background: #f6b35a; box-shadow: 0 0 0 4px rgb(246 179 90 / 12%), 0 0 16px rgb(246 179 90 / 52%); animation: campfire-status-pulse 1.6s ease-in-out infinite; }
.campfire-live-dot.is-offline { background: var(--text-muted); box-shadow: none; }
.campfire-dock__heading h2 { margin: 0; font-family: var(--font-display, inherit); }
.campfire-notice {
    display: flex;
    gap: 10px;
    align-items: center;
    margin: 10px 14px 0;
    padding: 8px 12px;
    border: 1px solid rgb(233 146 82 / 20%);
    border-radius: 10px;
    background: var(--bg-elevated);
    color: var(--text-secondary);
    font-size: .8rem;
    line-height: 1.45;
}
.campfire-notice p { margin: 0; }
.campfire-notice__short { display: none; }
.campfire-notice__close {
    flex: 0 0 auto;
    margin: -5px -5px 0 auto;
    padding: 4px 8px;
    border: 0;
    background: transparent;
    color: var(--text-muted);
    font-size: 1.1rem;
    cursor: pointer;
}
.campfire-notice__icon { color: var(--campfire-accent); font-size: 1.1rem; line-height: 1.2; }
.campfire-transcript {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow-y: auto;
    padding: 12px 12px 10px;
    scroll-behavior: smooth;
    scrollbar-color: var(--border-color) transparent;
}
.campfire-message {
    position: relative;
    display: flex;
    gap: 11px;
    padding: 2px 8px;
    border-radius: var(--radius-md);
    animation: campfire-message-in .2s ease-out both;
}
.campfire-message:not(.is-grouped) { margin-top: 10px; }
.campfire-transcript > .campfire-message:first-child,
.campfire-date-separator + .campfire-message { margin-top: 2px; }
@media (hover: hover) {
    .campfire-message:hover { background: rgb(255 255 255 / 3%); }
    .campfire-message:hover .campfire-message__gutter-time { opacity: 1; }
}
.campfire-message.is-own { background: linear-gradient(90deg, rgb(233 146 82 / 10%), transparent 72%); }
.campfire-message.is-removed { opacity: .7; }
.campfire-message__gutter { flex: 0 0 38px; display: flex; align-items: flex-start; justify-content: center; padding-top: 2px; }
.campfire-message__gutter-time { align-self: center; color: var(--text-muted); font-size: .6rem; font-variant-numeric: tabular-nums; opacity: 0; transition: opacity .12s; }
.campfire-message__avatar,
.campfire-mention-option__avatar {
    display: grid;
    place-items: center;
    width: 38px;
    height: 38px;
    overflow: hidden;
    border: 1px solid rgb(233 146 82 / 28%);
    border-radius: 11px;
    background: linear-gradient(145deg, rgb(233 146 82 / 22%), rgb(111 75 113 / 28%));
    color: #f3bf8c;
    font-weight: 700;
}
.campfire-message__avatar img { width: 100%; height: 100%; object-fit: cover; }
.campfire-message__content { flex: 1; min-width: 0; }
.campfire-message__byline {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 1px;
    color: var(--text-muted);
    font-size: .74rem;
}
.campfire-message__byline strong { color: var(--text-primary); font-size: .84rem; font-weight: 700; }
.campfire-message__byline time { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.campfire-message__body {
    position: relative;
    overflow-wrap: anywhere;
    max-height: 16em;
    overflow: hidden;
    color: var(--text-primary);
    font-size: .93rem;
    line-height: 1.55;
}
.campfire-message__body.is-expanded { max-height: none; }
.campfire-message__body.is-overflowing:not(.is-expanded)::after {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    height: 2.5em;
    background: linear-gradient(to bottom, transparent, var(--bg-surface));
    content: '';
    pointer-events: none;
}
.campfire-message__body [style*="font-size"] { font-size: 1em !important; }
.campfire-history-row .campfire-message__body { max-height: none; }
.campfire-message__expand {
    margin-top: 4px;
    padding: 2px 0;
    border: 0;
    background: transparent;
    color: var(--campfire-accent);
    font-size: .75rem;
    font-weight: 700;
    cursor: pointer;
}
.campfire-message__body > :first-child { margin-top: 3px; }
.campfire-message__body > :last-child { margin-bottom: 0; }
.campfire-message__body .bbcode-h1,
.campfire-message__body .bbcode-h2,
.campfire-message__body .bbcode-h3 {
    margin: 2px 0;
    color: #f1bb84;
    font-size: .95rem;
    font-weight: 700;
    line-height: 1.2;
}
.campfire-message__body .bbcode-columns { display: block; }
.campfire-message__body .bbcode-col { display: block; margin: 0 0 7px; }
.campfire-message__body .bbcode-code { max-width: 100%; overflow-x: auto; }
.campfire-message__body .bbcode-image { display: block; max-height: 280px; border-radius: 8px; }
.campfire-message__body .bbcode-spoiler { margin: 5px 0; }
.campfire-message__body .bbcode-yt { max-width: 260px; margin: 4px 0; }
.campfire-message__tombstone { margin: 0; color: var(--text-muted); font-style: italic; }
.campfire-message__menu { flex: 0 0 auto; align-self: flex-start; position: relative; }
@media (hover: hover) {
    .campfire-message__menu { opacity: 0; transition: opacity .12s; }
    .campfire-message:hover .campfire-message__menu,
    .campfire-message:focus-within .campfire-message__menu { opacity: 1; }
}
.campfire-message__menu summary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    min-height: 26px;
    border-radius: 7px;
    color: var(--text-muted);
    cursor: pointer;
    list-style: none;
    font-size: .82rem;
}
.campfire-message__menu summary::-webkit-details-marker { display: none; }
.campfire-message__menu summary:focus-visible { background: var(--campfire-glow); color: var(--text-primary); }
@media (hover: hover) {
    .campfire-message__menu summary:hover { background: var(--campfire-glow); color: var(--text-primary); }
}
.campfire-message__menu-panel {
    position: absolute;
    z-index: 3;
    top: 24px;
    right: 0;
    width: 230px;
    padding: 12px;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    background: var(--bg-elevated);
    box-shadow: 0 14px 30px rgb(0 0 0 / 28%);
}
.campfire-message__menu-panel form { display: grid; gap: 8px; }
.campfire-message__menu-panel label { color: var(--text-primary); font-size: .78rem; }
.campfire-message__menu-panel textarea { width: 100%; min-height: 64px; resize: vertical; }
.campfire-empty { display: grid; place-items: center; min-height: 220px; color: var(--text-muted); text-align: center; }
.campfire-empty strong { color: var(--text-primary); }
.campfire-empty p { margin: 5px 0 0; }
.campfire-empty__ember { display: block; margin-bottom: 6px; color: var(--campfire-accent); font-size: 2rem; }
.campfire-composer {
    flex: 0 0 auto;
    padding: 10px 14px 12px;
    border-top: 1px solid var(--border-subtle);
    background: var(--bg-surface);
}
.campfire-composer--closed { display: flex; align-items: center; gap: 12px; color: var(--text-secondary); }
.campfire-composer--closed p { margin: 0; font-size: .82rem; }
.campfire-composer--closed strong { display: block; margin-bottom: 2px; color: var(--text-primary); }
.campfire-composer__icon { color: var(--campfire-accent); font-size: 1.1rem; line-height: 1.4; }
.campfire-composer__row { display: flex; align-items: flex-end; gap: 8px; }
.campfire-composer__toggle {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    border: 1px solid var(--border-color);
    border-radius: 11px;
    background: var(--bg-elevated);
    color: var(--text-secondary);
    font-weight: 700;
    font-size: .82rem;
    cursor: pointer;
}
.campfire-composer__toggle.is-active { border-color: var(--campfire-accent); color: color-mix(in srgb, var(--campfire-accent) 52%, var(--text-primary)); }
.campfire-composer__field { position: relative; flex: 1; min-width: 0; }
.campfire-composer textarea {
    display: block;
    width: 100%;
    min-height: 40px;
    max-height: 168px;
    padding: 9px 13px;
    border: 1px solid var(--border-color);
    border-radius: 13px;
    background: var(--bg-elevated);
    color: var(--text-primary);
    font: inherit;
    line-height: 1.45;
    resize: none;
    overflow-y: hidden;
}
.campfire-composer textarea:focus-visible { border-color: color-mix(in srgb, var(--campfire-accent) 60%, var(--border-color)); outline: none; }
.campfire-composer__send {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border: 0;
    border-radius: 11px;
    background: var(--campfire-accent);
    color: #1c1206;
    font-size: 1rem;
    cursor: pointer;
}
.campfire-composer__send[disabled] { opacity: .6; cursor: progress; }
.campfire-composer__format { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.campfire-composer__fmt {
    min-width: 34px;
    height: 30px;
    padding: 0 9px;
    border: 1px solid var(--border-color);
    border-radius: 8px;
    background: var(--bg-elevated);
    color: var(--text-secondary);
    font-size: .82rem;
    cursor: pointer;
}
.campfire-composer__hint { margin: 8px 0 0; color: var(--text-muted); font-size: .7rem; }
.campfire-composer__hint kbd { padding: 1px 5px; border: 1px solid var(--border-color); border-radius: 4px; font-size: .66rem; }
.campfire-composer__mention-wrap { position: absolute; left: 0; right: 0; bottom: calc(100% + 8px); z-index: 5; }
.campfire-mention-list {
    width: 100%;
    max-height: 230px;
    overflow-y: auto;
    padding: 5px;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    background: var(--bg-elevated);
    box-shadow: 0 16px 28px rgb(0 0 0 / 35%);
}
.campfire-mention-option {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    padding: 7px 8px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--text-primary);
    text-align: left;
    cursor: pointer;
}
.campfire-mention-option:focus-visible,
.campfire-mention-option.is-highlighted { background: var(--campfire-glow); }
@media (hover: hover) {
    .campfire-mention-option:hover { background: var(--campfire-glow); }
}
.campfire-mention-option__avatar { width: 25px; height: 25px; border-radius: 8px; font-size: .72rem; }
.campfire-mention-empty { margin: 7px; color: var(--text-muted); font-size: .75rem; }
.campfire-link-host { color: var(--text-muted); font-size: .82em; white-space: nowrap; }
.campfire-date-separator { display: flex; align-items: center; gap: 10px; margin: 12px 9px 4px; color: var(--text-muted); font-size: .68rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.campfire-date-separator::before,
.campfire-date-separator::after { flex: 1; height: 1px; background: var(--border-subtle); content: ''; }
/* Shared by the Campfire transcript (both the full room and the dock, inserted
   client-side by campfireRoom.scrollToInitialPosition against a localStorage
   last-seen id: there's no per-user read receipt on the shared room) and the
   Comms Relay thread (rendered server-side from membership.last_read_message_id,
   see _message_rows.html). Coloured with --color-reward, the same "something's
   waiting on you" accent the notification/nav unread dots already use, but the
   text label carries the meaning: colour alone is never the only signal. */
.unread-divider { display: flex; align-items: center; gap: 10px; margin: 10px 4px; color: var(--color-reward); font-size: .68rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
.unread-divider::before,
.unread-divider::after { flex: 1; height: 1px; background: color-mix(in srgb, var(--color-reward) 55%, transparent); content: ''; }
.campfire-new-messages {
    position: relative;
    z-index: 3;
    align-self: center;
    margin: -34px auto 6px;
    padding: 6px 14px;
    border: 1px solid color-mix(in srgb, var(--campfire-accent) 55%, var(--border-color));
    border-radius: 999px;
    background: var(--bg-elevated);
    color: var(--text-primary);
    font-size: .78rem;
    font-weight: 600;
    box-shadow: 0 8px 20px rgb(0 0 0 / 22%);
    cursor: pointer;
}
/* z-index must clear .site-header's 100 (layout.css), matching the tier every other
   modalShell dialog uses (.hatch-modal etc. sit at 9990+). At 20 the header painted over
   the panel's top edge wherever the two geometrically overlapped: on a short viewport
   (iPad landscape, ~744-834px tall) the max-height calc below always leaves the panel's
   top edge just 24px under the viewport top, inside the header's 62px band, so the
   heading row (title + "Open room" link + close button) rendered behind the header and
   was unclickable. */
.campfire-dock { position: fixed; z-index: 9990; right: 20px; bottom: 20px; }
/* The launcher never sits over a modal (it outranks their z-index), and on a phone it
   stays off a Patchwork play surface, where it covered mat cells and the Deliver button.
   The Campfire page in the nav still works there. */
body.modal-open .campfire-dock { display: none; }
@media (width < 768px) {
    body:has(.pwk-run:not([data-delivered="true"])) .campfire-dock,
    body:has(.dsn-editor) .campfire-dock { display: none; }
}
.campfire-dock__trigger {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 9px;
    min-height: 44px;
    padding: 10px 14px;
    border: 1px solid rgb(233 146 82 / 45%);
    border-radius: 999px;
    background: color-mix(in srgb, var(--bg-surface) 93%, #e99252);
    color: var(--text-primary);
    box-shadow: 0 10px 25px rgb(0 0 0 / 24%), 0 0 24px rgb(233 146 82 / 12%);
    cursor: pointer;
}
/* Unread-while-closed dot: a closed dock has no other way to say a message
   arrived (see campfireRoom's hidden-cadence refresh in alpine-components.js).
   Same attention colour as .nav-active-dot, not the trigger's own warm flame
   orange, so it reads as new rather than blending into the always-on chrome. */
.campfire-dock__unread {
    position: absolute;
    top: 2px;
    right: 2px;
    width: 10px;
    height: 10px;
    border-radius: 999px;
    background: var(--color-reward);
    box-shadow: 0 0 0 2px var(--bg-surface), var(--glow-reward);
    animation: nav-dot-pulse 1.8s ease-in-out infinite;
}
body.reduced-motion .campfire-dock__unread { animation: none; }
@media (prefers-reduced-motion: reduce) {
    .campfire-dock__unread { animation: none; }
}
@media (hover: hover) {
    .campfire-dock__trigger:hover { border-color: #e99252; transform: translateY(-1px); }
}
.campfire-dock__flame { color: #f0aa6d; font-size: 1.05rem; }
.campfire-dock__trigger-label { font-size: .8rem; font-weight: 700; }
.campfire-dock__trigger .campfire-live-dot { width: 7px; height: 7px; box-shadow: none; }
.campfire-dock__panel {
    position: absolute;
    right: 0;
    bottom: 56px;
    width: min(410px, calc(100vw - 32px));
    /* The 100px budget below the header height is the bottom-offset(76px)+margin this
       always leaves; without also subtracting the header, a short viewport (iPad
       landscape) put the panel's top edge inside the sticky header's own band. */
    max-height: min(730px, calc(100vh - var(--header-height) - 100px));
    max-height: min(730px, calc(100dvh - var(--header-height) - 100px));
    overflow: hidden;
    border: 1px solid rgb(233 146 82 / 35%);
    border-radius: 16px;
    background: var(--bg-surface);
    box-shadow: 0 22px 60px rgb(0 0 0 / 38%), 0 0 45px rgb(233 146 82 / 12%);
}
.campfire-dock__content {
    display: flex;
    max-height: min(730px, calc(100vh - var(--header-height) - 100px));
    max-height: min(730px, calc(100dvh - var(--header-height) - 100px));
    flex-direction: column;
}
.campfire-dock__heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 14px; border-bottom: 1px solid var(--border-subtle); background: linear-gradient(105deg, rgb(233 146 82 / 12%), transparent 60%); }
.campfire-dock__heading-id { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.campfire-dock__heading h2 { font-size: .98rem; white-space: nowrap; }
.campfire-dock__heading-status { color: var(--text-muted); font-size: .62rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
.campfire-dock__heading-actions { display: inline-flex; align-items: center; gap: 6px; }
.campfire-dock__close { padding: 4px 8px; border: 0; background: transparent; color: var(--text-muted); font-size: 1.15rem; cursor: pointer; }
.campfire-dock__full-link { color: color-mix(in srgb, var(--campfire-accent) 52%, var(--text-primary)); font-size: .7rem; white-space: nowrap; }
/* overscroll-behavior: contain, not body scroll lock (the dock no longer uses
   modalShell, see _campfire_dock.html): a player scrolling the page behind the floating
   panel must still be able to, so all this needs to stop is a bounce at the transcript's
   own top/bottom edge from chaining into whatever sits behind it. */
.campfire-dock__transcript { flex: 1; min-height: 170px; max-height: 360px; overflow-y: auto; overscroll-behavior: contain; padding: 8px 11px; }
.campfire-dock__transcript .campfire-message { gap: 8px; }
.campfire-dock__transcript .campfire-message__gutter { flex-basis: 30px; }
.campfire-dock__transcript .campfire-message__avatar { width: 30px; height: 30px; border-radius: 9px; font-size: .75rem; }
.campfire-dock__transcript .campfire-message__body { font-size: .84rem; }
.campfire-dock__transcript .campfire-empty { min-height: 145px; }
.campfire-dock .campfire-composer { padding: 9px 11px 11px; }
.campfire-dock .campfire-composer__hint { display: none; }
.campfire-dock__loading { padding: 28px; color: var(--text-muted); text-align: center; }
/* .campfire-report-row__buttons is the one survivor of the old card-layout
   report queue (replaced by the table-based partials/_moderation_queue_rows.html,
   which matches forum/messaging/profile-comment's own shape): a plain
   flex-wrap row for the Dismiss/Remove/Mute buttons, still used there. */
.campfire-report-row__buttons { display: flex; flex-wrap: wrap; gap: 6px; }
.campfire-page .site-footer { display: none; }
.campfire-manage-panel { max-width: 620px; }
.campfire-manage-panel form { display: grid; gap: 14px; }
.campfire-manage-panel .settings-value-row input[type='number'] { max-width: 90px; }
#campfire-settings-saved { margin-top: 12px; color: #94d4ab; font-size: .82rem; }
.campfire-history-filter {
    display: grid;
    gap: 8px;
    margin-bottom: 14px;
    padding: 14px 16px;
    border: 1px solid var(--border-subtle);
    border-radius: 12px;
    background: var(--bg-surface);
}
.campfire-history-filter label { color: var(--text-muted); font-size: .78rem; font-weight: 600; }
.campfire-history-filter__controls { display: flex; flex-wrap: wrap; gap: 8px; }
.campfire-history-filter__controls input { flex: 1 1 260px; min-width: 0; }
.campfire-history-list { overflow: hidden; border: 1px solid var(--border-subtle); border-radius: 14px; background: var(--bg-surface); }
.campfire-history__summary {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border-subtle);
    color: var(--text-muted);
    font-size: .76rem;
}
.campfire-history__rows { display: grid; }
.campfire-history-row {
    display: grid;
    grid-template-columns: 36px minmax(0, 1fr);
    gap: 11px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--border-subtle);
}
.campfire-history-row:last-child { border-bottom: 0; }
.campfire-history-row.is-removed { background: rgb(255 255 255 / 1.5%); }
.campfire-history-row.is-context { outline: 2px solid color-mix(in srgb, var(--campfire-accent) 62%, transparent); outline-offset: -2px; scroll-margin-top: 20px; }
.campfire-history-row__content { min-width: 0; }
.campfire-history-row__badge {
    padding: 2px 6px;
    border: 1px solid rgb(229 144 144 / 35%);
    border-radius: 999px;
    color: #e59090;
    font-size: .66rem;
    letter-spacing: .04em;
    text-transform: uppercase;
}
.campfire-history-row__reason { margin: 6px 0 0; color: var(--text-muted); font-size: .75rem; }
.campfire-history__pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 14px 16px;
    border-top: 1px solid var(--border-subtle);
    color: var(--text-muted);
    font-size: .78rem;
}
@keyframes campfire-message-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
@keyframes campfire-status-pulse { 50% { opacity: .55; } }

@media (width < 1024px) {
    /* The bottom tab bar replaces the sidebar below desktop, so reclaim its height. */
    .campfire-page .page-container {
        height: calc(100vh - var(--header-height) - var(--tabbar-height));
        height: calc(100dvh - var(--header-height) - var(--tabbar-height));
    }
    /* .mobile-tabbar itself switches on at this same `width < 1024px` breakpoint (not
       768px), so the dock's tabbar-aware lift has to match it exactly: it used to sit only
       inside the 768px breakpoint below, which left a ~769-1023px "tablet" band using the
       desktop bottom:20px rule. .mobile-tabbar is ~79px tall and the dock's z-index (9990)
       sits well above its 150, so at that width the trigger rendered on top of the tab bar
       instead of above it, and the floating panel's composer (anchored off the trigger's own
       position) was obscured behind the bar right along with it. */
    /* --tabbar-height excludes the tab bar's own safe-area padding by convention (see the
       var's definition above): a caller has to add env(safe-area-inset-bottom) itself, same
       as body.is-app does. This rule didn't, so on a real phone with a home-indicator inset
       the tab bar sits that much taller than tabbar-height alone accounts for, and the
       button's bottom offset undershot it: the button sank into/under the tab bar's own row
       instead of sitting in the clear strip above it. Not reproducible in a desktop emulator,
       which reports a 0 safe-area-inset. */
    .campfire-dock { right: 12px; bottom: calc(var(--tabbar-height, 79px) + env(safe-area-inset-bottom, 0px) + 12px); }
}
@media (max-width: 768px) {
    .campfire-bar { flex-wrap: wrap; gap: 6px 12px; padding: 10px 14px; }
    .campfire-bar__welcome { display: none; }
    .campfire-notice { margin: 8px 12px 0; padding: 7px 10px; font-size: .76rem; line-height: 1.35; }
    .campfire-notice__full { display: none; }
    .campfire-notice__short { display: inline; }
    .campfire-transcript { padding: 10px 8px 8px; }
    .campfire-dock__trigger-label { display: none; }
    .campfire-dock__trigger { width: 46px; height: 46px; justify-content: center; padding: 0; }
    .campfire-dock__panel { position: fixed; inset: 0; width: auto; max-height: none; border: 0; border-radius: 0; }
    /* height: 100% here would resolve against #campfire-dock-content, a plain wrapper
       <div> with no height of its own, so the percentage does nothing and this flex
       column shrinks to its content instead of filling the screen: the transcript then
       grows unbounded (no scroll, since the panel itself is overflow: hidden) and pushes
       the composer below the clipped bottom edge, off-screen. Viewport units don't have
       that problem, matching the desktop max-height rules just above. */
    .campfire-dock__content { height: 100vh; height: 100dvh; max-height: none; padding-bottom: calc(var(--tabbar-height, 79px) + env(safe-area-inset-bottom)); }
    .campfire-dock__transcript { flex: 1; min-height: 0; max-height: none; }
    .campfire-dock .campfire-composer { margin: 9px 12px 12px; }
    .campfire-history__summary { align-items: start; flex-direction: column; gap: 4px; }
    .campfire-history-filter__controls .btn { flex: 1 1 auto; }
}
@media (pointer: coarse) {
    .campfire-message__menu summary,
    .campfire-message__expand,
    .campfire-dock__close,
    .campfire-notice__close,
    .campfire-composer__toggle,
    .campfire-composer__send,
    .campfire-composer__fmt { min-width: 44px; min-height: 44px; }
    .campfire-message__menu { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .campfire-message { animation: none; }
    .campfire-live-dot.is-polling { animation: none; }
    .campfire-transcript { scroll-behavior: auto; }
}

