/* ============================================================
 * events.css — events end-to-end
 * ============================================================
 *
 * This file owns every events-touching surface in the app.
 *
 * Phases covered:
 *   - ev9            event roster
 *   - ev6            freespace Mode G (event reference)
 *   - ev10           visual refresh across edit / show / list templates
 *   - ev-calendar-view  calendar shell + month / week / day surfaces
 *   - ev11a          event comments
 *   - ev11b-1        event media (images + videos)
 *   - ev11b-2        post ↔ event linking chrome
 *   - ev11c          message blast
 *   - ev11d-1        bulk actions on drafts tab
 *
 * Reference: markdown/design/DESIGN_DECISIONS_CSS_REFACTOR.md
 * ============================================================ */

/* === event roster (ev9) ===
   Per-row roster on event detail page (avatar, name, response badge,
   host-only kick). Layout is mostly Bootstrap utilities (d-flex,
   gap-2, py-1, flex-grow-1). This section adds the small refinements
   utilities can't:

   - subtle border between adjacent rows for legibility as the roster
     grows beyond a couple of entries (first row has no top-border
     thanks to the adjacent-sibling selector)
   - medium weight on the display name so it reads as the primary
     identifier (default 400 reads identical to the muted handle
     minus color); handle keeps the .text-muted small utility
   - hover underline on the display name only — the wrapping link
     has text-decoration:none, but we still want hover affordance
*/

.event-roster-row + .event-roster-row {
    border-top: 1px solid var(--color-border-subtle);
}

.event-roster-display-name {
    font-weight: var(--font-weight-medium);
}

.event-roster-name:hover .event-roster-display-name {
    text-decoration: underline;
}

/* ============================================================
 * ev6 — freespace Mode G (event reference)
 * ============================================================
 *
 * Two rendering surfaces:
 *   1. editor surface — both account/free_space.html (settings)
 *      AND profile/_free_space_modal.html (profile modal). Same
 *      partial-driven markup ships on both via templates/events/
 *      _search_results.html.
 *      - .freespace-event-picker             outer container, no chrome
 *      - .freespace-event-search-results     results dropdown
 *      - .freespace-event-result-tile        per-result button (also
 *                                            reused for selected preview)
 *      - .freespace-event-result-{title,
 *          meta, handle, happened-badge}     inner spans
 *      - .freespace-event-selected-preview   wrapper around inert tile
 *
 *   2. profile view render (profile/view.html)
 *      - .freespace-content-event            wrapper around _event_card
 *      - .freespace-content-event.is-past    "happened" badge via ::after
 *      - .freespace-content-event-empty      owner-only CTA when the
 *                                            referenced event went away
 *      - .freespace-event-caption            optional caption above card
 *
 * All colors / borders / spacing are token-driven. Mirrors the
 * shape of the Mode E (post) styles in the picker-result tile
 * area, and the Mode F (music) styles for the empty-state.
 */

/* ---- Editor surface (settings page + profile modal) --------- */

/* Outer picker container — no chrome of its own. The parent fieldset
   (settings page) or freespace-subform (modal) already provides the
   sectioning frame. */
.freespace-event-picker {
    /* Reserved for future tweaks; layout currently lives on the
       child containers (.freespace-event-picker-search and
       .freespace-event-picker-selected). */
}

/* Results dropdown — scrollable list of result tiles. Mirrors
   .freespace-post-results' max-height + gap + padding. */
.freespace-event-search-results {
    max-height: 320px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    background: transparent;
    padding: 0.25rem;
    margin-top: var(--space-2);
}

/* Result tile — button per search hit. Mirrors .freespace-post-result
   -row shape with a 3-line content stack (title / meta / handle). */
.freespace-event-result-tile {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    width: 100%;
    padding: 0.75rem;
    text-align: left;
    color: var(--bs-body-color);
    background: var(--bs-tertiary-bg);
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    cursor: pointer;
    position: relative;
    transition: background-color 120ms ease, border-color 120ms ease;
}

.freespace-event-result-tile:hover,
.freespace-event-result-tile:focus-visible {
    background: var(--bs-secondary-bg);
    border-color: var(--bs-emphasis-color);
    outline: none;
}

/* Inert variant — used for the selected-preview tile. Same visual
   shape as a result tile but no cursor pointer, no hover state. */
.freespace-event-result-tile.is-selected-preview,
.freespace-event-result-tile:disabled {
    cursor: default;
    pointer-events: none;
}

.freespace-event-result-tile.is-selected-preview:hover,
.freespace-event-result-tile:disabled:hover {
    background: var(--bs-tertiary-bg);
    border-color: var(--bs-border-color);
}

.freespace-event-result-title {
    font-weight: 500;
    color: var(--bs-body-color);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.freespace-event-result-meta {
    color: var(--bs-secondary-color);
    font-size: 0.875rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.freespace-event-result-handle {
    color: var(--bs-secondary-color);
    font-size: 0.8125rem;
}

/* "happened" badge on past events in the result tile. Small pill
   pinned to the top-right corner of the tile so the user can spot
   past-vs-upcoming at a glance while scanning the list. */
.freespace-event-result-happened-badge {
    position: absolute;
    top: var(--space-2);
    right: var(--space-2);
    padding: 0.125rem 0.5rem;
    font-size: 0.6875rem;
    font-weight: 500;
    text-transform: lowercase;
    color: var(--bs-secondary-color);
    background: var(--bs-secondary-bg);
    border-radius: 999px;
}

/* Wrapper around the inert selected-preview tile. Just a layout slot;
   the tile itself carries the visual styling. */
.freespace-event-selected-preview {
    /* Reserved for future tweaks. */
}

/* ---- Profile view surface ----------------------------------- */

/* Wrapper around the _event_card.html include on Mode G render.
   position: relative so the .is-past ::after badge can pin to the
   top-right. The event card itself owns its inner padding + card
   chrome via Bootstrap's .card. */
.freespace-content-event {
    width: 100%;
    position: relative;
}

/* "happened" badge for past events on the profile view. Same visual
   language as the result-tile badge but rendered via ::after so the
   _event_card.html partial doesn't need to know about freespace
   semantics. Positioned over the card's top-right corner; the card's
   own padding keeps the title clear of the badge. */
.freespace-content-event.is-past::after {
    content: "happened";
    position: absolute;
    top: var(--space-2);
    right: var(--space-2);
    padding: 0.125rem 0.5rem;
    font-size: 0.6875rem;
    font-weight: 500;
    text-transform: lowercase;
    color: var(--bs-secondary-color);
    background: var(--bs-secondary-bg);
    border-radius: 999px;
    pointer-events: none;
    z-index: 1;
}

/* Owner-only state when the referenced event is no longer available
   (deleted / went private / blocked the featurer / became invisible).
   Visitors don't see this branch — the template skips rendering.
   Layout mirrors .freespace-content-post-empty + .freespace-content-
   music-empty. */
.freespace-content-event-empty {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
}

/* Caption above the event card. Mirrors .freespace-post-caption's
   typography so featured-event captions feel like featured-post
   captions: user-added context in a muted small line above the
   featured content. */
.freespace-event-caption {
    margin-bottom: var(--space-2);
}

/* === === === ev10 events visual refresh === === === */
/*
   Console-styled refresh of all four events templates: new.html,
   edit.html, show.html, list.html. Mirrors the fe-an1 admin
   announcements composer pattern (header + body + footer bands,
   segmented controls, flag chips) but built on native form controls
   + CSS :has() so no JS sync is required — the radios/checkboxes
   are the source of truth and labels carry the visual state.

   Scoping: every rule lives under .event-composer, .event-detail,
   or .event-list so nothing leaks into other surfaces. The
   existing .event-roster-* rules from ev9 get a visual refresh
   in place but keep their selectors so dashboard/feed embeds are
   unaffected.
*/

/* ---- Composer chrome (new.html / edit.html via _form.html) ---- */

.event-composer {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    margin-bottom: var(--space-4);
}

.event-composer-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-subtle);
    border-bottom: 1px solid var(--color-border);
}

.event-composer-header-title {
    font-family: var(--font-mono);
    font-size: var(--font-size-base);
    color: var(--color-text);
}

.event-composer-header-meta {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
}

.event-composer-header-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 0.125rem 0.5rem;
    font-size: var(--font-size-xs);
    text-transform: lowercase;
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
}

.event-composer-body {
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}

.event-composer-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-subtle);
    border-top: 1px solid var(--color-border);
}

.event-composer-footer-hint {
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
}

.event-composer-footer-actions {
    display: flex;
    gap: var(--space-2);
}

/* Stack the footer on narrow screens — keep the buttons reachable. */
@media (max-width: 480px) {
    .event-composer-footer {
        flex-direction: column;
        align-items: stretch;
    }
    .event-composer-footer-hint {
        text-align: center;
    }
    .event-composer-footer-actions {
        justify-content: flex-end;
    }
}

/* ---- Section dividers within composer body ---- */

.event-composer-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

.event-composer-section-label {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
    padding-bottom: var(--space-1);
    border-bottom: 1px solid var(--color-border-subtle);
}

/* ---- Field primitives ---- */

.event-field {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.event-field-label {
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
}

.event-field-help {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    margin: 0;
}

.event-field-help code {
    font-family: var(--font-mono);
    font-size: 0.95em;
    padding: 0.0625rem 0.25rem;
    background: var(--color-bg-subtle);
    border-radius: var(--radius-sm);
}

.event-field-error {
    font-size: var(--font-size-md);
    color: var(--color-danger);
}

.event-field-grid-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
}

@media (max-width: 540px) {
    .event-field-grid-2 {
        grid-template-columns: 1fr;
    }
}

.event-text-input,
.event-text-area,
.event-text-select {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    font-family: var(--font-sans);
    font-size: var(--font-size-body);
    color: var(--color-text);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.event-text-input:focus,
.event-text-area:focus,
.event-text-select:focus {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 25%, transparent);
}

.event-text-area {
    resize: vertical;
    min-height: 5rem;
}

.event-text-input-compact {
    max-width: 8rem;
}

/* ---- Date/time inputs — the literal ev10 fix ----
   Native <input type="datetime-local"> renders its calendar/clock
   picker indicator using the page's color-scheme. Without an
   explicit color-scheme, dark themes get the browser's default
   (light) icons against a dark background — invisible.

   `color-scheme: dark` flips the indicator to match the surface.
   The ::-webkit-calendar-picker-indicator filter is the belt for
   Chromium/Safari since color-scheme alone isn't always reliable
   on those engines. Firefox respects color-scheme natively. */
.event-datetime-input {
    color-scheme: dark light;
}

[data-theme="dark"] .event-datetime-input,
.event-datetime-input.is-dark {
    color-scheme: dark;
}

[data-theme="dark"] .event-datetime-input::-webkit-calendar-picker-indicator {
    filter: invert(0.85) brightness(1.1);
    opacity: 0.75;
    cursor: pointer;
}

[data-theme="dark"] .event-datetime-input::-webkit-calendar-picker-indicator:hover {
    opacity: 1;
}

/* ---- Segmented control (repeats + end-condition) ----
   Built on a hidden radio + labeled tile. :has() reads the radio's
   :checked state to drive the visual state — no JS, no aria-pressed
   bookkeeping. The radio remains the form's source of truth. */

.event-segmented {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    padding: var(--space-1);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    /* ev10: shrink to content inside a column flex .event-field.
       Without this, the parent's default align-items: stretch
       forces inline-flex to fill the cross axis, leaving a long
       blank tail after the last chip. */
    align-self: flex-start;
    max-width: 100%;
}

.event-segmented-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.375rem 0.875rem;
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: color var(--transition-fast), background var(--transition-fast);
    user-select: none;
}

.event-segmented-btn:hover {
    color: var(--color-text);
}

.event-segmented-btn input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    width: 0;
    height: 0;
}

.event-segmented-btn:has(input:checked) {
    color: var(--color-text-on-accent);
    background: var(--color-accent);
}

.event-segmented-btn:has(input:focus-visible) {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 30%, transparent);
}

/* ---- BYDAY chips (weekly) ----
   Same hidden-input + label pattern but using checkboxes (multi-
   select). Seven chips in a row, wrap on narrow viewports. */

.event-byday-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
}

.event-byday-chip {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.5rem;
    padding: 0.375rem 0.625rem;
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: all var(--transition-fast);
    user-select: none;
}

.event-byday-chip:hover {
    color: var(--color-text);
    border-color: color-mix(in srgb, var(--color-accent) 50%, var(--color-border));
}

.event-byday-chip input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    width: 0;
    height: 0;
}

.event-byday-chip:has(input:checked) {
    color: var(--color-text-on-accent);
    background: var(--color-accent);
    border-color: var(--color-accent);
}

.event-byday-chip:has(input:focus-visible) {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 30%, transparent);
}

/* ---- Audience tiles ----
   Stacked clickable tiles per Q2.A. Each tile wraps a hidden radio
   + visible label + muted subtext. :has() drives the selected
   state — same JS-free pattern as the segmented controls. */

.event-audience-tiles {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.event-audience-tile {
    position: relative;
    display: block;
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: all var(--transition-fast);
}

.event-audience-tile:hover {
    border-color: color-mix(in srgb, var(--color-accent) 40%, var(--color-border));
    background: color-mix(in srgb, var(--color-accent) 3%, var(--color-bg-surface));
}

.event-audience-tile input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    width: 0;
    height: 0;
}

.event-audience-tile:has(input:checked) {
    border-color: var(--color-accent);
    background: color-mix(in srgb, var(--color-accent) 6%, var(--color-bg-surface));
    box-shadow: 0 0 0 1px var(--color-accent);
}

.event-audience-tile:has(input:focus-visible) {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 25%, transparent);
}

.event-audience-tile-label {
    font-size: var(--font-size-body);
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
    margin: 0;
}

.event-audience-tile-desc {
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    margin-top: var(--space-1);
    margin-bottom: 0;
}

/* ---- Flag chips (is_all_day, rsvps_enabled) ----
   Mirrors .ann-flag-chip but scoped to events. Pressed = on. */

.event-flag-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

.event-flag-chip {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 0.375rem 0.75rem;
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: all var(--transition-fast);
    user-select: none;
}

.event-flag-chip:hover {
    color: var(--color-text);
    border-color: color-mix(in srgb, var(--color-accent) 40%, var(--color-border));
}

.event-flag-chip input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    width: 0;
    height: 0;
}

.event-flag-chip:has(input:checked) {
    color: var(--color-text-on-accent);
    background: var(--color-accent);
    border-color: var(--color-accent);
}

.event-flag-chip:has(input:focus-visible) {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 30%, transparent);
}

/* Optional check-mark glyph slot — emoji or icon goes inside
   .event-flag-chip-glyph; hidden when chip is unchecked. */
.event-flag-chip-glyph {
    font-size: 0.875em;
    opacity: 0;
    transition: opacity var(--transition-fast);
}

.event-flag-chip:has(input:checked) .event-flag-chip-glyph {
    opacity: 1;
}

/* ---- Composer footer buttons ---- */

.event-btn-publish {
    padding: 0.5rem 1.25rem;
    font-size: var(--font-size-body);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-on-accent);
    background: var(--color-accent);
    border: 1px solid var(--color-accent);
    border-radius: var(--radius-md);
    cursor: pointer;
    text-decoration: none;
    transition: background var(--transition-fast);
}

.event-btn-publish:hover {
    color: var(--color-text-on-accent);
    text-decoration: none;
    background: var(--color-accent-hover);
    border-color: var(--color-accent-hover);
}

.event-btn-publish:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 30%, transparent);
}

.event-btn-secondary {
    display: inline-flex;
    align-items: center;
    padding: 0.5rem 1rem;
    font-size: var(--font-size-body);
    color: var(--color-text);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    cursor: pointer;
    text-decoration: none;
    transition: all var(--transition-fast);
}

.event-btn-secondary:hover {
    color: var(--color-text);
    text-decoration: none;
    border-color: var(--color-text-muted);
}

.event-btn-secondary:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 25%, transparent);
}

/* ---- Mode-change warning + back-link inside composer chrome ---- */

.event-composer-warning {
    margin: 0 var(--space-4) var(--space-4);
    padding: var(--space-3) var(--space-4);
    background: color-mix(in srgb, var(--color-warning) 8%, var(--color-bg-surface));
    border: 1px solid color-mix(in srgb, var(--color-warning) 30%, var(--color-border));
    border-radius: var(--radius-md);
    color: var(--color-text);
}

.event-composer-warning code {
    font-family: var(--font-mono);
    padding: 0.0625rem 0.25rem;
    background: var(--color-bg-subtle);
    border-radius: var(--radius-sm);
}

.event-composer-back-link {
    display: inline-block;
    margin-bottom: var(--space-3);
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    text-decoration: none;
}

.event-composer-back-link:hover {
    color: var(--color-text);
}

/* ---- Invitee management section (edit page, light touch) ---- */

.event-invitee-section {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-4);
    margin-bottom: var(--space-4);
}

.event-invitee-section-label {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
    margin-bottom: var(--space-3);
}

/* Delete button sits below the composer; styled danger-secondary so
   it reads as a destructive action without screaming. */
.event-composer-delete {
    display: flex;
    justify-content: flex-end;
    margin-bottom: var(--space-4);
}

.event-btn-danger {
    padding: 0.375rem 0.875rem;
    font-size: var(--font-size-md);
    color: var(--color-danger);
    background: var(--color-bg-surface);
    border: 1px solid color-mix(in srgb, var(--color-danger) 50%, var(--color-border));
    border-radius: var(--radius-md);
    cursor: pointer;
    text-decoration: none;
    transition: all var(--transition-fast);
}

.event-btn-danger:hover {
    color: var(--color-text-on-accent);
    background: var(--color-danger);
    border-color: var(--color-danger);
}

.event-btn-danger:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-danger) 30%, transparent);
}

/* === === === ev10 · show.html — event detail === === === */

.event-detail {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    margin-bottom: var(--space-4);
}

/* Hero band — title on the left, pills below; actions on the right. */
.event-detail-hero {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-5) var(--space-4) var(--space-4);
    background: var(--color-bg-subtle);
    border-bottom: 1px solid var(--color-border);
}

.event-detail-hero-titlewrap {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    min-width: 0;
    flex-grow: 1;
}

.event-detail-hero-title {
    font-size: 1.5rem;
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
    margin: 0;
    word-break: break-word;
}

.event-detail-hero-pills {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
}

.event-detail-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 0.125rem 0.5rem;
    font-size: var(--font-size-xs);
    text-transform: lowercase;
    color: var(--color-text-muted);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
}

.event-detail-pill-draft {
    color: var(--color-warning);
    border-color: color-mix(in srgb, var(--color-warning) 50%, var(--color-border));
}

.event-detail-pill-audience {
    color: var(--color-text);
}

.event-detail-hero-actions {
    display: flex;
    gap: var(--space-2);
    flex-shrink: 0;
}

@media (max-width: 540px) {
    .event-detail-hero {
        flex-direction: column;
    }
    .event-detail-hero-actions {
        align-self: stretch;
    }
}

.event-detail-body {
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.event-detail-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border-subtle);
}

.event-detail-section:first-child {
    padding-top: 0;
    border-top: none;
}

.event-detail-section-label {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
}

.event-detail-when,
.event-detail-where {
    font-size: var(--font-size-body);
    color: var(--color-text);
}

.event-detail-when-recurrence {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    margin-top: var(--space-1);
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
}

.event-detail-description {
    font-size: var(--font-size-body);
    color: var(--color-text);
    white-space: pre-wrap;
    line-height: 1.5;
}

/* RSVP affordance — buttons + revoke. */
.event-detail-rsvp-prompt {
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
}

.event-detail-rsvp-buttons {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}

.event-detail-rsvp-btn {
    padding: 0.375rem 0.875rem;
    font-size: var(--font-size-md);
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border);
    background: var(--color-bg-surface);
    color: var(--color-text-muted);
    cursor: pointer;
    transition: all var(--transition-fast);
}

.event-detail-rsvp-btn:hover {
    color: var(--color-text);
}

.event-detail-rsvp-btn.is-going {
    color: var(--color-text-on-accent);
    background: var(--color-success);
    border-color: var(--color-success);
}

.event-detail-rsvp-btn.is-maybe {
    color: var(--color-text);
    background: var(--color-warning);
    border-color: var(--color-warning);
}

.event-detail-rsvp-btn.is-not-going {
    color: var(--color-text);
    background: var(--color-bg-subtle);
    border-color: var(--color-text-muted);
}

.event-detail-rsvp-revoke {
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    text-decoration: underline;
}

.event-detail-rsvp-revoke:hover {
    color: var(--color-text);
}

.event-detail-locked {
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    font-style: italic;
}

.event-detail-pending {
    font-size: var(--font-size-md);
}

.event-detail-pending a {
    color: var(--color-accent);
    text-decoration: none;
}

.event-detail-pending a:hover {
    text-decoration: underline;
}

.event-detail-host-actions {
    display: flex;
    gap: var(--space-2);
}

/* ev11c-fu (blast-history) — subtle inline chip below the host-actions
   button row. Tiny muted link; lays out on its own line so it doesn't
   crowd the row of action buttons above. */
.event-blast-history-chip {
    display: inline-block;
    margin-top: var(--space-1);
    font-size: 0.8125rem;
    color: var(--color-text-muted);
    text-decoration: none;
}

.event-blast-history-chip:hover,
.event-blast-history-chip:focus-visible {
    color: var(--color-text);
    text-decoration: underline;
}

/* ---- Roster row refresh (in-place on existing classes from ev9) ---- */

.event-roster {
    margin: 0;
    padding: 0;
}

.event-roster-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--color-border-subtle);
}

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

.event-roster-name {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    flex-grow: 1;
    min-width: 0;
    color: var(--color-text);
    text-decoration: none;
}

.event-roster-display-name {
    font-weight: var(--font-weight-medium);
}

.event-roster-handle {
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
}

.event-roster-response {
    display: inline-flex;
    align-items: center;
    padding: 0.125rem 0.5rem;
    font-size: var(--font-size-xs);
    text-transform: lowercase;
    border-radius: var(--radius-pill);
}

.event-roster-response.is-going {
    color: var(--color-text-on-accent);
    background: var(--color-success);
}

.event-roster-response.is-maybe {
    color: var(--color-text);
    background: var(--color-warning);
}

.event-roster-response.is-not-going {
    color: var(--color-text-muted);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
}

.event-roster-host-badge {
    display: inline-flex;
    padding: 0.125rem 0.5rem;
    font-size: var(--font-size-xs);
    text-transform: lowercase;
    color: var(--color-info);
    background: color-mix(in srgb, var(--color-info) 12%, transparent);
    border-radius: var(--radius-pill);
}

.event-roster-kick {
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
}

.event-roster-kick:hover {
    color: var(--color-danger);
    text-decoration: underline;
}

/* === === === ev10 · list.html — events list === === === */

.event-list-page {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

.event-list-status {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.event-list-status-left {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    min-width: 0;
    flex-wrap: wrap;
}

.event-list-status-prompt {
    font-family: var(--font-mono);
    font-size: var(--font-size-base);
    color: var(--color-text);
}

.event-list-status-counts {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
}

.event-list-status-count-pill {
    display: inline-flex;
    align-items: baseline;
    gap: 0.25em;
    padding: 0.0625rem 0.5rem;
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
}

.event-list-status-count-pill strong {
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
}

/* Segmented tabs — share the .event-segmented chrome from the
   composer; small visual difference for the tab context. */
.event-list-tabs {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    padding: var(--space-1);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.event-list-tab {
    padding: 0.375rem 0.875rem;
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    background: transparent;
    border-radius: var(--radius-sm);
    text-decoration: none;
    transition: color var(--transition-fast), background var(--transition-fast);
}

.event-list-tab:hover {
    color: var(--color-text);
}

.event-list-tab.is-active {
    color: var(--color-text-on-accent);
    background: var(--color-accent);
}

.event-list-tab:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent) 30%, transparent);
}

.event-list-empty {
    padding: var(--space-5);
    text-align: center;
    color: var(--color-text-muted);
    font-size: var(--font-size-md);
    background: var(--color-bg-surface);
    border: 1px dashed var(--color-border);
    border-radius: var(--radius-md);
}

.event-list-empty a {
    color: var(--color-accent);
    text-decoration: none;
}

.event-list-empty a:hover {
    text-decoration: underline;
}

.event-list-rows {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* Halo'd inbox-style row — matches the fe-an1 admin announcements
   list aesthetic. Whole row is a click target.

   ev11d-2-pr3-fu layout rework — two-column grid where col 1 is the
   optional draft checkbox (auto-sized, vertically centered) and col 2
   is a flex column containing all the row's content. Non-draft tabs
   render without a checkbox, so the grid collapses to a single column
   (auto / 1fr is fine — auto with no content takes no width). Inside
   the body, content stacks vertically: title, when, location, rsvp,
   then a bottom meta row with pills + the draft cta. Each text line
   truncates at one line via ellipsis so the chrome stays at most
   ~3 lines of stacked text above the pills row — long event titles
   and addresses don't blow out the card height. */
.event-list-row {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-3);
    align-items: stretch;
    padding: var(--space-3) var(--space-4);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: var(--color-text);
    transition: all var(--transition-fast);
}

.event-list-row:hover {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--color-accent) 50%, var(--color-border));
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 20%, transparent),
                var(--shadow-sm);
}

.event-list-row-check {
    align-self: center;
}

/* Body — vertical flex column holding everything to the right of the
   checkbox. min-width: 0 lets ellipsis kick in on its children
   (without it, flex children default to min-content and refuse to
   shrink past their content width). */
.event-list-row-body {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    min-width: 0;
}

/* Title / when / location each cap at one line. Whoever overflows
   gets ellipsized at the right edge of the body column. The body
   column is the available width minus the checkbox, so each line
   uses the full card width. */
.event-list-row-title {
    font-size: var(--font-size-body);
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.event-list-row-title:hover {
    color: var(--color-accent);
    text-decoration: none;
}

.event-list-row-when {
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.event-list-row-location {
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.event-list-row-rsvp {
    /* The shared _rsvp_pill macro renders Bootstrap btn-sm buttons;
       constrain the row so they don't bloat the layout. Self-empty
       for drafts and past events (macro returns nothing). */
    margin-top: var(--space-1);
}

/* Meta row — bottom slot for pills + draft cta. Horizontal flex with
   space-between so pills cluster on the left and the cta sits on the
   right edge of the card. Wraps to a second line if both sides
   together don't fit (small-screen safety). */
.event-list-row-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    margin-top: var(--space-2);
}

.event-list-row-pills {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-1);
}

.event-list-row-pill {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: 0.125rem 0.5rem;
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    text-transform: lowercase;
}

.event-list-row-pill-recurring {
    color: var(--color-text);
}

@media (max-width: 540px) {
    .event-list-status {
        flex-direction: column;
        align-items: stretch;
        gap: var(--space-2);
    }
}

/* Draft row variant — muted subdued chrome with a "continue working"
   affordance. */
.event-list-row[data-draft="true"] {
    border-style: dashed;
}

.event-list-row[data-draft="true"] .event-list-row-title {
    color: var(--color-text-muted);
}

.event-list-row-draft-cta {
    padding: 0.25rem 0.625rem;
    font-size: var(--font-size-md);
    color: var(--color-text);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    text-decoration: none;
    transition: all var(--transition-fast);
    /* Keep "keep working" on one line so the bottom row never breaks
       awkwardly. The meta row's flex-wrap absorbs overflow by
       wrapping the cta below the pills on tight widths. */
    flex-shrink: 0;
    white-space: nowrap;
}

.event-list-row-draft-cta:hover {
    border-color: var(--color-text-muted);
    color: var(--color-text);
}


/* ============================================================
   ev-calendar-view — calendar surface (month / week / day)
   ============================================================
   Shared shell (.cal-shell) wraps both events list and calendar
   views so they read as one app. Calendar-specific chrome below:
   rail, status bar, toolbar (period pills + nav), monthly grid,
   weekly hour-grid + mobile-stacked fallback, daily agenda.

   Theme-adaptive tints: every accent-tinted background uses
   color-mix(in srgb, var(--color-accent) N%, transparent) so it
   tracks the existing :root / [data-theme="dark"] accent values
   automatically. No new color tokens introduced.

   Cell + event chip backgrounds use --color-bg-subtle (which has
   light/dark variants in the token block already) layered with
   the page background for subtle elevation.

   Weekly event positioning: --cal-hour-height is the px height of
   each hour row (44px default), scoped to .cal-week-desktop. Each
   .cal-week-event sets --ev-top-min and --ev-duration-min as
   inline-style variables; calc() converts them to top/height px.

   Mobile (max-width: 768px): rail collapses to top-of-page
   segmented control, weekly desktop hour-grid is hidden, weekly
   stacked agenda is shown, monthly cells shrink, toolbar wraps.
   ============================================================ */


/* ---- Shell: rail + main grid -------------------------------- */

.cal-shell {
    display: grid;
    grid-template-columns: 180px 1fr 0;
    gap: var(--space-5);
    align-items: start;
    margin: var(--space-5) auto;
    padding: 0 var(--space-4);
    /* max-width is set per data-view below so list and calendar can
       feel different widths — list reads as a tight column (matches
       the pre-ev-calendar-view .content-narrow feel), calendar fills
       the wider container (matches .account-console).

       Grid is always 3 columns: rail, main, pane. The pane track
       is 0px when closed; the [data-pane-open="true"] selector
       expands it to 360px. Keeping the track count fixed makes the
       grid-template-columns transition smooth (cleaner than
       interpolating between 2-col and 3-col grids).

       Both max-width and grid-template-columns animate so view
       switches (list ↔ calendar) scale the shell, and pane open/close
       slides the pane in/out. */
    transition:
        max-width 250ms ease,
        grid-template-columns 250ms ease;
}

.cal-shell[data-view="list"] {
    /* rail (180) + gap (24) + content (≈600px, the old .content-narrow
       feel) ≈ 804px. Rounded to 820 for a small breathing margin.
       Pane is never open on list view — third column stays at 0. */
    max-width: 820px;
}

.cal-shell[data-view="calendar"] {
    /* Matches .account-console — wide enough for the 7-col monthly
       grid + the event side-pane when open. */
    max-width: 1400px;
}

.cal-shell[data-view="calendar"][data-pane-open="true"] {
    /* Pane open — third column expands. Calendar (middle 1fr) shrinks
       by 360 + gap = 384px to make room. At 1400px shell:
       1196px calendar → 836px calendar. 7 cols at ≈115px each, still
       very legible. */
    grid-template-columns: 180px 1fr 360px;
}

.cal-shell-main {
    /* Right column. Min-width: 0 prevents overflow when long event
       titles try to push the grid wider than its column width. */
    min-width: 0;
}


/* ---- Rail --------------------------------------------------- */

.cal-rail {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-3);
    position: sticky;
    top: var(--space-4);
}

.cal-rail-header {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--color-text-muted);
    padding: 0 var(--space-2) var(--space-2);
}

.cal-rail-item {
    display: block;
    padding: 10px 14px;
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: var(--font-size-base);
    border-radius: var(--radius-sm);
    margin-bottom: 2px;
    font-weight: var(--font-weight-medium);
    transition: all var(--transition-fast);
}

.cal-rail-item:hover {
    color: var(--color-text);
    background: var(--color-bg-subtle);
}

/* Active state is CSS-driven from the parent shell's data-view
   attribute. When events_calendar.js swaps data-view during a
   client-side view switch, the rail item updates without any JS
   class toggle. */
.cal-shell[data-view="list"] .cal-rail-item[data-rail-view="list"],
.cal-shell[data-view="calendar"] .cal-rail-item[data-rail-view="calendar"] {
    color: var(--color-text-on-accent);
    background: var(--color-accent);
}


/* ---- Side pane ---------------------------------------------- */

/* The pane element sits in the third grid column. The column itself
   is 0px wide by default and expands to 360px via the
   [data-pane-open="true"] selector on .cal-shell. min-width:0 lets
   the grid item shrink below its content's intrinsic width;
   overflow:hidden clips the 360px-wide inner content while the
   column is collapsed. */
.cal-pane {
    min-width: 0;
    overflow: hidden;
    border-radius: var(--radius-lg);
    position: sticky;
    top: var(--space-5);
    max-height: calc(100vh - var(--space-5) * 2);
    overflow-y: auto;
}

/* Surface chrome (background + border) only renders when the pane
   is actually open. At 0-width (closed), a 1px border would still
   render outside the 0-width content box as a thin vertical line;
   gating it on [data-pane-open="true"] keeps the closed state
   completely invisible. */
.cal-shell[data-pane-open="true"] .cal-pane {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
}

/* Inner wrapper has fixed width so the content layout doesn't squish
   during the grid-template-columns transition — instead it gets
   revealed/clipped by the parent's overflow:hidden. */
.cal-pane-inner {
    width: 360px;
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* Empty pane (initial state, no event selected) is invisible without
   needing display:none — the grid track is 0px wide (rail | main | 0)
   and overflow:hidden clips the 360px inner content. Critically, we
   do NOT use :empty { display: none } here, because that would make
   paneIsAvailable() in events_calendar.js return false (it checks
   computed display !== 'none'), which would short-circuit the click
   intercept and the pane could never open. */

/* Hide the pane entirely on list view — the data-pane-open state
   can theoretically persist across view swaps, but the pane is a
   calendar-only affordance and shouldn't bleed into list. */
.cal-shell[data-view="list"] .cal-pane {
    display: none;
}

/* Header: linked title + close button */
.cal-pane-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--space-3);
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--color-border);
}

.cal-pane-title {
    flex: 1;
    font-size: var(--font-size-lg);
    font-weight: 600;
    color: var(--color-text);
    text-decoration: none;
    line-height: 1.3;
    word-break: break-word;
}

.cal-pane-title:hover {
    color: var(--color-accent);
    text-decoration: underline;
}

.cal-pane-close {
    flex-shrink: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: var(--space-1);
    color: var(--color-text-muted);
    cursor: pointer;
    line-height: 1;
    transition: background 120ms ease, color 120ms ease;
}

.cal-pane-close:hover {
    background: var(--color-bg-subtle);
    color: var(--color-text);
}

/* Labeled sections (when / where / details) */
.cal-pane-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.cal-pane-section-label {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
}

.cal-pane-section-body {
    font-size: var(--font-size-sm);
    color: var(--color-text);
    word-break: break-word;
}

.cal-pane-section-aux {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    margin-left: var(--space-2);
}

.cal-pane-description {
    white-space: pre-wrap;
    line-height: 1.5;
}

/* Pills row — audience + recurrence */
.cal-pane-pills {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
}

.cal-pane-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px var(--space-2);
    border-radius: var(--radius-pill);
    background: var(--color-bg-subtle);
    color: var(--color-text-muted);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
}

.cal-pane-pill-recurring {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    color: var(--color-accent);
}

/* RSVP region — macro's own wrappers handle their own spacing,
   this is just a container for layout flow. */
.cal-pane-rsvp {
    /* macro renders nothing for past/draft, so empty pane-rsvp
       leaves no visual hole — the gap on .cal-pane-inner collapses
       since there's no rendered child. */
}

/* Footer with "open full page" link */
.cal-pane-footer {
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-border);
}

.cal-pane-open-full {
    font-family: var(--font-mono);
    font-size: var(--font-size-sm);
    color: var(--color-accent);
    text-decoration: none;
}

.cal-pane-open-full:hover {
    text-decoration: underline;
}

/* ---- Main panel + status bar -------------------------------- */

.cal-main {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-4);
}

.cal-status-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-2) var(--space-4);
    border-bottom: 1px solid var(--color-border);
    margin-bottom: var(--space-4);
}

.cal-status-prompt {
    font-family: var(--font-mono);
    font-size: var(--font-size-base);
    color: var(--color-text-muted);
}

.cal-status-prompt-accent {
    color: var(--color-accent);
}

.cal-status-prompt-path {
    color: var(--color-text);
}


/* ---- Toolbar: period pills + nav ---------------------------- */

.cal-content {
    /* JS swap target. Inline content has its own padding rules
       per partial; .cal-content itself is just a hook for the
       fragment fetch → innerHTML swap. */
}

.cal-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: var(--space-4);
    gap: var(--space-3);
    flex-wrap: wrap;
}

.cal-segmented {
    display: inline-flex;
    gap: 4px;
    padding: 4px;
    background: var(--color-bg-subtle);
    border-radius: var(--radius-sm);
}

.cal-segmented-btn {
    background: transparent;
    border: none;
    color: var(--color-text-muted);
    padding: 6px 14px;
    font-family: var(--font-mono);
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-medium);
    border-radius: 6px;
    cursor: pointer;
    text-decoration: none;
    transition: all var(--transition-fast);
}

.cal-segmented-btn:hover {
    color: var(--color-text);
}

.cal-segmented-btn.is-active {
    background: var(--color-accent);
    color: var(--color-text-on-accent);
}

.cal-nav {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.cal-nav-btn {
    background: var(--color-bg-subtle);
    border: none;
    color: var(--color-text-muted);
    width: 32px;
    height: 32px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-mono);
    font-size: var(--font-size-lg);
    text-decoration: none;
    transition: all var(--transition-fast);
}

.cal-nav-btn:hover {
    color: var(--color-text);
    background: color-mix(in srgb, var(--color-text) 8%, transparent);
}

.cal-nav-today {
    background: var(--color-bg-subtle);
    border: none;
    color: var(--color-text-muted);
    height: 32px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-medium);
    margin-left: var(--space-1);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    transition: color var(--transition-fast);
}

.cal-nav-today:hover {
    color: var(--color-text);
}

.cal-nav-label {
    font-family: var(--font-mono);
    font-size: var(--font-size-base);
    color: var(--color-text);
    margin-left: var(--space-2);
    letter-spacing: 0.02em;
    font-variant-numeric: tabular-nums;
}


/* ---- Monthly grid ------------------------------------------- */

.cal-month-header {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 6px;
    margin-bottom: var(--space-2);
    padding: 0 4px;
}

.cal-month-header-cell {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--color-text-muted);
    font-weight: var(--font-weight-medium);
    padding: 6px 8px;
}

.cal-month {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 6px;
}

.cal-month-cell {
    background: var(--color-bg-subtle);
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    padding: 10px;
    min-height: 110px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    transition: background var(--transition-fast);
    min-width: 0;
}

.cal-month-cell:hover {
    background: color-mix(in srgb, var(--color-text) 4%, var(--color-bg-subtle));
}

.cal-month-cell.is-out-of-month {
    background: transparent;
    border: 1px dashed var(--color-border);
}

.cal-month-cell.is-out-of-month .cal-month-cell-date {
    color: var(--color-text-muted);
    opacity: 0.55;
}

.cal-month-cell.is-out-of-month .cal-chip {
    opacity: 0.55;
}

.cal-month-cell.is-today {
    background: color-mix(in srgb, var(--color-accent) 8%, transparent);
    border-color: color-mix(in srgb, var(--color-accent) 22%, transparent);
}

.cal-month-cell-date {
    font-family: var(--font-mono);
    font-size: var(--font-size-base);
    color: var(--color-text);
    text-align: right;
    margin-bottom: 4px;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.cal-month-cell.is-today .cal-month-cell-date {
    color: var(--color-text-on-accent);
    background: var(--color-accent);
    width: 24px;
    height: 24px;
    border-radius: 50%;
    margin-left: auto;
    margin-bottom: 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: var(--font-weight-semibold);
    font-size: var(--font-size-md);
}


/* ---- Event chip (monthly cells + weekly stacked) ------------ */

.cal-chip {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 3px 6px 3px 4px;
    border-radius: 4px;
    background: color-mix(in srgb, var(--color-text) 4%, transparent);
    text-decoration: none;
    color: var(--color-text);
    font-size: var(--font-size-sm);
    line-height: 1.3;
    border-left: 2px solid var(--color-accent);
    transition: background var(--transition-fast);
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    min-width: 0;
}

.cal-chip:hover {
    background: color-mix(in srgb, var(--color-accent) 15%, transparent);
}

.cal-chip-time {
    font-family: var(--font-mono);
    color: var(--color-text-muted);
    font-size: var(--font-size-xs);
    flex-shrink: 0;
}

.cal-chip-title {
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--color-text);
    min-width: 0;
}

.cal-chip-more {
    color: var(--color-accent);
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    text-decoration: none;
    padding: 2px 6px;
    margin-top: 2px;
}

.cal-chip-more:hover {
    text-decoration: underline;
}


/* ---- Weekly hour-grid (desktop) ----------------------------- */

.cal-week-desktop {
    --cal-hour-height: 44px;
    display: grid;
    grid-template-columns: 56px repeat(7, minmax(0, 1fr));
    max-height: 70vh;
    overflow-y: auto;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-bg-subtle);
}

.cal-week-day-headers {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: 56px repeat(7, minmax(0, 1fr));
    background: var(--color-bg-surface);
    border-bottom: 1px solid var(--color-border);
    position: sticky;
    top: 0;
    z-index: 2;
}

.cal-week-day-header {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    font-weight: var(--font-weight-medium);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 10px 12px;
    text-align: center;
    border-right: 1px solid var(--color-border-subtle);
}

.cal-week-day-header:last-child {
    border-right: none;
}

.cal-week-day-header.is-today {
    color: var(--color-accent);
}

.cal-week-day-header-spacer {
    /* Top-left corner above the hour gutter — intentionally blank. */
}

.cal-week-day-header-name {
    display: inline;
}

.cal-week-day-header-num {
    display: block;
    font-family: var(--font-mono);
    font-size: var(--font-size-lg);
    color: var(--color-text);
    margin-top: 2px;
    font-weight: var(--font-weight-semibold);
    text-transform: none;
    font-variant-numeric: tabular-nums;
}

.cal-week-day-header.is-today .cal-week-day-header-num {
    color: var(--color-accent);
}

.cal-week-allday-strip {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: 56px repeat(7, minmax(0, 1fr));
    background: var(--color-bg-surface);
    border-bottom: 1px solid var(--color-border);
    min-height: 36px;
    position: sticky;
    top: 60px;
    z-index: 1;
}

.cal-week-allday-label {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 10px;
    font-weight: var(--font-weight-medium);
    border-right: 1px solid var(--color-border-subtle);
}

.cal-week-allday-cell {
    padding: 4px 6px;
    border-right: 1px solid var(--color-border-subtle);
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.cal-week-allday-cell:last-child {
    border-right: none;
}

.cal-week-allday-cell.is-today {
    background: color-mix(in srgb, var(--color-accent) 6%, transparent);
}

.cal-week-hour-row {
    /* display: contents lets the row's children participate directly
       in the parent .cal-week-desktop grid, keeping label + 7 cells
       on the same row without a real flex/grid container. */
    display: contents;
}

.cal-week-hour-label {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    padding: 4px 10px;
    border-bottom: 1px solid var(--color-border-subtle);
    text-align: right;
    min-height: var(--cal-hour-height);
    background: var(--color-bg-subtle);
    font-variant-numeric: tabular-nums;
}

.cal-week-hour-cell {
    border-left: 1px solid var(--color-border-subtle);
    border-bottom: 1px solid var(--color-border-subtle);
    position: relative;
    min-height: var(--cal-hour-height);
    background: var(--color-bg-subtle);
    overflow: visible;
}

.cal-week-hour-cell.is-today {
    background: color-mix(in srgb, var(--color-accent) 5%, var(--color-bg-subtle));
}

.cal-week-event {
    /* Position derived from --ev-top-min and --ev-duration-min set
       inline on this element by the template. calc converts the
       minute values to px based on --cal-hour-height. */
    position: absolute;
    left: 2px;
    right: 2px;
    top: calc(var(--ev-top-min, 0) * var(--cal-hour-height) / 60);
    height: calc(var(--ev-duration-min, 60) * var(--cal-hour-height) / 60);
    background: color-mix(in srgb, var(--color-accent) 18%, transparent);
    border-left: 2px solid var(--color-accent);
    color: var(--color-text);
    padding: 3px 6px;
    border-radius: 4px;
    font-size: var(--font-size-xs);
    overflow: hidden;
    cursor: pointer;
    text-decoration: none;
    line-height: 1.25;
    z-index: 1;
    transition: background var(--transition-fast);
}

.cal-week-event:hover {
    background: color-mix(in srgb, var(--color-accent) 28%, transparent);
}

.cal-week-event-time {
    display: block;
    font-family: var(--font-mono);
    font-size: 9px;
    color: var(--color-text-muted);
}

.cal-week-event-title {
    display: block;
    font-weight: var(--font-weight-medium);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}


/* ---- Weekly stacked agenda (mobile) ------------------------- */

.cal-week-stacked {
    display: none;
    flex-direction: column;
    gap: var(--space-2);
}

.cal-week-stacked-day {
    background: var(--color-bg-subtle);
    border-radius: var(--radius-md);
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.cal-week-stacked-day.is-today {
    background: color-mix(in srgb, var(--color-accent) 8%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-accent) 22%, transparent);
}

.cal-week-stacked-day-header {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--color-border-subtle);
}

.cal-week-stacked-day-name {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-weight: var(--font-weight-medium);
}

.cal-week-stacked-day.is-today .cal-week-stacked-day-name,
.cal-week-stacked-day.is-today .cal-week-stacked-day-num {
    color: var(--color-accent);
}

.cal-week-stacked-day-num {
    font-family: var(--font-mono);
    font-size: var(--font-size-base);
    color: var(--color-text);
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.cal-week-stacked-day-events {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.cal-week-stacked-day-empty {
    color: var(--color-text-muted);
    font-family: var(--font-mono);
    font-size: var(--font-size-sm);
    text-align: center;
    padding: 4px 0;
    opacity: 0.5;
}


/* ---- Daily agenda ------------------------------------------- */

.cal-day {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

.cal-day-section-label {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--color-text-muted);
    font-weight: var(--font-weight-medium);
    padding: var(--space-2) 0;
}

.cal-day-row {
    display: grid;
    grid-template-columns: 160px 1fr auto;
    align-items: center;
    gap: var(--space-3);
    padding: 14px 16px;
    border-radius: var(--radius-md);
    text-decoration: none;
    color: var(--color-text);
    background: var(--color-bg-subtle);
    border-left: 2px solid var(--color-accent);
    margin-bottom: 6px;
    transition: background var(--transition-fast);
    min-width: 0;
}

.cal-day-row:hover {
    background: color-mix(in srgb, var(--color-text) 4%, var(--color-bg-subtle));
}

.cal-day-row-time {
    font-family: var(--font-mono);
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    font-variant-numeric: tabular-nums;
}

.cal-day-row-title {
    font-size: var(--font-size-base);
    color: var(--color-text);
    font-weight: var(--font-weight-medium);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.cal-day-row-meta {
    font-family: var(--font-mono);
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
    opacity: 0.7;
}

.cal-day-empty {
    color: var(--color-text-muted);
    font-family: var(--font-mono);
    font-size: var(--font-size-sm);
    padding: 8px 14px;
    opacity: 0.6;
}


/* ---- Responsive: mobile (≤768px) ---------------------------- */

@media (max-width: 768px) {

    .cal-shell {
        grid-template-columns: 1fr;
        gap: var(--space-3);
        margin: var(--space-3) auto;
        padding: 0 var(--space-3);
    }

    /* The side pane is a desktop-only affordance — mobile users
       click event chips and get the full event detail page via the
       normal href fallback (events_calendar.js checks pane
       visibility before intercepting). */
    .cal-pane {
        display: none;
    }

    /* Rail collapses to a top segmented control above the toolbar.
       Same DOM — just restyled to read as pills rather than a
       sidebar. Keeps a single source of truth for the rail items. */
    .cal-rail {
        position: static;
        padding: 4px;
        display: flex;
        gap: 4px;
        background: var(--color-bg-subtle);
        border: none;
        border-radius: var(--radius-sm);
    }

    .cal-rail-header {
        display: none;
    }

    .cal-rail-item {
        flex: 1;
        margin-bottom: 0;
        padding: 6px 14px;
        text-align: center;
        font-family: var(--font-mono);
        font-size: var(--font-size-md);
        border-radius: 6px;
    }

    /* Tighter main panel padding on mobile. */
    .cal-main {
        padding: var(--space-3);
    }

    .cal-status-bar {
        padding: var(--space-1) var(--space-1) var(--space-3);
        margin-bottom: var(--space-3);
        gap: var(--space-2);
    }

    .cal-toolbar {
        gap: var(--space-2);
    }

    /* Monthly cells shrink hard — chips truncate aggressively. */
    .cal-month-header {
        gap: 3px;
    }

    .cal-month-header-cell {
        padding: 4px;
        font-size: 9px;
    }

    .cal-month {
        gap: 3px;
    }

    .cal-month-cell {
        min-height: 64px;
        padding: 4px;
        gap: 2px;
    }

    .cal-month-cell-date {
        font-size: var(--font-size-sm);
    }

    .cal-month-cell.is-today .cal-month-cell-date {
        width: 20px;
        height: 20px;
        font-size: var(--font-size-xs);
    }

    .cal-chip {
        padding: 2px 4px 2px 3px;
        font-size: 10px;
    }

    .cal-chip-time {
        font-size: 9px;
    }

    /* Swap weekly layouts: hide desktop hour-grid, show stacked. */
    .cal-week-desktop {
        display: none;
    }

    .cal-week-stacked {
        display: flex;
    }

    /* Daily row stacks to two-row grid on narrow screens. */
    .cal-day-row {
        grid-template-columns: 1fr;
        gap: 4px;
        padding: 12px 14px;
    }

    .cal-day-row-meta {
        font-size: 10px;
    }

}


/* ====================================================================
 * ev11a — Event comments
 * ====================================================================
 *
 * Light additions on top of Bootstrap card defaults for the comments
 * section at the bottom of events/show.html. The partial uses the
 * standard Bootstrap card for layout; these rules add token-based
 * color / spacing so the section sits visually with the rest of the
 * event-detail-* aesthetic.
 */

.event-detail-comments .event-comments-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}

.event-detail-comments .event-comments-empty {
    font-family: var(--font-mono);
    color: var(--color-text-muted);
}

.event-detail-comments .event-comments-form {
    margin-top: var(--space-3);
}

/* Per-comment card. Override Bootstrap's default white background
   with the subtle token so comments sit with the broader event-
   detail-section style. */
.event-comment {
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.event-comment-body {
    color: var(--color-text);
    word-break: break-word;
    white-space: pre-wrap;
    line-height: 1.5;
}

/* Inline edit collapse — subtle dashed separator above so the
   nested state reads as a panel rather than free-floating form. */
.event-comment-edit {
    padding-top: var(--space-2);
    border-top: 1px dashed var(--color-border-subtle);
}

/* ====================================================================
 * ev11b-1 — Event media (images + videos)
 * ====================================================================
 *
 * Carousel + picker styling for media attached to events. Most chrome
 * is inherited from the post-side rules — deliberately, so the visual
 * language stays consistent across content types:
 *   - .media-carousel  (~line 2375): aspect 4/3, max-height 600px,
 *     subtle bg, pagination + nav button styling.
 *   - .media-carousel .swiper-slide img.post-image (~line 2396): fills
 *     slide with object-fit:contain (letterbox preserved aspect).
 *   - .remove-active-media-btn (~line 2541): floating × button on the
 *     edit carousel.
 *   - .post-image (~line 1027): max-width:100% baseline for standalone
 *     images outside a carousel.
 *
 * What's new in this block:
 *   - .event-media-single: wrapper for the 1-media case (no carousel).
 *   - .event-media-video: <video> element styling + carousel-slide fill.
 *   - .event-media-add-btn: file-picker label-button with the canonical
 *     three-layer violet halo on hover. Matches the .has-halo (~line
 *     396) and .notification-row:hover (~line 4186) pattern so the
 *     picker reads as the same kind of tappable surface used elsewhere.
 *
 * Image+video branching is template-side (Jinja conditionals on
 * Media.media_type in _event_media.html / _event_media_edit.html);
 * CSS just gives both element types the right visual treatment.
 *
 * Followup ev11b-1-followup-video-preview: media_preview.js skips
 * non-image file types when rendering new-pick preview slides, so
 * newly-picked videos upload but show no preview in the form. When
 * that's lifted, the JS-injected preview slide will use this same
 * .event-media-video element + classes for free.
 * ==================================================================== */

/* ---- Single-media wrapper (no carousel chrome) ---- */

.event-media-single {
    margin-top: var(--space-3);
}

/* Images inside the single wrapper use .post-image's natural sizing
   (max-width:100%, height:auto). No override needed. Videos get an
   explicit cap so portrait clips don't dominate the page — see
   .event-media-video below. */

/* ---- Video element ---- */

.event-media-video {
    display: block;
    max-width: 100%;
    max-height: 600px;
    border-radius: var(--radius-md);
    /* Letterbox bg for non-4:3 clips inside carousel slides. */
    background-color: var(--color-bg-subtle);
}

/* When the video sits inside a carousel slide (viewer or editor),
   fill the slide and let object-fit handle aspect — same shape as
   the existing .media-carousel .swiper-slide img.post-image rule. */

.event-media-carousel .swiper-slide .event-media-video,
.event-media-carousel-edit .swiper-slide .event-media-video {
    width: 100%;
    height: 100%;
    object-fit: contain;
    /* Override the single-context max-height cap; the carousel itself
       caps via aspect-ratio + max-height. */
    max-height: none;
}

/* ---- File-picker label-button ("add some pics + clips") ---- */

/* The element is a <label> wrapping a hidden <input type="file">.
   Clicking the label opens the OS file picker — that's the standard
   accessible pattern. We style it as a button: bordered, rounded,
   surface bg, with a violet halo on hover so it feels like the rest
   of FriendZone's tappable surfaces. */

.event-media-add-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0.5rem 1rem;
    font-size: var(--font-size-body);
    color: var(--color-text);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    cursor: pointer;
    user-select: none;
    transition: border-color var(--transition-fast),
                box-shadow var(--transition-fast);
}

/* Three-layer violet halo on hover — matches the
   .notification-row:hover pattern (~line 4196). Inner 1px ring sits
   at the border, mid glow softens by ~12px, far diffuse layer fades
   by ~32px. --bs-primary-rgb is the brand violet (139,92,246 light /
   167,139,250 dark) so the halo theme-switches automatically. */

.event-media-add-btn:hover {
    border-color: rgba(var(--color-halo-rgb), 0.45);
    box-shadow:
        0 0 0 1px rgba(var(--color-halo-rgb), 0.45),
        0 0 12px 2px rgba(var(--color-halo-rgb), 0.22),
        0 0 32px 4px rgba(var(--color-halo-rgb), 0.10);
}

/* :focus-within (not :focus) because keyboard focus lands on the
   hidden <input> inside the label, not the label itself. Visually
   identical to hover so tab-focus and mouse-hover look the same. */

.event-media-add-btn:focus-within {
    outline: none;
    border-color: rgba(var(--color-halo-rgb), 0.55);
    box-shadow:
        0 0 0 2px rgba(var(--color-halo-rgb), 0.50),
        0 0 12px 2px rgba(var(--color-halo-rgb), 0.22),
        0 0 28px 4px rgba(var(--color-halo-rgb), 0.10);
}

@media (prefers-reduced-motion: reduce) {
    .event-media-add-btn {
        transition: none;
    }
}


/* =====================================================================
 * ev11b-2 — post ↔ event linking.
 *
 * Three surfaces:
 *   1. Post chip (.post-event-chip*)   — chip on post cards between
 *      body and media.
 *   2. Picker inline panel (.post-event-picker*) — search-as-you-type
 *      panel below the compose action row.
 *   3. Linked-posts section (.event-linked-post*) — compact tiles on
 *      the event detail page between media and RSVP.
 *
 * All append-only under this banner. Reuses the freespace-event-result
 * tile styling from the events/_search_results.html partial as-is; the
 * tile inherits its existing visual treatment unchanged. The picker
 * wrapper styles below add the panel chrome around it.
 * ===================================================================== */

/* ---- 1. Post chip ---- */

.post-event-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.25rem 0.75rem;
    border-radius: 999px;
    background-color: rgba(124, 58, 237, 0.08);  /* violet, subtle */
    color: var(--bs-body-color);
    transition: background-color 0.15s ease;
    max-width: 100%;
}

.post-event-chip:hover {
    background-color: rgba(124, 58, 237, 0.16);
    color: var(--bs-body-color);
}

.post-event-chip-icon {
    color: rgba(124, 58, 237, 0.85);
    flex-shrink: 0;
}

.post-event-chip-title {
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.post-event-chip-date {
    flex-shrink: 0;
    white-space: nowrap;
}

/* ---- 2. Picker inline panel ---- */

/* Outer wrapper matches .post-music-picker-inline shape (d-none by
   default; revealed by JS). Just the visual chrome around the picker
   contents — no own padding since the inner .post-event-picker owns
   its layout. */
.post-event-picker-inline {
    /* Intentionally empty — sibling to .post-music-picker-inline; only
       there as a stable hook + structural anchor. */
}

.post-event-picker {
    border: 1px solid var(--bs-border-color);
    border-radius: 0.5rem;
    padding: 0.75rem;
    background-color: var(--bs-tertiary-bg);
}

.post-event-picker-search,
.post-event-picker-selected {
    /* States toggled via .d-none from JS. */
}

.post-event-picker-selected-preview {
    /* Inner result tile is rendered by the JS via the shared
       template; this is just the slot it lands in. */
    margin-top: 0.25rem;
}

/* ---- 3. Linked posts section on event detail ---- */

.event-linked-posts-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-top: 0.5rem;
}

.event-linked-post-tile {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    padding: 0.75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.5rem;
    background-color: var(--bs-body-bg);
    color: var(--bs-body-color);
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.event-linked-post-tile:hover {
    background-color: rgba(124, 58, 237, 0.04);
    border-color: rgba(124, 58, 237, 0.35);
    color: var(--bs-body-color);
}

.event-linked-post-avatar {
    flex-shrink: 0;
}

.event-linked-post-meta {
    flex: 1 1 auto;
    min-width: 0;
}

.event-linked-post-author {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    margin-bottom: 0.15rem;
}

.event-linked-post-author-name {
    font-weight: 600;
}

.event-linked-post-author-handle {
    /* .text-muted .small from Bootstrap; nothing extra needed. */
}

.event-linked-post-excerpt {
    color: var(--bs-secondary-color);
    font-size: 0.9rem;
    line-height: 1.35;
    /* Clamp visually to two lines if the 80-char truncate plus a
       narrow column still overflows. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.event-linked-post-thumbs {
    display: flex;
    gap: 0.25rem;
    flex-shrink: 0;
}

.event-linked-post-thumb {
    width: 48px;
    height: 48px;
    object-fit: cover;
    border-radius: 0.25rem;
    display: block;
}

/* On narrow viewports the thumb strip eats too much width — collapse
   to a single thumb so the meta block keeps room to breathe. */
@media (max-width: 480px) {
    .event-linked-post-thumbs .event-linked-post-thumb:nth-child(n+2) {
        display: none;
    }
}


/* =====================================================================
 * ev11c — message blast
 * =====================================================================
 *
 * Two surfaces:
 *   1. Blast page (.blast-*) — recipient preview + compose form
 *      at /events/<id>/blast. Inherits the event-detail page chrome
 *      (hero band, sectioned body) from show.html's classes.
 *   2. Inline event-card (.message-event-card*) — compact event tile
 *      rendered inside thread.html for messages with event_id set.
 *      Visually mirrors .shared-post-card (nested card on bg-subtle).
 *
 * Both surfaces use the existing design tokens so the visual language
 * stays consistent with the rest of the events surface.
 * =====================================================================
 */

/* ---- Blast page: recipient preview chips ---- */

.blast-recipient-summary {
    font-size: var(--font-size-body);
    color: var(--color-text);
}

.blast-recipient-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin-top: var(--space-1);
}

.blast-recipient-chip {
    display: inline-flex;
    padding: 0.125rem 0.5rem;
    font-size: var(--font-size-md);
    color: var(--color-text);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    text-decoration: none;
    transition: all var(--transition-fast);
}

.blast-recipient-chip:hover {
    color: var(--color-text);
    border-color: var(--color-text-muted);
    text-decoration: none;
}

/* ---- Blast page: empty + existing-thread banner ---- */

.blast-empty {
    font-size: var(--font-size-body);
    color: var(--color-text-muted);
    line-height: 1.4;
}

.blast-existing-banner {
    padding: var(--space-2) var(--space-3);
    background: color-mix(in srgb, var(--color-accent) 8%, var(--color-bg-surface));
    border: 1px solid color-mix(in srgb, var(--color-accent) 30%, var(--color-border));
    border-radius: var(--radius-md);
    font-size: var(--font-size-body);
    color: var(--color-text);
}

.blast-existing-banner a {
    color: var(--color-accent);
    text-decoration: none;
    margin-left: var(--space-1);
}

.blast-existing-banner a:hover {
    text-decoration: underline;
}

/* ---- Blast page: compose form wrapper (minimal — form-control + button do the heavy lifting) ---- */

.blast-compose {
    display: flex;
    flex-direction: column;
}

/* ---- Inline event-card inside thread messages ---- */

/* Card surface mirrors .shared-post-card (bg-subtle nested inside the message bubble's Bootstrap card). margin-left matches the ms-4 indent applied to message content so the card aligns under the body text rather than under the avatar. */
.message-event-card {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
    margin-left: 1.5rem;
    margin-top: var(--space-2);
    padding: var(--space-3);
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: var(--color-text);
    transition: all var(--transition-fast);
}

.message-event-card:hover {
    text-decoration: none;
    color: var(--color-text);
    border-color: var(--color-text-muted);
}

.message-event-card-icon {
    flex-shrink: 0;
    color: var(--color-text-muted);
    padding-top: 0.125rem;
}

.message-event-card-body {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    flex: 1;
    min-width: 0;
}

.message-event-card-title {
    font-weight: var(--font-weight-semibold);
    color: var(--color-text);
    line-height: 1.3;
}

.message-event-card-when,
.message-event-card-where {
    font-size: var(--font-size-md);
    color: var(--color-text-muted);
    line-height: 1.3;
}

.message-event-card-meta {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-1);
}

/* Pill bg uses bg-surface so it stands out against the card's bg-subtle. Mirrors .event-detail-pill shape without taking the dependency. */
.message-event-card-pill {
    display: inline-flex;
    padding: 0.125rem 0.5rem;
    font-size: var(--font-size-xs);
    text-transform: lowercase;
    color: var(--color-text-muted);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
}

.message-event-card-arrow {
    font-size: var(--font-size-xs);
    color: var(--color-accent);
}

/* =====================================================================
   ev11d-1 bulk actions — drafts tab UI
   =====================================================================
   Lives on /events?tab=drafts (+ /events/imports shortcut). New surfaces:

     - imports banner   ("you have 1,030 imported drafts. review →")
     - filter bar       (date range + quick chip + source + recurring + q)
     - bulk toolbar     (master checkbox + publish/delete buttons)
     - override prompt  ("apply to all N matching" when total > page)
     - row checkbox     (per-row select column)
     - imported pill    (variant of event-list-row-pill on imported drafts)
     - pagination       (prev/next links + page status)

   Token-only colors (var(--color-*)). All new classes are
   .drafts-* or .event-list-row-pill-imported / .event-list-row-check
   so they nest predictably under the existing event-list-* tree
   without touching the upcoming/past tab rendering.
   ===================================================================== */

/* ---- Imports banner ----
   Sits between tabs and filter bar, only on drafts tab when there
   are imported drafts and the user isn't already in imports-only
   view. Tertiary-info styling (subtle bg, small text). */
.drafts-imports-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-top: var(--space-3);
    padding: 0.75rem 1rem;
    font-size: var(--font-size-body);
    color: var(--color-text);
    background: color-mix(in srgb, var(--color-accent) 8%, var(--color-bg-surface));
    border: 1px solid color-mix(in srgb, var(--color-accent) 25%, transparent);
    border-radius: var(--radius-md);
}

.drafts-imports-banner a {
    color: var(--color-accent);
    text-decoration: none;
    font-weight: var(--font-weight-medium);
    white-space: nowrap;
}

.drafts-imports-banner a:hover {
    text-decoration: underline;
}

/* ---- Filter bar ----
   GET form. Two rows of fields + one row of actions. Stacks on
   mobile via flex-wrap on the row. */
.drafts-filter-bar {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin-top: var(--space-3);
    padding: 0.75rem 1rem;
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
}

.drafts-filter-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--space-3);
}

.drafts-filter-field {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 140px;
}

/* Search field grows to fill remaining row width. */
.drafts-filter-field-grow {
    flex: 1 1 200px;
}

.drafts-filter-label {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--color-text-muted);
}

.drafts-filter-field input[type="date"],
.drafts-filter-field input[type="text"],
.drafts-filter-field select {
    padding: 0.4rem 0.6rem;
    font-size: var(--font-size-body);
    color: var(--color-text);
    background: var(--color-bg-page);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
}

.drafts-filter-field input:focus-visible,
.drafts-filter-field select:focus-visible {
    outline: none;
    border-color: var(--color-accent);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-accent) 25%, transparent);
}

.drafts-filter-actions {
    align-items: center;
}

.drafts-filter-clear {
    font-size: var(--font-size-body);
    color: var(--color-text-muted);
    text-decoration: none;
}

.drafts-filter-clear:hover {
    color: var(--color-text);
    text-decoration: underline;
}

/* ---- Bulk-action form + toolbar ----
   Form itself is a layout marker — no visual styling. The toolbar
   inside is what users actually see. */
.drafts-bulk-form {
    margin-top: var(--space-3);
}

.drafts-bulk-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: 0.6rem 1rem;
    background: var(--color-bg-subtle);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-md);
}

.drafts-bulk-selectall {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--font-size-body);
    color: var(--color-text-muted);
    cursor: pointer;
}

.drafts-bulk-selectall input[type="checkbox"] {
    /* Slightly larger hit target than browser-default; same visual
       size as row checkboxes for visual consistency. */
    width: 16px;
    height: 16px;
    cursor: pointer;
}

.drafts-bulk-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* ---- Override prompt ----
   "apply to all N matching" — appears below the bulk toolbar when
   total_count > visible page. Smaller, secondary-feeling than the
   main bulk row. */
.drafts-bulk-override {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-top: var(--space-2);
    padding: 0.5rem 1rem;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
    background: var(--color-bg-surface);
    border: 1px dashed var(--color-border-subtle);
    border-radius: var(--radius-md);
}

.drafts-bulk-override-prompt {
    color: var(--color-text);
}

.drafts-bulk-override-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}

/* ---- Per-row checkbox column ----
   Adds a slim column at the start of the draft row. Inherits from
   the existing .event-list-row flex layout — no row-level changes
   needed. */
.event-list-row-check {
    display: flex;
    align-items: center;
    padding-right: var(--space-1);
}

.event-list-row-check input[type="checkbox"] {
    width: 16px;
    height: 16px;
    cursor: pointer;
}

/* ---- Imported pill ----
   Variant of .event-list-row-pill (existing). Same shape, accent
   tinted to mark imported events at a glance. Mirrors the
   summary-pill.is-admin token (violet) since "this came from
   somewhere else" is a provenance signal, like admin = "this is
   special". */
.event-list-row-pill-imported {
    background: color-mix(in srgb, var(--color-accent) 12%, transparent);
    color: var(--color-accent);
}

/* ---- Pagination ----
   Bottom of the drafts list. prev / status / next. */
.drafts-pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    margin-top: var(--space-4);
    padding: var(--space-2) 0;
    font-size: var(--font-size-body);
}

.drafts-pagination-link {
    padding: 0.3rem 0.6rem;
    color: var(--color-accent);
    text-decoration: none;
    border-radius: var(--radius-sm);
}

.drafts-pagination-link:hover {
    background: var(--color-bg-subtle);
    text-decoration: none;
}

.drafts-pagination-link.is-disabled {
    color: var(--color-text-muted);
    cursor: default;
    opacity: 0.5;
}

.drafts-pagination-link.is-disabled:hover {
    background: transparent;
}

.drafts-pagination-status {
    font-family: var(--font-mono);
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

/* ===================================================================
 * bugfix/time-difference — event tz picker visibility
 *
 * The tz picker is irrelevant for all-day events (date-anchored,
 * Event.timezone stays NULL). CSS :has() collapses the row whenever
 * the all-day flag chip is checked inside the same composer section.
 * Route already ignores form.timezone in the all-day branch, so the
 * hide is purely UX polish — no functional dependency.
 * =================================================================== */
.event-composer-section:has(.event-flag-chip input:checked) .event-tz-row {
    display: none;
}

