/* ═══════════════════════════════════════════════════════════════
   EkklesiaSelect / EkklesiaAutocomplete — GLOBAL stylesheet.
   (Scoped .razor.css cannot style RenderTreeBuilder-built option rows:
   no scope attribute is emitted, so selectors never match. HeroUI's
   BEM classes are global too; this file follows that model.)
   Namespace: .ekklesia-select / .ekklesia-ac / .ekklesia-chip
   Tokens from app.css :root incl. dark-mode ink family.
   ═══════════════════════════════════════════════════════════════ */

/* ── Shell (shared by both pickers) ── */
.ekklesia-select,
.ekklesia-ac {
    position: relative;
    display: inline-flex;
    flex-direction: column;
    font-family: inherit;
}

.ekklesia-select--full,
.ekklesia-ac--full { width: 100%; }

.ekklesia-select--inline,
.ekklesia-ac--inline { max-width: 100%; }

/* ── Trigger ── */
.ekklesia-select__trigger,
.ekklesia-ac__trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    min-height: 40px;
    padding: 0.35rem 0.85rem;
    background: var(--bg-secondary);
    border-radius: 9999px;
    cursor: pointer;
    width: 100%;
    text-align: left;
    transition: background var(--motion-duration-fast) var(--motion-ease),
                box-shadow var(--motion-duration-fast) var(--motion-ease);
}

/* primary variant: soft shadow; secondary: flat */
.ekklesia-select:not(.ekklesia-select--secondary) .ekklesia-select__trigger,
.ekklesia-ac:not(.ekklesia-ac--secondary) .ekklesia-ac__trigger {
    box-shadow: var(--shadow-sm);
}

.ekklesia-select__trigger:hover,
.ekklesia-ac__trigger:hover {
    background: color-mix(in srgb, var(--primary) 7%, var(--bg-secondary));
}

.ekklesia-select__trigger:focus-visible,
.ekklesia-ac__trigger:focus-visible {
    outline: 2px solid var(--primary-ink);
    outline-offset: 1px;
}

.ekklesia-select.is-open .ekklesia-select__trigger,
.ekklesia-ac.is-open .ekklesia-ac__trigger {
    background: var(--bg-card);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary-ink) 55%, transparent);
}

.ekklesia-select.is-invalid .ekklesia-select__trigger,
.ekklesia-ac.is-invalid .ekklesia-ac__trigger {
    background: color-mix(in srgb, var(--danger-ink) 8%, var(--bg-secondary));
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--danger-ink) 50%, transparent);
}

.ekklesia-select__trigger[aria-disabled="true"],
.ekklesia-ac__trigger[aria-disabled="true"] {
    opacity: 0.6;
    cursor: not-allowed;
    pointer-events: none;
}

/* ── Value / placeholder ── */
.ekklesia-select__value,
.ekklesia-ac__value {
    flex: 1;
    min-width: 0;
    font-size: 0.875rem;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ekklesia-select__value.is-placeholder,
.ekklesia-ac__value.is-placeholder { color: var(--text-muted); }

.ekklesia-ac__selected { display: inline-flex; align-items: center; gap: 0.4rem; }

/* ── Indicator ── */
.ekklesia-select__indicator,
.ekklesia-ac__indicator {
    color: var(--text-muted);
    font-size: 0.8rem;
    flex-shrink: 0;
    transition: transform var(--motion-duration-fast) var(--motion-ease);
}

.ekklesia-select.is-open .ekklesia-select__indicator,
.ekklesia-ac.is-open .ekklesia-ac__indicator { transform: rotate(180deg); }

/* ── Chips (multiple mode) ── */
.ekklesia-select__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    white-space: normal;
}



/* Issue #93: summary-mode trigger — "N selected" + clear button, one tidy line. */
.ekklesia-select__summary, .ekklesia-ac__summary { flex: 1; min-width: 0; font-size: 0.875rem; font-weight: 500; color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ekklesia-select__summary-clear, .ekklesia-ac__summary-clear { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border: none; border-radius: 50%; background: transparent; color: var(--text-muted); font-size: 0.9rem; line-height: 1; cursor: pointer; transition: background var(--motion-duration-fast) ease, color var(--motion-duration-fast) ease; }
.ekklesia-select__summary-clear:hover, .ekklesia-ac__summary-clear:hover { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger); }

.ekklesia-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
    background: var(--primary-light);
    color: var(--primary-ink);
    border-radius: 999px;
    padding: 0.1rem 0.3rem 0.1rem 0.55rem;
    font-size: 0.72rem;
    font-weight: 600;
}

.ekklesia-chip__remove {
    border: none;
    background: transparent;
    color: inherit;
    cursor: pointer;
    font-size: 0.85rem;
    line-height: 1;
    padding: 0 0.25rem;
    opacity: 0.65;
}

.ekklesia-chip__remove:hover { opacity: 1; color: var(--danger-ink); }

/* ── Trigger clear button (autocomplete) ── */
.ekklesia-ac__clear {
    border: none;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    padding: 0.15rem;
    border-radius: 50%;
    font-size: 0.75rem;
    flex-shrink: 0;
    transition: var(--transition);
}

.ekklesia-ac__clear:hover { color: var(--danger-ink); background: var(--bg-secondary); }

/* ── Popover (positioned by ekklesia-popover.js as position:fixed) ── */
.ekklesia-pop-overlay {
    position: fixed;
    inset: 0;
    z-index: 1090;
    background: transparent;
    border: none;
}

.ekklesia-select__popover,
.ekklesia-ac__popover,
.ek-colorpicker__panel {
    position: fixed;
    visibility: hidden; /* hidden until first JS position — no flash at 0,0 */

    /* Issue #154: the visual chrome lives on the BASE rule, not only on the
       [data-positioned="true"] rule. The popover is rendered into the DOM a
       round-trip before watch() positions it (measured: 18ms in Blazor Server),
       so any rule that reveals it before positioning must not also strip its
       appearance — otherwise the first paint is a bare transparent list and the
       dropdown appears to "open twice". Keeping the chrome here means EVERY state
       looks like a dropdown. */
    z-index: 2100;
    max-height: 300px;
    max-width: 340px;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: 0.35rem;
}

/* Issue #132: safety net for "the positioning module never ran" (slow/blocked
   module load, import error) — without it the popover stays permanently invisible
   while still being open and clickable, an "invisible dropdown".
   
   Issue #154: this MUST NOT reveal the popover immediately. It was written as
   `visibility: visible` up front, which made it the normal first paint — the
   popover is in the DOM ~18ms before watch() sets data-positioned="true", so it
   flashed once unpositioned (absolutely placed at its parent, wrong size) and then
   again once positioned. Reported as "both dropdowns open twice, the first a few
   ms before the second".
   
   Fix: keep the popover hidden and reveal it only after a delay, via a
   fill-forwards animation. A healthy open sets data-positioned="true" long before
   the delay elapses, this selector then stops matching and the animation is
   dropped — so the normal path never paints the unpositioned state at all, while a
   genuinely broken module still ends up with a reachable list. */
.ekklesia-select__popover:not([data-positioned="true"]),
.ekklesia-ac__popover:not([data-positioned="true"]),
.ek-colorpicker__panel:not([data-positioned="true"]) {
    position: absolute;
    top: 100%;
    left: 0;
    animation: ek-popover-reveal-fallback 0s linear 600ms forwards;
}

@keyframes ek-popover-reveal-fallback {
    to { visibility: visible; }
}

.ekklesia-select__popover[data-positioned="true"],
.ekklesia-ac__popover[data-positioned="true"],
.ek-colorpicker__panel[data-positioned="true"] {
    visibility: visible;
    z-index: 2100;
    animation: ek-pop var(--motion-duration-fast) var(--motion-ease);
}

/* Fade-only entry: transform animations would make the popover its own
   containing block while running and offset fixed positioning. */
@keyframes ek-pop {
    from { opacity: 0; }
}

/* ── List ── */
.ekklesia-select__list { list-style: none; margin: 0; padding: 0; }

.ekklesia-select__section-header {
    padding: 0.5rem 0.65rem 0.25rem;
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

/* ── Option rows — HeroUI-style: generous spacing, rounded, no borders between ── */
.ekklesia-select__option {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.55rem 0.65rem;
    margin: 1px 0;
    border-radius: var(--radius);
    font-size: 0.875rem;
    line-height: 1.4;
    color: var(--text-primary);
    cursor: pointer;
    list-style: none;
    transition: background var(--motion-duration-fast) var(--motion-ease),
                color var(--motion-duration-fast) var(--motion-ease);
}

/* Option label: single line, grows with content. Ellipsis appears only
   when the popover's 340px max-width cap clips the text. */
.ekklesia-select__option-label {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ekklesia-select__option > i { color: var(--text-muted); flex-shrink: 0; }

.ekklesia-select__option:hover { background: var(--bg-secondary); }

.ekklesia-select__option.is-highlighted {
    background: color-mix(in srgb, var(--primary-ink) 12%, transparent);
    color: var(--text-primary);
}

.ekklesia-select__option.is-selected {
    background: color-mix(in srgb, var(--primary-ink) 10%, transparent);
    color: var(--primary-ink);
    font-weight: 600;
}

.ekklesia-select__option-check { margin-left: auto; color: var(--primary-ink); font-size: 0.9rem; flex-shrink: 0; }

.ekklesia-select__option.is-disabled {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}

.ekklesia-select__empty {
    padding: 1rem;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.82rem;
    list-style: none;
}

.ekklesia-select__loading { padding: 0.7rem; display: flex; flex-direction: column; gap: 0.55rem; }

/* ── Autocomplete filter row ── */
.ekklesia-ac__filter {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.6rem;
    margin: 0.1rem 0.1rem 0.35rem;
    border-radius: 9999px;
    background: var(--bg-secondary);
    position: sticky;
    top: 0;
    z-index: 1;
}

.ekklesia-ac__filter:focus-within {
    background: var(--bg-card);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary-ink) 45%, transparent);
}

.ekklesia-ac__filter > i { color: var(--text-muted); font-size: 0.8rem; }

.ekklesia-ac__input {
    border: none;
    outline: none;
    background: transparent;
    width: 100%;
    font-size: 0.85rem;
    color: var(--text-primary);
    font-family: inherit;
}

.ekklesia-ac__filter-clear {
    border: none;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    display: inline-flex;
    padding: 0;
    font-size: 0.75rem;
}

.ekklesia-ac__filter-clear:hover { color: var(--danger-ink); }


/* ═══════════════════════════════════════════════════════════════
   EkklesiaToast — stacked notification region (HeroUI-style)
   ═══════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════════
   EkklesiaToast — HeroUI-style stacked region.
   Collapsed: deck (front card + peeking cards behind, scaled/faded).
   Expanded (region hover/focus or touch): vertical list.
   ═══════════════════════════════════════════════════════════════ */
.ekklesia-toast-region {
    position: fixed;
    z-index: 3000;
    display: grid; /* stack all cards in the same cell */
    width: min(420px, calc(100vw - 2rem));
    pointer-events: auto; /* region IS the hover target for unfurl */
}

.ekklesia-toast-region--br { right: 1rem; bottom: 1rem; }
.ekklesia-toast-region--bc { left: 50%; bottom: 1rem; transform: translateX(-50%); }
.ekklesia-toast-region--bl { left: 1rem; bottom: 1rem; }
.ekklesia-toast-region--tr { right: 1rem; top: calc(var(--header-height, 64px) + 0.75rem); }
.ekklesia-toast-region--tc { left: 50%; top: calc(var(--header-height, 64px) + 0.75rem); transform: translateX(-50%); }
.ekklesia-toast-region--tl { left: 1rem; top: calc(var(--header-height, 64px) + 0.75rem); }

.ekklesia-toast {
    grid-area: 1 / 1; /* overlap → stacked deck */
    position: relative;   /* anchor for the progress bar */
    overflow: hidden;     /* clip bar to card radius */
    pointer-events: auto;
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    padding: 0.8rem 0.9rem;
    background: var(--bg-card);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    transition: transform var(--motion-duration-base) var(--motion-ease),
                opacity var(--motion-duration-base) var(--motion-ease);
    animation: ekt-in var(--motion-duration-base) var(--motion-spring);
}

@keyframes ekt-in {
    from { opacity: 0; transform: translateY(12px); }
}

/* Collapsed deck: older cards peek UPWARD behind the frontmost (negative Y). */
.ekklesia-toast[data-index="1"] { transform: translateY(-10px) scale(0.95); opacity: 0.72; z-index: -1; }
.ekklesia-toast[data-index="2"] { transform: translateY(-19px) scale(0.90); opacity: 0.5; z-index: -2; }

/* Expanded list: undo offsets, full opacity, flow layout (block list) */
.ekklesia-toast-region:hover,
.ekklesia-toast-region:focus-within,
.ekklesia-toast-region.is-expanded {
    display: flex;              /* leave grid stacking */
    flex-direction: column;     /* block-style list, newest on top */
    gap: 0.5rem;                /* space between message cards */
}

.ekklesia-toast-region:hover .ekklesia-toast,
.ekklesia-toast-region.is-expanded .ekklesia-toast {
    transform: none;
    opacity: 1;
    z-index: auto;
    grid-area: auto;
}

/* Region hover: make sure the whole deck area is hoverable even when 1 card */
.ekklesia-toast-region { min-height: 1rem; }

.ekklesia-toast__indicator {
    position: relative;       /* anchor for absolute icon centering */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* Absolute-center the glyph: immune to icon-font baseline quirks (the
   loading spinner centers perfectly because it's a sized box — this matches it). */
.ekklesia-toast__indicator .bi {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 0.85rem;
    line-height: 1;
    display: block;
}

.ekklesia-toast__content { flex: 1; min-width: 0; }

.ekklesia-toast__title {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.35;
}

.ekklesia-toast__description {
    margin-top: 0.1rem;
    font-size: 0.78rem;
    color: var(--text-secondary);
    line-height: 1.45;
}

.ekklesia-toast__action {
    align-self: center;
    border: none;
    background: transparent;
    color: var(--primary-ink);
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    padding: 0.3rem 0.5rem;
    border-radius: var(--radius-sm);
    flex-shrink: 0;
}

.ekklesia-toast__action:hover { background: var(--bg-secondary); }

.ekklesia-toast__close {
    border: none;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    display: inline-flex;
    padding: 0.2rem;
    border-radius: 50%;
    font-size: 0.7rem;
    flex-shrink: 0;
}

.ekklesia-toast__close:hover { color: var(--text-primary); background: var(--bg-secondary); }

/* Variants — tinted indicator + accent edge (ink tokens → dark-mode safe) */
.ekklesia-toast--default .ekklesia-toast__indicator { background: var(--bg-secondary); color: var(--text-secondary); }
.ekklesia-toast--accent .ekklesia-toast__indicator { background: var(--info-light); color: var(--info-ink); }
.ekklesia-toast--success .ekklesia-toast__indicator { background: var(--success-light); color: var(--success-ink); }
.ekklesia-toast--warning .ekklesia-toast__indicator { background: var(--warning-light); color: var(--warning-ink); }
.ekklesia-toast--danger .ekklesia-toast__indicator { background: var(--danger-light); color: var(--danger-ink); }

/* (left border accent removed per design update) */

/* Touch / small screens: no hover → auto-expand to list */
@media (hover: none), (max-width: 768px) {
    .ekklesia-toast[data-index="1"],
    .ekklesia-toast[data-index="2"] { transform: none; opacity: 1; z-index: auto; }
    .ekklesia-toast-region { display: flex; flex-direction: column; }
}


/* ═══════════════════════════════════════════════════════════════
   EkklesiaTooltip — hover/focus tooltip (HeroUI-style)
   ═══════════════════════════════════════════════════════════════ */
.ekklesia-tooltip { display: inline-flex; position: relative; }

.ekklesia-tooltip__trigger { cursor: help; display: inline-flex; }

/* ── Issue #487 — rail tooltip wrapper ───────────────────────────────────────
   Each nav row is wrapped in `.sidebar-rail-tip` so a collapsed rail can explain
   its icons. Note this lives HERE rather than in app.css: app.css is linked BEFORE
   ekklesia-forms.css, so a rule of equal specificity there loses to the
   `.ekklesia-tooltip { display: inline-flex }` rule below no matter how it looks.
   The wrapper must override that, so it belongs on this side of the link.

   The wrapper takes over the row's layout slot in .sidebar-nav. Blazor does NOT
   emit an element for a component, which is why the wrapper is the tooltip's own
   root carrying a class rather than a real wrapper tag. */
.sidebar-rail-tip {
    display: block;
    flex: none;
}

/* Fill the rail so the row's hover target stays full-bleed. */
.sidebar-rail-tip > .ekklesia-tooltip__trigger {
    display: flex;
    flex: 1;
    /* The component sets `cursor: help`, right for an ⓘ affordance beside a figure
       and wrong for a navigation row — these are links and buttons. */
    cursor: inherit;
}

/* The row must fill the space the wrapper freed. A `.nav-item` is a flex ROW whose
   only in-flow width comes from its children, and every wide child is pinned
   `flex: none` (the icon, the caret) or truncating (the label). As a direct child of
   `.sidebar-nav` — a BLOCK container — that never mattered: a block-level child fills
   the rail regardless of its contents, so the row measured 260px. Once the wrapper
   made it a FLEX item, `flex: 1` on the WRAPPER only sized the wrapper to its
   content, and the row inside it shrank to the text width.

   Measured on a 260px rail: rows were 164/184/152/131/202px instead of 260px, so
   every hover and active background stopped short of the edge and the rows no longer
   shared a right edge. Collapsed, the same shrink moved the centred icon from 27px to
   13px from the rail edge — a 72px rail with a 44px hit target. Restoring `flex: 1`
   and `width: 100%` here returns both states to their pre-wrapper measurements
   (260px rows; icon 27px). */
.sidebar-rail-tip > .ekklesia-tooltip__trigger > .nav-item {
    flex: 1 1 auto;
    width: 100%;
}

.ekklesia-tooltip__content {
    position: fixed; /* positioned by ekklesia-popover.js */
    visibility: hidden; /* hidden until first JS position — no flash at the wrong place */
    z-index: 1200;
    max-width: 260px;
    padding: 0.45rem 0.65rem;
    background: var(--bg-tooltip, #2A2A2E);
    color: #FAFAFA;
    font-size: 0.78rem;
    line-height: 1.45;
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    text-align: left;
}

/* Issue #494 — the tooltip opened at one position and then blinked to another.
   Measured with Playwright: the content paints ~32ms BEFORE the popover engine
   gives it coordinates, and because `position: fixed` with no top/left resolves
   to its static position, that first paint was VISIBLE at the wrong place (a
   measured 48px jump). The select popovers had the same defect and solved it with
   exactly this gate (see the #154 note above), so the tooltip now matches them.

   Reveal only once the engine has positioned it. A healthy open sets
   data-positioned="true" before the first paint, so the hidden state is never
   seen for long — it exists to cover the gap, not to animate a delay. */
.ekklesia-tooltip__content[data-positioned="true"] {
    visibility: visible;
    /* Enter: fade only. A transform animation would make the tooltip its own
       containing block and offset its own fixed positioning. */
    animation: ek-tooltip-in var(--motion-duration-fast) var(--motion-ease);
}

/* Leaving (issue #494) — the component keeps the node rendered for one short beat
   so the exit can fade instead of disappearing. Matches enter's timing/easing so
   the pair reads as one motion. */
.ekklesia-tooltip__content.is-leaving {
    visibility: visible;
    pointer-events: none;
    animation: ek-tooltip-out var(--motion-duration-fast) var(--motion-ease) forwards;
}

@keyframes ek-tooltip-in {
    from { opacity: 0; }
}

@keyframes ek-tooltip-out {
    to { opacity: 0; }
}

/* Safety net for "the positioning module never ran" (slow or blocked module load,
   import error) — without it the tooltip stays permanently invisible while still
   being open. Like the select's fallback this must NOT reveal it immediately, or
   it becomes the normal first paint and we are back to the blink; reveal on a
   delay instead. A healthy open sets data-positioned="true" long before the delay
   elapses, this selector stops matching, and the animation is dropped. */
.ekklesia-tooltip__content:not([data-positioned="true"]) {
    animation: ek-tooltip-reveal-fallback 0s linear 600ms forwards;
}

@keyframes ek-tooltip-reveal-fallback {
    to { visibility: visible; }
}

:root[data-theme="dark"] .ekklesia-tooltip__content {
    --bg-tooltip: #334155;
}

.ekklesia-tooltip__arrow {
    position: absolute;
    width: 8px;
    height: 8px;
    background: inherit;
    transform: rotate(45deg);
}

.ekklesia-tooltip__content[data-placement="bottom"] .ekklesia-tooltip__arrow {
    top: -4px;
    left: 50%;
    margin-left: -4px;
}

.ekklesia-tooltip__content[data-placement="top"] .ekklesia-tooltip__arrow {
    bottom: -4px;
    left: 50%;
    margin-left: -4px;
}

/* Issue #487 — side placements, used by the collapsed sidebar rail (the panel sits
   beside the icon, so the arrow points back at it from the near edge). */
.ekklesia-tooltip__content[data-placement="right"] .ekklesia-tooltip__arrow {
    left: -4px;
    top: 50%;
    margin-top: -4px;
}

.ekklesia-tooltip__content[data-placement="left"] .ekklesia-tooltip__arrow {
    right: -4px;
    top: 50%;
    margin-top: -4px;
}


/* ═══════════════════════════════════════════════════════════════
   EkklesiaTable — HeroUI-style table (global BEM classes because
   Header/Rows fragments are authored by consuming pages, whose
   scope-ids differ from the component's)
   ═══════════════════════════════════════════════════════════════ */
.ek-table--wrapped {
    background: var(--bg-card);
    /* Issue #427 — no outer border. The container edge is carried by its SURFACE
       (card background + radius + shadow) instead of a 1px outline, matching the
       header work in #425: the design language is flat, with containment expressed
       by surface and spacing rather than lines. Geometry is unchanged because
       box-sizing:border-box is global, so the wrapper keeps its exact box. */
    border: none;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

.ek-table--secondary.ek-table--wrapped { box-shadow: none; }
/* Chrome suppression without losing the responsive card view.
   RemoveWrapper used to emit NO wrapper class, which also killed the
   mobile card-on-small-screens rules below (issue #426). */
.ek-table--no-chrome { background: transparent; border: none; border-radius: 0; box-shadow: none; }

.ek-table__scroll-container { overflow-x: auto; overscroll-behavior-x: contain; }

.ek-table__content { width: 100%; border-collapse: collapse; font-size: 0.85rem; }

.ek-table__content thead th {
    text-align: left;
    padding: 0.6rem 1rem;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    background: var(--bg-secondary);
    /* Issue #427 — the header band is delimited by its TINT, not a rule. It already
       sits on a different background from the rows, so the line restated the colour
       change. The row separators below are deliberately kept: see the note there. */
    border-bottom: none;
    white-space: nowrap;
}

/* ── Table corners inside a card (issue #241 follow-up, refined) ─────────────
   A table's header row carries an OPAQUE grey background, so wherever the table's
   top edge is visible its square corners clash with the rounded card behind it.
   Measured on the report pages before this fix:

     flush card, no header above     thead 12px | last row 12px   <- only this was right
     flush card, header above        thead  0px | last row 12px   <- mixed
     flush card, header + toolbar    thead  0px | last row 12px   <- mixed
     default (padded) card           thead  0px | last row  0px   <- nothing rounded

   The rule applied: a table's four corners all take the same radius, so top and
   bottom always match and the table reads as one rounded surface. The rounded band
   is whichever element forms the edge — the header row at the top, and either the
   footer band or the last row at the bottom (most report tables have a footer).

   Deliberately scoped to `.ek-card`, NOT applied to every `.ek-table` in the app:
   a table sitting full-bleed on the page background has no curve to match, and
   rounding it there would introduce a new defect. A WRAPPED table
   (RemoveWrapper=false) keeps square cells because its own 12px wrapper radius +
   `overflow: hidden` already clips the corners.

   Why this is the GLOBAL sheet and not EkklesiaCard.razor.css: `thead th` / `tbody
   td` are authored by the CONSUMING PAGE (they arrive through EkklesiaTable's
   Header/Rows fragments), so they carry the page's scope id. A rule inside the card
   component compiles to `... thead th[card-scope]` and can never match; and a card's
   `overflow: hidden` cannot round a child's background anyway. */

/* ── Top edge: the header row ── */
.ek-card .ek-table:not(.ek-table--wrapped) .ek-table__content > thead > tr:first-child > th:first-child {
    border-top-left-radius: var(--radius-lg, 12px);
}

.ek-card .ek-table:not(.ek-table--wrapped) .ek-table__content > thead > tr:first-child > th:last-child {
    border-top-right-radius: var(--radius-lg, 12px);
}

/* ── Bottom edge: the footer band, or the last row when there is no footer ── */
.ek-card .ek-table:not(.ek-table--wrapped) .ek-table__footer {
    border-bottom-left-radius: var(--radius-lg, 12px);
    border-bottom-right-radius: var(--radius-lg, 12px);
}

.ek-card .ek-table:not(.ek-table--wrapped) .ek-table__content > tbody > tr:last-child > td:first-child {
    border-bottom-left-radius: var(--radius-lg, 12px);
}

.ek-card .ek-table:not(.ek-table--wrapped) .ek-table__content > tbody > tr:last-child > td:last-child {
    border-bottom-right-radius: var(--radius-lg, 12px);
}

/* When a footer follows, it owns the bottom edge — the last row must stay square or
   its corners curl inside the straight footer band. */
.ek-card .ek-table:has(.ek-table__footer) .ek-table__content > tbody > tr:last-child > td {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}

/* The last table row should not draw a border hard against the clipped corner.
   (Moved here from EkklesiaCard.razor.css, where the scope id landed on the
   page-authored `td` and the rule could never match.) */
.ek-card--flush .ek-table__content tbody tr:last-child td { border-bottom: none; }

/* ═══════════════════════════════════════════════════════════════
   Issue #427 — .data-table corners inside a card.

   The rules above are scoped to `.ek-table`, which is what EkklesiaTable renders. The
   DASHBOARD tables (Dashboard.razor, SystemDashboard.razor, Expired.razor) are bare
   `<table class="data-table">` — they do NOT use EkklesiaTable — so not one of those
   rules could ever match them. Measured in a flush card (radius 20px, overflow hidden):

     bare .data-table      header corner radius 0px     <- square, paints over the curve
     EkklesiaTable path    header corner radius 12px    <- correct

   `.data-table thead th` carries an OPAQUE --bg-body background, so its square corner is
   what makes the defect visible. The flush card's `overflow: hidden` cannot round a
   child's background, so the corner has to be set on the cell itself — same conclusion
   the block above reached for `.ek-table`.

   Two differences from the `.ek-table` rules, both intentional:
     - `.data-table` has no wrapper/footer bands, so only the header th and the last row
       carry a visible edge.
     - `.data-table` uses `border-collapse: separate` (not collapse), which is what makes a
       per-cell radius render at all. `td` needs the bottom corner because there is no
       `.ek-table__footer` here — without it the flush card's bottom-left stayed square
       (measured 0px) even on the `.ek-table` path. */
.ek-card .data-table > thead > tr:first-child > th:first-child {
    border-top-left-radius: var(--radius-lg, 12px);
}

.ek-card .data-table > thead > tr:first-child > th:last-child {
    border-top-right-radius: var(--radius-lg, 12px);
}

.ek-card .data-table > tbody > tr:last-child > td:first-child {
    border-bottom-left-radius: var(--radius-lg, 12px);
}

.ek-card .data-table > tbody > tr:last-child > td:last-child {
    border-bottom-right-radius: var(--radius-lg, 12px);
}

/* Issue #427 — the row separator is DELIBERATELY KEPT while the outer border and the
   header rule are removed. It is not decoration: a row here is ~47px of vertical run
   across six columns, and this line is what lets the eye carry one row's Amount across
   to its Actions. Remove it and the columns stop tracking — the same class of defect as
   removing a hover affordance (see #425). It is also the only grid line left, so the
   table reads as a list of rows rather than a ruled grid. */
.ek-table__content tbody td {
    padding: 0.65rem 1rem;
    color: var(--text-primary);
    border-bottom: 1px solid var(--border-color);
    vertical-align: middle;
}

.ek-table__content tbody tr:last-child td { border-bottom: none; }

.ek-table__content tbody tr { transition: background var(--motion-duration-fast) var(--motion-ease); }

.ek-table__content tbody tr:hover { background: var(--bg-table-hover); }

/* bordered flavor: vertical separators */
.ek-table--bordered .ek-table__content th:not(:last-child),
.ek-table--bordered .ek-table__content td:not(:last-child) { border-right: 1px solid var(--border-color); }

.ek-table__footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.65rem 1rem;
    border-top: 1px solid var(--border-color);
    background: var(--bg-secondary);
    flex-wrap: wrap;
}

.ek-table__empty { padding: 1rem 0; }

/* small screens: allow the same card-on-mobile pattern app.css uses */
@media (max-width: 768px) {
    /* Card-on-mobile for data tables. Applies to tables that opted into the
       wrapper chrome, and to those that suppressed it to sit inside a card
       (--no-chrome) — those used to emit no wrapper class at all, which
       silently killed every rule below (issue #426). */
    .ek-table--wrapped .ek-table__scroll-container,
    .ek-table--no-chrome .ek-table__scroll-container { overflow-x: visible; }

    .ek-table--wrapped .ek-table__content thead,
    .ek-table--no-chrome .ek-table__content thead { display: none; }

    .ek-table--wrapped .ek-table__content tbody tr,
    .ek-table--no-chrome .ek-table__content tbody tr {
        display: block;
        padding: 0.6rem 1rem;
        border-bottom: 1px solid var(--border-color);
    }

    .ek-table--wrapped .ek-table__content tbody td,
    .ek-table--no-chrome .ek-table__content tbody td {
        display: flex;
        justify-content: space-between;
        gap: 1rem;
        border-bottom: none;
        padding: 0.3rem 0;
    }

    .ek-table--wrapped .ek-table__content tbody td::before,
    .ek-table--no-chrome .ek-table__content tbody td::before {
        content: attr(data-label);
        font-size: 0.7rem;
        font-weight: 600;
        color: var(--text-muted);
        text-transform: uppercase;
        letter-spacing: 0.04em;
    }

    /* First cell = the card's header row (avatar + name + email on Users, the
       title on Events/Announcements). It has NO data-label, so space-between
       pushed the whole block to the RIGHT edge with the empty ::before holding
       the left — the identity of each card sat against the wrong side.
       Match the .data-table card view, which already does this. */
    .ek-table--wrapped .ek-table__content tbody td:first-child,
    .ek-table--no-chrome .ek-table__content tbody td:first-child {
        justify-content: flex-start;
        padding-bottom: 0.6rem;
        margin-bottom: 0.4rem;
        border-bottom: 1px solid var(--border-color);
        font-weight: 600;
    }
    .ek-table--wrapped .ek-table__content tbody td:first-child::before,
    .ek-table--no-chrome .ek-table__content tbody td:first-child::before { display: none; }

    /* Last cell = actions on most pages (no label, right-aligned). Pages whose
       last column is real data override this locally. */
    .ek-table--wrapped .ek-table__content tbody td:last-child:not(:first-child),
    .ek-table--no-chrome .ek-table__content tbody td:last-child:not(:first-child) {
        justify-content: flex-end;
        padding-top: 0.6rem;
        margin-top: 0.4rem;
        border-top: 1px solid var(--border-color);
    }
    .ek-table--wrapped .ek-table__content tbody td:last-child:not(:first-child)::before,
    .ek-table--no-chrome .ek-table__content tbody td:last-child:not(:first-child)::before { display: none; }
}


/* ═══════════════════════════════════════════════════════════════
   EkklesiaAlertDialog — critical confirmation dialog (HeroUI-style)
   ═══════════════════════════════════════════════════════════════ */
.ek-adialog__backdrop {
    position: fixed;
    inset: 0;
    z-index: 1100;
    background: rgb(15 23 42 / 0.55);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    /* 'backwards' fill: the page-transition stagger (app.css) sets animation-delay
       on every .page-transition-shell child — including this backdrop when the
       page hosts the dialog. Without a fill-mode the backdrop showed its NATURAL
       (fully dark) opacity during the delay, then the delayed fade replayed 0→1
       on top of it = the dialog visibly "opened twice" (issue #105). 'backwards'
       holds the hidden state during any inherited delay, so the entrance plays
       exactly once — same trick ek-modal-fade's 'both' already uses. */
    animation: ekad-fade var(--motion-duration-fast) var(--motion-ease) backwards;
}

.ek-adialog__backdrop--blur { backdrop-filter: blur(6px); background: rgb(15 23 42 / 0.4); }
.ek-adialog__backdrop--transparent { background: transparent; }

.ek-adialog__container {
    width: 100%;
    max-width: 420px;
    animation: ekad-pop var(--motion-duration-base) var(--motion-spring) backwards;
}

@keyframes ekad-fade { from { opacity: 0; } }
@keyframes ekad-pop { from { opacity: 0; transform: scale(0.96) translateY(8px); } }

.ek-adialog__dialog {
    background: var(--bg-card);
    border-radius: 20px;
    box-shadow: var(--shadow-lg);
    padding: 1.4rem 1.5rem 1.25rem;
    position: relative;
}

.ek-adialog__close {
    position: absolute;
    top: 0.8rem;
    right: 0.8rem;
    border: none;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    padding: 0.3rem;
    border-radius: 50%;
    display: inline-flex;
    font-size: 0.75rem;
}

.ek-adialog__close:hover { color: var(--text-primary); background: var(--bg-secondary); }

.ek-adialog__header {
    display: flex;
    align-items: center;
    gap: 0.85rem;
    margin-bottom: 1rem;
    padding-right: 1.5rem;
}

.ek-adialog__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 12px;
    font-size: 1.05rem;
    flex-shrink: 0;
}

.ek-adialog__heading {
    margin: 0;
    font-size: 1.02rem;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.3;
}

.ek-adialog__body {
    font-size: 0.88rem;
    color: var(--text-secondary);
    line-height: 1.55;
    margin-bottom: 1.1rem;
}

.ek-adialog__body p { margin: 0; }

.ek-adialog__footer {
    display: flex;
    justify-content: flex-end;
    gap: 0.55rem;
    margin-top: 1.25rem;
}

/* Status tints — icon plate + heading accent (ink tokens: dark-safe) */
[data-status="danger"] .ek-adialog__icon { background: var(--danger-light); color: var(--danger-ink); }
[data-status="warning"] .ek-adialog__icon { background: var(--warning-light); color: var(--warning-ink); }
[data-status="success"] .ek-adialog__icon { background: var(--success-light); color: var(--success-ink); }
[data-status="accent"] .ek-adialog__icon { background: var(--info-light); color: var(--info-ink); }

/* ═══════════════════════════════════════════════════════════════
   EkklesiaPagination — HeroUI ghost-button pagination
   ═══════════════════════════════════════════════════════════════ */
.ek-pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.ek-pagination__summary { font-size: 0.8rem; color: var(--text-muted); }

.ek-pagination__content {
    display: flex;
    align-items: center;
    gap: 0.2rem;
    margin-left: auto;
}

.ek-pagination__link {
    min-width: 34px;
    height: 34px;
    padding: 0 0.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    border-radius: var(--radius);
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--text-secondary);
    cursor: pointer;
    transition: background var(--motion-duration-fast) var(--motion-ease),
                color var(--motion-duration-fast) var(--motion-ease);
}

.ek-pagination__link:hover:not(:disabled) { background: var(--bg-secondary); color: var(--text-primary); }

.ek-pagination__link:focus-visible { outline: 2px solid var(--primary-ink); outline-offset: 1px; }

.ek-pagination__link[data-active="true"] {
    background: var(--primary);
    color: #fff;
    font-weight: 600;
    cursor: default;
}

.ek-pagination__link:disabled { opacity: 0.4; cursor: not-allowed; }

.ek-pagination__link--nav { color: var(--text-muted); }
.ek-pagination__link--nav:hover:not(:disabled) { color: var(--primary-ink); }

.ek-pagination__ellipsis {
    min-width: 26px;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.85rem;
}

/* sizes */
.ek-pagination--sm .ek-pagination__link { min-width: 28px; height: 28px; font-size: 0.78rem; }
.ek-pagination--lg .ek-pagination__link { min-width: 42px; height: 42px; font-size: 0.95rem; }

/* dark mode: active page fill stays saturated for contrast; ink accents elsewhere */




/* ═══════════════════════════════════════════════════════════════
   EkklesiaButton — port of HeroUI button.css
   (pill shape, custom-property variants, pressed scale, states)
   ═══════════════════════════════════════════════════════════════ */
.ek-button {
    position: relative;
    isolation: isolate;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    height: 2.5rem;            /* h-10 */
    width: fit-content;
    padding: 0 1rem;
    border-radius: 9999px;     /* rounded-3xl pill */
    font-size: 0.875rem;
    font-weight: 500;
    white-space: nowrap;
    outline: none;
    user-select: none;
    border: none;
    transform-origin: center;
    will-change: transform;
    transition:
        transform 250ms cubic-bezier(0.22, 1, 0.36, 1),
        background-color 100ms ease-out,
        box-shadow 100ms ease-out,
        color 100ms ease-out;
    cursor: pointer;
    /* default tokens (fallback) */
    --button-bg: transparent;
    --button-bg-hover: var(--button-bg);
    --button-bg-pressed: var(--button-bg-hover);
    --button-fg: currentColor;
    background-color: var(--button-bg);
    color: var(--button-fg);
}

.ek-button:focus-visible {
    outline: 2px solid var(--primary-ink);
    outline-offset: 2px;
}

.ek-button:disabled,
.ek-button[aria-disabled="true"] {
    opacity: 0.45;
    pointer-events: none;
}

.ek-button[data-pending="true"] { pointer-events: none; }

.ek-button:active {
    background-color: var(--button-bg-pressed);
    transform: scale(0.97);   /* HeroUI pressed squeeze */
}

/* sizes */
.ek-button--sm { height: 2.25rem; padding: 0 0.75rem; font-size: 0.82rem; }
.ek-button--sm:active { transform: scale(0.98); }
.ek-button--lg { height: 2.75rem; padding: 0 1.25rem; font-size: 0.95rem; }
.ek-button--lg:active { transform: scale(0.96); }

/* variants — map HeroUI semantics onto our ink/tint tokens */
.ek-button--primary {
    --button-bg: var(--primary);
    --button-bg-hover: color-mix(in srgb, var(--primary) 88%, #000);
    --button-bg-pressed: color-mix(in srgb, var(--primary) 82%, #000);
    --button-fg: #fff;
}
.ek-button--secondary {
    --button-bg: var(--bg-secondary);
    --button-bg-hover: color-mix(in srgb, var(--bg-secondary) 80%, var(--text-secondary));
    --button-bg-pressed: var(--button-bg-hover);
    --button-fg: var(--text-primary);
}
.ek-button--tertiary {
    --button-bg: var(--bg-secondary);
    --button-bg-hover: color-mix(in srgb, var(--bg-secondary) 80%, var(--text-secondary));
    --button-bg-pressed: var(--button-bg-hover);
    --button-fg: var(--text-secondary);
}
.ek-button--ghost,
.ek-button--outline {
    --button-bg: transparent;
    --button-bg-hover: var(--bg-secondary);
    --button-bg-pressed: var(--bg-secondary);
    --button-fg: var(--text-primary);
}
.ek-button--outline { border: 1px solid var(--border-color); }
.ek-button--danger {
    --button-bg: var(--danger);
    --button-bg-hover: color-mix(in srgb, var(--danger) 88%, #000);
    --button-bg-pressed: color-mix(in srgb, var(--danger) 80%, #000);
    --button-fg: #fff;
}
.ek-button--warning-soft {
    --button-bg: color-mix(in srgb, var(--warning-ink) 14%, var(--bg-card));
    --button-bg-hover: color-mix(in srgb, var(--warning-ink) 24%, var(--bg-card));
    --button-bg-pressed: var(--button-bg-hover);
    --button-fg: var(--warning-ink);
}
.ek-button--success-soft {
    --button-bg: color-mix(in srgb, var(--success-ink) 15%, var(--bg-card));
    --button-bg-hover: color-mix(in srgb, var(--success-ink) 25%, var(--bg-card));
    --button-bg-pressed: var(--button-bg-hover);
    --button-fg: var(--success-ink);
}
.ek-button--danger-soft {
    --button-bg: var(--danger-light);
    --button-bg-hover: color-mix(in srgb, var(--danger-light) 70%, var(--danger-ink));
    --button-bg-pressed: var(--button-bg-hover);
    --button-fg: var(--danger-ink);
}

/* dark mode: hover lightens instead of darkens */
[data-theme="dark"] .ek-button--primary {
    --button-bg-hover: color-mix(in srgb, var(--primary) 80%, #fff);
    --button-bg-pressed: color-mix(in srgb, var(--primary) 72%, #fff);
}
[data-theme="dark"] .ek-button--danger {
    --button-bg-hover: color-mix(in srgb, var(--danger) 80%, #fff);
    --button-bg-pressed: color-mix(in srgb, var(--danger) 72%, #fff);
}

/* modifiers */
.ek-button--icon-only { width: 2.5rem; padding: 0; }
.ek-button--icon-only.ek-button--sm { width: 2.25rem; }
.ek-button--icon-only.ek-button--lg { width: 2.75rem; }
.ek-button--full-width { width: 100%; }

.ek-button .ek-button__icon { font-size: 1rem; pointer-events: none; }

/* ═══════════════════════════════════════════════════════════════
   EkklesiaButtonGroup — port of HeroUI button-group.css
   ═══════════════════════════════════════════════════════════════ */
.ek-button-group { display: inline-flex; align-items: center; justify-content: center; gap: 0; }
.ek-button-group--horizontal { flex-direction: row; }
.ek-button-group--vertical { flex-direction: column; }

/* radius joining: pill caps on the outer ends only */
.ek-button-group .ek-button { border-radius: 0; }
.ek-button-group--horizontal .ek-button:first-child { border-radius: 9999px 0 0 9999px; }
.ek-button-group--horizontal .ek-button:last-child { border-radius: 0 9999px 9999px 0; }
.ek-button-group--horizontal .ek-button:first-child:last-child { border-radius: 9999px; }
.ek-button-group--vertical .ek-button:first-child { border-radius: 9999px 9999px 0 0; }
.ek-button-group--vertical .ek-button:last-child { border-radius: 0 0 9999px 9999px; }
.ek-button-group--vertical .ek-button:first-child:last-child { border-radius: 9999px; }

/* no pressed-scale inside groups (HeroUI rule) */
.ek-button-group .ek-button:active { transform: none; }

/* raise focused button so the ring shows above neighbors */
.ek-button-group .ek-button:focus-visible { z-index: 10; }

/* adjacent buttons separate by surface tint; outline variant collapses shared edge */
.ek-button-group--horizontal .ek-button--outline + .ek-button--outline { border-left: none; }

/* ═══════════════════════════════════════════════════════════════
   EkklesiaAlert — port of HeroUI alert.css (soft tinted surface)
   ═══════════════════════════════════════════════════════════════ */
.ek-alert {
    display: flex;
    width: 100%;
    flex-direction: row;
    align-items: flex-start;
    gap: 0.65rem;
    padding: 0.85rem 1rem;
    border-radius: 16px;
    background: var(--bg-card);
    box-shadow: var(--shadow-md);
}

.ek-alert__content { display: flex; flex: 1; flex-direction: column; align-items: flex-start; min-width: 0; }

.ek-alert__indicator {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    user-select: none;
    /* same box as the title's first line: 0.875rem * 1.5 line-height = 21px */
    width: 21px;
    height: 21px;
    flex-shrink: 0;
    font-size: 0.95rem;
    line-height: 1;
}

.ek-alert__title { font-size: 0.875rem; font-weight: 600; line-height: 1.5; color: var(--text-primary); }

.ek-alert__description { font-size: 0.875rem; color: var(--text-secondary); line-height: 1.5; margin-top: 0.1rem; }

.ek-alert__close {
    border: none; background: transparent; color: var(--text-muted);
    cursor: pointer; display: inline-flex; padding: 0.25rem;
    border-radius: 50%; font-size: 0.75rem; flex-shrink: 0;
}
.ek-alert__close:hover { color: var(--text-primary); background: var(--bg-secondary); }

/* Status variants — soft-tinted SURFACE + tinted indicator/title text (HeroUI semantics) */
.ek-alert--default { background: var(--bg-secondary); }
.ek-alert--default .ek-alert__indicator { color: var(--text-primary); }

.ek-alert--accent { background: color-mix(in srgb, var(--info-ink) 10%, var(--bg-secondary)); }
.ek-alert--accent .ek-alert__indicator, .ek-alert--accent .ek-alert__title { color: var(--info-ink); }

.ek-alert--success { background: color-mix(in srgb, var(--success-ink) 10%, var(--bg-secondary)); }
.ek-alert--success .ek-alert__indicator, .ek-alert--success .ek-alert__title { color: var(--success-ink); }

.ek-alert--warning { background: color-mix(in srgb, var(--warning-ink) 12%, var(--bg-secondary)); }
.ek-alert--warning .ek-alert__indicator, .ek-alert--warning .ek-alert__title { color: var(--warning-ink); }

.ek-alert--danger { background: color-mix(in srgb, var(--danger-ink) 10%, var(--bg-secondary)); }
.ek-alert--danger .ek-alert__indicator, .ek-alert--danger .ek-alert__title { color: var(--danger-ink); }


/* Toast progress bar — bottom edge of each card, drains left→right (timer) */
.ekklesia-toast__progress {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 3px;
    overflow: hidden;
}

.ekklesia-toast__progress-bar {
    height: 100%;
    background: var(--text-muted);
    opacity: 0.55;
    transform-origin: left;
    animation: ekt-countdown linear forwards;
}

.ekklesia-toast__progress-bar.is-paused { animation-play-state: paused; }

@keyframes ekt-countdown {
    from { width: 100%; }
    to { width: 0%; }
}

/* variant-tinted progress bars (ink tokens) */
.ekklesia-toast--accent .ekklesia-toast__progress-bar { background: var(--info-ink); }
.ekklesia-toast--success .ekklesia-toast__progress-bar { background: var(--success-ink); }
.ekklesia-toast--warning .ekklesia-toast__progress-bar { background: var(--warning-ink); }
.ekklesia-toast--danger .ekklesia-toast__progress-bar { background: var(--danger-ink); }

/* ═══ Rich Text Editor (Quill) — design-language flattening ═══
   quill.snow.css draws borders on toolbar + container; our rules replace
   them with surface separation only. */
.ql-toolbar.ql-snow {
    border: none !important;
    border-radius: 14px 14px 0 0;
    background: var(--bg-secondary);
    padding: 0.5rem 0.6rem;
}

.ql-container.ql-snow {
    border: none !important;
    border-radius: 0 0 14px 14px;
    background: var(--bg-card);
    font-family: inherit;
}

/* Editor sits as one soft surface: wrap toolbar+editor visual with shadow via container */
.ql-toolbar.ql-snow + .ql-container.ql-snow { margin-top: 2px; }

.ql-snow .ql-stroke { stroke: var(--text-secondary); }
.ql-snow .ql-fill { fill: var(--text-secondary); }
.ql-snow .ql-picker { color: var(--text-secondary); }
.ql-snow .ql-picker-options {
    background: var(--bg-card);
    border: none;
    border-radius: 12px;
    box-shadow: var(--shadow-md);
    padding: 0.4rem;
}
.ql-snow .ql-picker-item:hover { color: var(--primary-ink); }
.ql-snow.ql-toolbar button:hover .ql-stroke,
.ql-snow .ql-picker-label:hover { color: var(--primary-ink); }
.ql-snow.ql-toolbar button:hover .ql-fill { fill: var(--primary-ink); }
.ql-snow.ql-toolbar button.ql-active .ql-stroke { stroke: var(--primary-ink); }
.ql-snow .ql-picker-label.ql-active { color: var(--primary-ink); }
.ql-snow .ql-tooltip {
    background: var(--bg-card);
    border: none;
    border-radius: 12px;
    box-shadow: var(--shadow-md);
    color: var(--text-primary);
}
.ql-snow .ql-editor { color: var(--text-secondary); }
