/* ============================================
   REVIEW SYSTEM - PREMIUM UI
   ============================================
   Modern, glassmorphism-styled review dashboard
   Matches FairlyRemote premium design language
   ============================================ */

/* ============================================
   CSS CUSTOM PROPERTIES FOR REVIEW SYSTEM
   ============================================ */
:root {
    --review-card-bg: rgba(255, 255, 255, 0.85);
    --review-card-border: rgba(203, 213, 225, 0.5);
    --review-card-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
    --review-accent: var(--primary-500);
    --review-accent-light: var(--primary-50);

    /* Status tokens — anchored to STATUS_PRESENTATION
       (js/shared/event-status-utils.js). Keep these in sync. */
    --rc-status-available: #22c55e;  /* available */
    --rc-status-working:   #16a34a;  /* working */
    --rc-status-tentative: #f59e0b;  /* tentative */
    --rc-status-busy:      #dc2626;  /* busy / blocking */
    --rc-status-away:      #d946ef;  /* away / leave — fuchsia, distinct from sleep */

    /* Non-status accent: "attention required" (banners, action prompts).
       Distinct from --rc-status-tentative because the semantics differ —
       tentative = "this might happen"; attention = "you must do something".
       Keeps the orange-as-attention signal without being treated as drift
       in future status-color audits. */
    --rc-accent-attention:        #f97316;
    --rc-accent-attention-strong: #ea580c;

    /* CONFLICT RED (2026-08-15). The one red the conflict surfaces are
       allowed to paint: the overlap column, the panel's warning glyph and
       the count badge riding the Scheduled tab.
       Do NOT reach for var(--danger) here. On 2026-08-15 the owner split
       busy into two tokens (view-mode-strip.css): --shading-busy #dc2626 is
       the RED that busy TIME is shaded, while --status-busy is now SLATE
       #64748b for busy-visibility event blocks. --danger is still aliased to
       --status-busy, so it silently resolves to SLATE and a var(--danger)
       overlap band would have painted grey on a grey track: the warning
       would have disappeared. Anchor on --shading-busy, the canonical red. */
    --rc-conflict-red: var(--shading-busy, #dc2626);

    /* Legacy aliases — kept as deliberate semantic shortcuts after Stage C.
       They read more naturally at call sites ("border-color: var(--review-urgent)"
       conveys intent better than "border-color: var(--rc-status-busy)" on a
       deadline-warning border). Anchored to canonical tokens so a single
       palette change still propagates everywhere. */
    --review-urgent: var(--rc-status-busy);
    --review-urgent-light: rgba(220, 38, 38, 0.1);
    --review-warning: var(--rc-status-tentative);
    --review-warning-light: rgba(245, 158, 11, 0.1);
    --review-success: var(--rc-status-available);
    --review-success-light: rgba(34, 197, 94, 0.1);

    /* Design tokens — type scale & spacing */
    --rc-font-heading: 14px;
    --rc-font-body: 13px;
    --rc-font-secondary: 12px;
    --rc-font-caption: 11px;
    --rc-font-tiny: 10px;
    --rc-spacing-card: 10px; /* 12→10 (2026-07-12 densify): tighter card padding fits more per screen */
    --rc-spacing-section: 8px;
    --rc-spacing-inline: 6px;
    --rc-radius-card: 8px;
    --rc-radius-pill: 12px;
    --rc-radius-btn: 6px;
}

body.dark-mode {
    --review-card-bg: rgba(30, 41, 59, 0.85);
    --review-card-border: rgba(71, 85, 105, 0.5);
    --review-card-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}

/* ============================================
   REVIEW CENTER BUTTON RESET
   Override global .btn { flex: 1; min-height: 44px }
   so buttons size to their content inside the panel
   ============================================ */
.review-modal .btn,
.review-dashboard-content .btn {
    flex: 0 0 auto;
    min-height: unset;
    padding: 6px 14px;
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 600;
    border-radius: var(--rc-radius-btn, 6px);
}

/* Shared disabled state for every Review Center button. This is an
   action-heavy surface where handlers disable buttons in-flight (accept,
   submit-vote, schedule-winner, withdraw, undo…); without this they looked
   identical to enabled. Covers the bespoke action/vote/visibility buttons
   too, which aren't plain .btn. */
.review-dashboard-content .btn:disabled,
.review-dashboard-content .btn[disabled],
.review-dashboard-content button:disabled,
.synced-vis-btn:disabled,
.synced-sweep-btn:disabled,
.submit-vote-btn:disabled,
.accept-all-btn:disabled,
.schedule-winner-btn:disabled,
.rc-withdraw-btn:disabled,
.undo-accept-btn:disabled {
    opacity: 0.55;
    cursor: not-allowed;
    box-shadow: none;
}

/* IN-FLIGHT state. `disabled` above only dims a button; on the join-request
   buttons that dim covers two chained network hops plus a refetch, which read
   as "the button is dead" rather than "the work is running" (user 2026-08-22:
   "accepting or declining a request is slow, perhaps a loading ... visual
   response is necessary"). aria-busy is the trigger so the state is announced
   to assistive tech as well as drawn, matching .sync-action[aria-busy] in
   calendar-views.css.

   The spinner is an ::after and the label is untouched: .request-actions .btn
   is white-space:nowrap inside a flex row, so swapping the text for
   "Approving…" would resize the button and shift the row under the cursor.
   The busy button keeps FULL opacity — it is working, not unavailable — while
   its disabled siblings stay dimmed by the rule above.

   ⚠️Must out-specify that :disabled rule — a busy button IS disabled, so both
   match, and `cursor: not-allowed` won on source order (caught in the live
   render 2026-08-22: the working button read as a blocked one). The :disabled
   qualifier raises specificity to (0,3,1) so progress wins. */
.review-dashboard-content button[aria-busy="true"],
.review-dashboard-content button[aria-busy="true"]:disabled {
    position: relative;
    opacity: 1;
    cursor: progress;
}

.review-dashboard-content button[aria-busy="true"] > i,
.review-dashboard-content button[aria-busy="true"] > svg {
    visibility: hidden;
}

/* Sits over the hidden leading icon, so the button's width never changes. */
.review-dashboard-content button[aria-busy="true"]::after {
    content: '';
    position: absolute;
    left: 12px;
    top: 50%;
    width: 12px;
    height: 12px;
    margin-top: -6px;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: spin 0.6s linear infinite;
}

/* Buttons with no leading icon (the spinner would otherwise overlap the label):
   centre it and hide the text instead. */
.review-dashboard-content button[aria-busy="true"].rc-busy-center {
    color: transparent;
}

.review-dashboard-content button[aria-busy="true"].rc-busy-center::after {
    left: 50%;
    margin-left: -6px;
    border-color: var(--text-secondary, #64748b);
    border-right-color: transparent;
}

@media (prefers-reduced-motion: reduce) {
    /* Keep the affordance, drop the motion — a static ring still marks the
       button as busy for anyone who has asked the OS for less animation. */
    .review-dashboard-content button[aria-busy="true"]::after {
        animation: none;
        opacity: 0.6;
    }
}

/* ============================================
   COARSE-POINTER TAP-FLOOR EXEMPTION
   The global WCAG floor (style.css ~975 + responsive.css ~382) slaps
   min-width:44px; min-height:44px on every <button>/[role=button]/.chip
   on touch devices. Inside the Review Center that floor inflates a whole
   family of intentionally-tiny inline controls into 44px boxes, and
   because several of them set width/height but no min-height, the floor
   distorts them into tall ovals (e.g. the 26x26 rank circle became 26x44).
   This is invisible under desktop emulation, so it only shows on a real
   phone. Mirror the existing team-status-bar exemption (style.css ~988):
   release the floor for these specific small controls; genuine tap targets
   (action buttons, the main tabs, sub-tabs) keep the 44px floor. */
@media (hover: none) and (pointer: coarse) {
    /* The rank circle is a true square indicator — collapse it fully to its
       intrinsic size so the 44px floor stops stretching it into a tall oval. */
    .review-modal .rank-circle,
    #review-dashboard-modal .rank-circle {
        min-width: 0 !important;
        min-height: 0 !important;
    }

    /* The inline X controls (mark-unavailable, dismiss batch tip, clear search)
       were also collapsed to 0, leaving 22px tap targets a thumb keeps missing.
       Keep the 44px-WIDTH floor released (it broke the inline rows) but give
       them a comfortable 32px tap HEIGHT, matching the chip row below. */
    .review-modal .rc-batch-tip-close,
    .review-modal .rc-search-clear,
    #review-dashboard-modal .rc-batch-tip-close,
    #review-dashboard-modal .rc-search-clear {
        min-width: 0 !important;
        min-height: 32px !important;
    }

    /* Inline pill/segment controls that still want a comfortable tap height
       but must not be forced to a 44px *width* (which broke the chip rows). */
    .review-modal .privacy-filter-chip,
    .review-modal .rc-triage-seg,
    .review-modal .btn-xs,
    .review-modal .conflict-action-btn,
    #review-dashboard-modal .privacy-filter-chip,
    #review-dashboard-modal .rc-triage-seg,
    #review-dashboard-modal .btn-xs,
    #review-dashboard-modal .conflict-action-btn {
        min-width: 0 !important;
        min-height: 32px !important;
    }

    /* The ⋮ "more actions" button is the ONLY path to Tentative / Delegate;
       its 36px box is below the comfortable touch floor. It is a genuine tap
       target (not an inline micro-control), so give it the full 44px. */
    .review-modal .more-options-btn,
    #review-dashboard-modal .more-options-btn {
        min-width: 44px !important;
        min-height: 44px !important;
    }

    /* Main tabs + sub-tabs are the primary navigation; they get a 44px floor
       in the ≤480 block, but the 481–768 coarse range (tablets, landscape
       phones) fell between the ≤480 rule and the pointer-keyed exemption and
       got neither. Key the floor to the pointer so every touch device matches. */
    .review-tab {
        min-height: 44px;
        padding: 10px 14px;
    }
    .review-sub-tabs .sub-tab {
        min-height: 44px;
        padding: 10px 14px;
    }
}

/* ============================================
   SHARED CARD LAYOUT UTILITIES (rc-*)
   Reusable layout classes for consistent card
   structure across all Review Center tabs
   ============================================ */

/* Card header — flex column container for title/meta/status rows */
.rc-card-header {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: var(--rc-spacing-section);
}

/* Title row — badge + title LEFT, key info RIGHT */
.rc-title-row {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

/* Right-aligned zone in title row */
.rc-title-right {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-left: auto;
    flex-shrink: 0;
    white-space: nowrap;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
}

/* Meta line — dot-separated items LEFT, counts/badges RIGHT */
.rc-meta-line {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
}

.rc-meta-line > span {
    white-space: nowrap;
}

.rc-meta-line > span:not(:last-child):not(.rc-meta-right)::after {
    content: "\00B7";
    margin: 0 6px;
    color: var(--slate-300);
}

/* Right-aligned zone in meta line. Wraps cleanly on narrow widths —
   trust + quota fall onto a second row instead of overflowing the card. */
.rc-meta-right {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-left: auto;
    flex-wrap: wrap;
    row-gap: 4px;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
}

.rc-meta-right > span {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

/* Location folded inline into the meta line (2026-07-12 densify — was its own
   .rc-location-line row). Caps its width + ellipsises so a long venue degrades
   gracefully instead of shoving the trust chip off the row. The full location
   still lives in the "see details" panel (hasCardDetails includes item.location). */
.rc-meta-location {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    max-width: 40%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.rc-meta-location i { color: var(--slate-400, #94a3b8); font-size: 11px; }

/* Status line — auto-accept countdown · "Pending your review".
   Uses gap-based separators (not &middot;) so wrap doesn't strand a dot. */
.rc-status-line {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px 10px;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-600);
    /* padding 2px 0 → 0 (2026-07-12 densify): the row-gap on the card body
       already spaces this row; the extra 2px top/bottom just added height. */
    padding: 0;
}

/* A1 — conflict line: the recipient is double-booked at this time.
   Uses the canonical busy token (not a raw hex) so the traffic-light red
   stays consistent across the surface. */
.rc-conflict-line {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--rc-status-busy, #dc2626);
    font-weight: 600;
}
.rc-conflict-line i { font-size: 11px; }

/* Compact conflict chip on the card face: signals THAT a clash exists (the
   decision-critical part) without spelling out the events — that detail lives
   in the disclosure panel. Keeps the canonical busy hue so the semantic is
   intact, but reads as a small count, not a full alarm. */
.rc-conflict-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    color: var(--rc-status-busy, #dc2626);
    background: color-mix(in srgb, var(--rc-status-busy, #dc2626) 10%, transparent);
}
.rc-conflict-chip i { font-size: 10px; }
body.dark-mode .rc-conflict-chip {
    color: #f87171;
    background: color-mix(in srgb, #f87171 16%, transparent);
}

/* A4 — leave coverage: teammates already away. Informational, amber. */
.rc-coverage-line {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: var(--rc-status-tentative, #f59e0b);
    font-weight: 600;
}
.rc-coverage-line i { font-size: 11px; }

/* Tier 2 — the running off-hours cost of accepting, for the recipient. Amber
   (accommodation hue), distinct from the busy-red conflict line. */
.rc-fairness-consequence {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    color: #b45309;
    font-weight: 600;
}
.rc-fairness-consequence i { font-size: 11px; color: var(--rc-status-tentative, #f59e0b); }

body.dark-mode .rc-conflict-line { color: #f87171; }
body.dark-mode .rc-coverage-line { color: #fbbf24; }
body.dark-mode .rc-fairness-consequence { color: #fbbf24; }

/* Location line — icon + address */
.rc-location-line {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
}

.rc-location-line i {
    font-size: 10px;
    color: var(--slate-400);
}

/* Actions bar — secondary LEFT, primary RIGHT */
.rc-actions-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding-top: var(--rc-spacing-section);
    border-top: 1px solid var(--slate-200);
}

/* Dark mode overrides for shared classes */
body.dark-mode .rc-title-right {
    color: var(--slate-400);
}

body.dark-mode .rc-meta-line {
    color: var(--slate-400);
}

body.dark-mode .rc-meta-line > span:not(:last-child):not(.rc-meta-right)::after {
    color: var(--slate-600);
}

body.dark-mode .rc-meta-right {
    color: var(--slate-400);
}

body.dark-mode .rc-status-line {
    color: var(--slate-400);
}

body.dark-mode .rc-location-line {
    color: var(--slate-400);
}

body.dark-mode .rc-location-line i {
    color: var(--slate-500);
}

body.dark-mode .rc-actions-bar {
    border-top-color: var(--slate-600);
}

/* ============================================
   REVIEW PILL (Calendar Row)
   Single pill with label and notification icons
   ============================================ */
.review-icons-wrapper {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    height: 44px;
    padding: 4px 10px;
    /* 2026-07-23 (user: "the review center indicators in the main area sometimes
       fall downwards due to width"). The conflict ⚠ and urgent-deadline 🕑 icons
       are hidden at rest and appear INLINE in the icon row only when there's
       something to flag — each adds ~26px, swinging this pill 121px → up to 162px.
       In the already-tight .proposer-calendar-row (nowrap, shrinkable siblings)
       that surge was enough to bump a neighbour onto a second line. Reserve the
       worst-case footprint (conflict w/ 2-digit count + urgent icon + 4 tabs) so
       the pill's width is CONSTANT regardless of alert state — the centred header
       + row just fill the reserved slot when alerts light up, and never perturb
       the toolbar. flex-shrink:0 so a crowded row can't squeeze it either. Mobile
       lays this out as a compact row-chip with its own intrinsic width + shrink
       guard (style.css ~9112), so it's reset to width:auto there. */
    /* 2026-07-27 (user: "the review center button needs a little perfecting
       regarding space, make it look more designed like the mobile one").
       MEASURED on desktop (1283px): worst case (both alert icons
       forced visible) renders at 163px, the resting pill at 122px. So 162px was
       NOT over-reserved — it is genuinely the alert-state width, and shrinking
       it would clip an alert. The slack at rest is inherent to reserving a
       constant slot, so the honest fix is to tighten the INTERNAL rhythm (label
       size, symmetric padding) rather than the outer box. 162 → 163 so the
       worst case fits exactly instead of losing a subpixel. */
    width: 163px;
    flex-shrink: 0;
    background: linear-gradient(135deg, rgba(148, 163, 184, 0.08) 0%, rgba(148, 163, 184, 0.04) 100%);
    border: 1px solid var(--slate-200);
    border-radius: var(--radius-lg);
    transition: all var(--transition-base);
}

.review-icons-wrapper:hover {
    background: linear-gradient(135deg, rgba(148, 163, 184, 0.12) 0%, rgba(148, 163, 184, 0.06) 100%);
}

/* Traffic light color coding: 1+ green, 5+ amber, 10+ red
   Tokens come from STATUS_PRESENTATION (available/tentative/busy). */
.review-icons-wrapper.level-green {
    border-color: var(--rc-status-available);
    box-shadow: 0 0 0 1px rgba(34, 197, 94, 0.2);
}

.review-icons-wrapper.level-amber {
    border-color: var(--rc-status-tentative);
    box-shadow: 0 0 0 1px rgba(245, 158, 11, 0.2);
}

.review-icons-wrapper.level-red {
    border-color: var(--rc-status-busy);
    box-shadow: 0 0 0 1px rgba(220, 38, 38, 0.2);
}

.review-icons-wrapper.level-green:hover { border-color: var(--rc-status-working); }
.review-icons-wrapper.level-amber:hover { border-color: var(--rc-status-tentative); }
.review-icons-wrapper.level-red:hover { border-color: var(--rc-status-busy); }

.review-icons-header {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    width: 100%;
    padding: 0 1px;
    padding-left: 6px;
}

.review-icons-label {
    /* 0.5rem (8px) was below the practical floor for uppercase tracked text —
       it read as a grey smudge rather than a label, which is a big part of why
       the desktop pill looked less designed than the mobile chip. 0.625rem
       (10px) is legible while still clearly subordinate to the icon row, and
       the pill has vertical room for it inside its fixed 44px height.
       (2026-07-27) */
    font-size: 0.625rem;
    font-weight: 600;
    color: var(--slate-500);
    text-transform: uppercase;
    letter-spacing: 0.4px;
    line-height: 1;
}

/* Conflict icon — header-level alert. Hidden at rest: it only appears
   when there's a real conflict to resolve, and when it appears it always
   carries its count badge (so it's never a bare, numberless triangle).
   Sits in the header strip next to the urgent-deadline icon, NOT inline
   with the four tab icons below (those are queue surfaces; this is a
   cross-cutting alert that spans the panel). */
.review-conflict-icon {
    /* Hidden at rest — JS adds .has-items (display:inline-flex) only when
       conflictCount > 0. A zero count means no icon at all. */
    display: none;
    align-items: center;
    justify-content: center;
    color: var(--slate-400, #94a3b8);
    font-size: 0.7rem;
    /* No leading margin (2026-07-04, user: "reduce the inner white space on the
       left on the desktop"). The conflict icon is the LEADING item in the
       centre-justified .review-icons-row; a margin-left here shifted the whole
       chip group right, leaving ~6px more inner whitespace on the LEFT of the
       pill than on the right (measured 17px left vs 11px right). Dropping it
       balances the row (11px each side). The 4px row `gap` still separates the
       conflict icon from the next tab icon, so they don't touch. */
    margin-left: 0;
    cursor: pointer;
    position: relative;
    transition: transform 0.15s ease, color 0.15s ease;
    /* DESKTOP: give the icon the SAME 22px box as the four tab buttons
       (.review-icon-btn, ~618). Without a fixed box this span shrink-wraps the
       ~11px triangle glyph, so the position:absolute count badge (anchored
       bottom:0; right:-3px below) lands directly ON TOP of the glyph instead of
       offset into the corner like the tab badges do (user 2026-06-26: "the
       conflict icon count is on the icon"). The 22px box pushes the badge's
       bottom-right anchor clear of the centred glyph — same corner offset as the
       tabs — making the alert consistent with the row it sits in. The glyph stays
       centred via align-items/justify-content:center. (The coarse/≤768px block
       overrides this back to a column for the mobile under-count layout.) */
    width: 22px;
    height: 22px;
}

.review-conflict-icon.has-items {
    display: inline-flex;
    color: var(--rc-status-busy);
}

/* SAME SHAPE AS ITS NEIGHBOURS (2026-08-16, user: "make the tab more
   beautiful. warning icon with text comparative to others when selected. the
   red seems too big").
   From the screenshot: a solid ~46px red DISC swallowing the ⚠ and its count,
   sitting inside the Events tab and crushing its label to "E…", while the
   sibling counts (2 / 1 / 4) are small tinted pills. The desktop badge idiom
   was never meant to be read at that scale on a phone.
   Make it a chip in the same family as the others: a soft red tint, red ink,
   the glyph and the number on ONE line, sized to the row rather than to a
   22px box that forces the count into a corner. */
.review-conflict-icon.has-items {
    width: auto;
    height: auto;
    gap: 4px;
    padding: 2px 7px;
    border-radius: var(--radius-full, 9999px);
    background: color-mix(in srgb, var(--rc-status-busy, #dc2626) 12%, transparent);
    font-size: 0.6875rem;
    line-height: 1.2;
}

.review-conflict-icon.has-items .review-conflict-count {
    /* In flow beside the glyph — not an absolutely-positioned corner badge, so
       nothing needs a fixed box to anchor against and nothing can land on top
       of the triangle. */
    position: static;
    inset: auto;
    margin: 0;
    min-width: 0;
    height: auto;
    padding: 0;
    background: none;
    box-shadow: none;
    color: inherit;
    font-size: inherit;
    font-weight: 700;
}
body.dark-mode .review-conflict-icon.has-items {
    background: rgba(248, 113, 113, 0.16);
    color: #f87171;
}

/* ⚠️PHONE ROW: NO PILL. The chip above assumes ONE line (its 2px/7px padding is
   sized for a glyph and digit side by side), but on the phone toolbar
   style.css forces this element to flex-direction:column — deliberately, so the
   digit lands on the same line as the four tab buttons' under-glyph counts.
   Those two intents are incompatible, and the column wins on mobile: the pill
   ended up wrapped around TWO stacked rows, so it rendered as a 25x26 near
   square (aspect 0.96 — the "red circle" shape again, just tinted) with the
   count spilling 2px BELOW its own background. Measured at 390px/dpr2, 08-23.

   The row's own idiom for a count is a flat coloured digit under the glyph with
   no chrome (see the coarse ≤640px rule further down, which already strips the
   count's pill). So strip the container's pill too and let the glyph + digit
   read as a column, consistent with its four neighbours. The red ink alone
   marks the alert — which is what "the red seems too big" asked for. */
@media (max-width: 640px) {
    .review-conflict-icon.has-items,
    /* Dark mode sets its own tint on .has-items at a higher specificity, so it
       has to be named here or the pill comes back on dark phones only. */
    body.dark-mode .review-conflict-icon.has-items {
        padding: 0;
        border-radius: 0;
        background: none;
        gap: 0;
    }
}

/* Count badge — DESKTOP: matched to the tab-icon badge (.review-icon-badge, ~566)
   idiom so the conflict alert is visually CONSISTENT with the four queue-tab badges
   in the same row: bottom-anchored "under" the glyph, pill radius, soft shadow, same
   size/weight. (Was top-anchored, radius:6px, no shadow — out of step with the row.)
   The badge is position:absolute against .review-conflict-icon (position:relative). */
.review-conflict-icon .review-conflict-count {
    position: absolute;
    bottom: 0px;
    right: -3px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 12px;
    height: 12px;
    padding: 0 2px;
    border-radius: var(--radius-full);
    background: var(--rc-status-busy, #dc2626);
    color: #fff;
    font-size: 0.5rem;
    font-weight: 700;
    line-height: 1;
    text-align: center;
    box-sizing: border-box;
    pointer-events: none;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
    animation: badgePop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
body.dark-mode .review-conflict-icon .review-conflict-count {
    background: #ef4444;
}

/* ============================================================================
   ALERT DOT — folded-in conflict / deadline signal (2026-07-23)
   ============================================================================
   Replaces the separate inline ⚠ conflict + 🕒 deadline icons, which were
   display:none→inline-flex and so ADDED ~22px to the Review cluster the instant
   an alert appeared — breaking the toolbar row (user: "no space when there's a
   conflict"). This dot lives permanently in the DOM at the top-LEFT corner of the
   Scheduled tab icon (the bottom-right corner holds the pending-count badge, so
   they never collide) and only toggles VISIBILITY via .has-alert. Because it's
   absolutely positioned inside the already-22px tab button, it changes the
   cluster width by ZERO whether lit or dark — the whole point of the change.
   Red (.is-conflict) = a scheduling conflict; amber = deadline-only. */
/* NO DOT (2026-08-16, user: "I dont like the red dot on review center also.
   remove and consider either bundling with the event notifications or changing
   the icon of events to red itself of conflicts").
   Taking the second option: the GLYPH carries the alert, so the signal
   survives without adding a separate mark to a row that already rejects dots
   (its sibling .review-icon-alert-count was retired for the same reason).
   The element stays in the DOM because the click router keys the
   conflicts-panel route off `.is-conflict` — it simply paints nothing now. */
.review-icon-alert-dot {
    display: none;
}

/* The alert lives on the icon itself. Amber = a deadline wants attention;
   red = an actual scheduling conflict, which is one of the few places red is
   correct (conflicts/danger), per the busy-is-slate split. */
#review-icon-scheduled.has-alert i {
    color: var(--rc-status-tentative, #f59e0b);
}
#review-icon-scheduled.has-alert:has(.review-icon-alert-dot.is-conflict) i {
    color: var(--rc-status-busy, #dc2626);
}
body.dark-mode #review-icon-scheduled.has-alert:has(.review-icon-alert-dot.is-conflict) i {
    color: #ef4444;
}

/* Coarse-pointer / phone: on a phone the four tab counts are NOT pills — they render
   as static, transparent-background, under-glyph hue-coloured text (style.css ~8340,
   `.proposer-calendar-row .review-icon-btn .review-icon-badge` inside @media
   max-width:640px). To be CONSISTENT with that row on mobile, the conflict count reads
   the same way: a flat red number tucked in the lower band of the icon's 26px box (the
   box gets align-items:flex-start on mobile so the glyph rides up top, leaving that
   band — style.css ~8551). KEEP bottom-anchoring (do NOT re-anchor to top — a pill on
   top would be the opposite of the row) and drop the pill chrome: flat red text, no
   fill/shadow/radius, a touch larger for legibility. The desktop .review-icon-badge
   coarse rule re-anchors to TOP only because its 44px touch target pushes a bottom
   badge off-frame; the conflict count is not inside that touch target, so bottom on the
   26px box is safe and is exactly where the tab numbers sit. */
/* Width-gated to ≤640px (added 2026-06-26): this static-flow restyle ASSUMES the
   icon is the flex COLUMN created only inside the @media(max-width:640px) block
   (flex-direction:column + align-items:flex-start in style.css ~8636, which puts
   the glyph on top and leaves the band below for the digit). On a coarse-pointer
   device at a WIDE viewport — a phone with "Request desktop site" on, or a tablet
   — that ≤640px column layout does NOT apply, so the icon stays a ROW; making the
   count position:static there flowed the digit INLINE beside the ⚠ instead of
   beneath it, mis-seating it vs the tab numbers (user 2026-06-26: "conflict
   indicator and other icons broken on the desktop view in mobile … misaligned").
   Requiring max-width:640px keeps this restyle paired with the column layout it
   depends on; wide touch viewports keep the self-consistent desktop pill badge. */
@media (hover: none) and (pointer: coarse) and (max-width: 640px) {
  .review-conflict-icon .review-conflict-count {
    /* Lay the conflict count out the SAME WAY as the four tab counts on mobile
       (user 2026-06-26: "conflict icon and digits in review button seem slightly
       wrongly aligned"). The tab badges (style.css ~8360,
       .proposer-calendar-row .review-icon-btn .review-icon-badge) are position:STATIC
       + margin-top:1px — they FLOW under the glyph, centred in the column. The
       conflict count was position:absolute; bottom:1px; right:-2px, so it sat a hair
       low AND shifted right of centre vs the tab numbers. Match the tabs exactly:
       static flow, centred, same margin-top / size / weight / line-height. The icon's
       inline-flex column (align-items:flex-start + padding-top:2px on the parent) puts
       the glyph on top; this number then sits beneath it like the tabs. */
    position: static;
    top: auto;
    right: auto;
    bottom: auto;
    left: auto;
    margin-top: 1px;
    min-width: 0;
    height: auto;
    padding: 0;
    font-size: 0.625rem;
    font-weight: 800;
    /* MATCH THE TAB NUMBERS' FONT (user 2026-06-26: "conflict digits still seem too
       bold compared to the other digits"). The four tab counts live inside <button>
       elements, which the UA renders in its default Arial — so the tab numbers are
       Arial 800. The conflict ⚠ is a <span>, so it inherited the app's Inter from
       .review-icons-row, and Inter@800 reads visibly HEAVIER than Arial@800. Pin the
       conflict count to the same Arial stack so the five numbers read identically. */
    font-family: Arial, sans-serif;
    line-height: 1;
    background: transparent;
    color: var(--rc-status-busy, #dc2626);
    border-radius: 0;
    box-shadow: none;
  }
  body.dark-mode .review-conflict-icon .review-conflict-count {
    background: transparent;
    color: #ef4444;
  }
}

.review-conflict-icon.has-items i {
    /* Softened 2026-06-25 (user: "the conflict warning number seems bolder than the
       other review center button indicators"). The font-weights already match the row
       (count 700 desktop / 800 mobile = the tab badges; icons 900), so the extra
       "heaviness" came from this red drop-shadow HALO around the ⚠ — no other tab icon
       has one, so the conflict indicator bloomed heavier than its neighbours. Cut the
       glow radius + alpha right down so the icon reads at the same weight as the rest;
       the red hue alone already marks it as the alert. */
    filter: drop-shadow(0 0 1px rgba(220, 38, 38, 0.35));
}

.review-conflict-icon:hover {
    transform: scale(1.25);
}

.review-conflict-icon.has-items:hover {
    color: #b91c1c;
}

body.dark-mode .review-conflict-icon {
    color: var(--slate-500, #64748b);
}

body.dark-mode .review-conflict-icon.has-items {
    color: #f87171;
}

body.dark-mode .review-conflict-icon.has-items:hover {
    color: #fca5a5;
}

/* Urgent icon - AMBER, subtle, deadline warnings (ignorable) */
.review-urgent-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Amber-700 is a darker variant of --rc-status-tentative;
       keep hardcoded — no canonical -strong token yet. */
    color: #d97706;
    font-size: 0.55rem;
    margin-left: 2px;
    opacity: 0.8;
    cursor: pointer;
    transition: transform 0.15s ease, opacity 0.15s ease, color 0.15s ease;
}

.review-urgent-icon:hover {
    transform: scale(1.25);
    opacity: 1;
    color: #b45309;
}

.review-urgent-icon i {
    filter: drop-shadow(0 0 1px rgba(217, 119, 6, 0.3));
}

body.dark-mode .review-urgent-icon {
    color: #fbbf24;
    opacity: 0.7;
}

body.dark-mode .review-urgent-icon:hover {
    color: #fcd34d;
    opacity: 1;
}

.review-total-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 16px;
    padding: 0 6px;
    margin-left: 4px;
    margin-right: 1px;
    font-size: 0.55rem;
    font-weight: 700;
    color: var(--primary-600);
    background: white;
    border-radius: 10px;
    line-height: 1;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

.review-icons-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
}

.review-icon-btn {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: all var(--transition-fast);
}

.review-icon-btn i {
    font-size: 0.75rem;
    transition: all var(--transition-fast);
}

/* ── MOBILE-DESKTOP MODE (coarse pointer, 641–768px wide) — TOP-ANCHOR the icons
   ───────────────────────────────────────────────────────────────────────────
   2026-06-26 (user: "the icons don't sit at the top like they should" in mobile
   desktop mode). At 641–768px coarse the WCAG touch floor (style.css ~60778)
   makes .review-icon-btn 44px tall and lays it out flex-direction:column, and
   style.css:60785 INTENDS justify-content:flex-start to seat the glyph+count at
   the top. But the base .review-icon-btn rule above (justify-content:center,
   same 0,1,0 specificity) loses that tie only on SOURCE ORDER — and review-
   inbox.css loads AFTER style.css, so the base center wins and the glyph floats
   in the middle of the 44px box. Re-assert the top-anchor HERE (last word in the
   later file) for exactly the coarse-wide range. NOT ≤640 (the phone keeps its
   own .proposer-calendar-row 28px-pill treatment, style.css ~8452) and NOT fine-
   pointer desktop (the centred 22px chip is correct there). The "REVIEW" text
   label + header stay visible and seated at the top of the column — kept, not
   removed (user clarified "the label should go higher, not omit … we have enough
   vertical space"); the wrapper's column layout already puts the header above the
   icon row, and top-anchoring the icons tightens the whole cluster upward. */
@media (hover: none) and (pointer: coarse) and (min-width: 641px) {
    .review-icon-btn {
        /* Icons back to vertically centred within their box. The earlier
           flex-start + padding-top:3px top-seated them, but combined with the
           flex-start wrapper below that read as "the Review text sits too high"
           on desktop-mode-viewed-on-mobile (user 2026-07-06). Centre is the
           balanced seat. */
        justify-content: center;
    }
    /* Centre the stacked cluster (label/header + icon row) in the 44px pill so
       the spare vertical space splits evenly above and below, rather than the
       whole cluster jammed against the top edge. */
    .review-icons-wrapper {
        justify-content: center;
    }
}

.review-icon-btn:hover {
    background: rgba(255, 255, 255, 0.5);
}

.review-icon-btn:active {
}

/* Badge overlay positioned bottom-right - offset to not obscure icon */
.review-icon-badge {
    position: absolute;
    bottom: 0px;
    right: -3px;
    display: none;
    align-items: center;
    justify-content: center;
    min-width: 12px;
    height: 12px;
    padding: 0 2px;
    font-size: 0.5rem;
    font-weight: 700;
    line-height: 1;
    color: white;
    border-radius: var(--radius-full);
    pointer-events: none;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

/* Coarse-pointer / phone: make the count figure bigger and legible — the 12px
   0.5rem desktop badge reads as an unlabelled dot on a phone (user 2026-06-18:
   "review center is also missing its figures"). Slightly larger min-width +
   font so the number is actually readable at the row's 36px mobile height.

   Anchor to the TOP-right, not the bottom. The mobile touch-target floor
   (style.css: .review-icon-btn min-height:44px under coarse/≤768px) makes the
   button box taller than the centred icon glyph and stretches it to the very
   bottom edge of the rounded Review frame. A bottom-anchored badge then hangs
   below that frame and gets clipped by its border (user 2026-06-18: counts
   "no longer show on mobile" — they'd drifted off the bottom edge). Pinning to
   the top keeps the figure over the icon's upper corner, safely inside the
   frame, with headroom from the alert/header row above. */
@media (hover: none) and (pointer: coarse) {
  .review-icon-badge {
    min-width: 15px;
    height: 15px;
    font-size: 0.62rem;
    top: -2px;
    bottom: auto;
    right: -5px;
  }
}

.review-icon-badge.visible {
    display: inline-flex;
    animation: badgePop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes badgePop {
    0% { transform: scale(0); }
    70% { transform: scale(1.15); }
    100% { transform: scale(1); }
}

/* Color themes matching Review Center tabs (kept in lockstep with the dashboard
   TABS hues: scheduled=teal #14b8a6, proposals=blue #3b82f6). The old amber/
   violet drifted from the tabs they jump to. The legacy amber/violet selectors
   are kept as aliases so any stale class still paints the right hue. */
/* Teal - Scheduled (was amber) */
.review-icon-btn.review-icon-teal i,
.review-icon-btn.review-icon-amber i { color: #14b8a6; }
.review-icon-btn.review-icon-teal .review-icon-badge,
.review-icon-btn.review-icon-amber .review-icon-badge { background: #14b8a6; }
.review-icon-btn.review-icon-teal:hover i,
.review-icon-btn.review-icon-amber:hover i { color: #0d9488; }

/* Blue - Proposals (was violet) */
.review-icon-btn.review-icon-blue i,
.review-icon-btn.review-icon-violet i { color: #3b82f6; }
.review-icon-btn.review-icon-blue .review-icon-badge,
.review-icon-btn.review-icon-violet .review-icon-badge { background: #3b82f6; }
.review-icon-btn.review-icon-blue:hover i,
.review-icon-btn.review-icon-violet:hover i { color: #2563eb; }

/* Emerald - Requested/Outgoing */
.review-icon-btn.review-icon-emerald i { color: #10b981; }
.review-icon-btn.review-icon-emerald .review-icon-badge { background: #10b981; }
.review-icon-btn.review-icon-emerald:hover i { color: #059669; }

/* Cyan - retired (was Publish, then the old cyan Privacy tab). Kept as an
   alias painting the current Privacy purple so any stale class still lands
   near the right identity. */
.review-icon-btn.review-icon-cyan i { color: #8b5cf6; }
.review-icon-btn.review-icon-cyan .review-icon-badge { background: #8b5cf6; }
.review-icon-btn.review-icon-cyan:hover i { color: #7c3aed; }

/* Purple - Privacy (2026-08-04 identity unification). Purple is the app-wide
   privacy hue (privacy-visual-config.js). Replaces the old amber fa-inbox
   "Incoming" slot, whose colour+glyph matched nothing inside the dashboard. */
.review-icon-btn.review-icon-purple i { color: #8b5cf6; }
.review-icon-btn.review-icon-purple .review-icon-badge { background: #8b5cf6; }
.review-icon-btn.review-icon-purple:hover i { color: #7c3aed; }
body.dark-mode .review-icon-btn.review-icon-purple i { color: #a78bfa; }

/* Indigo - Requests (join requests). Deliberately not the `.review-icon-violet`
   legacy class: that one is an alias kept pointing at the Proposals blue
   (#3b82f6, see above), so reusing it would have painted Requests identically
   to Proposals. Also deliberately NOT #7c3aed — that violet is a reserved
   STATUS_PRESENTATION hue (deep sleep) locked by the canonical-shading
   ratchet, and a category icon must not paint a status colour.
   (Requests wore the `purple` class name until 2026-08-04; the class was
   renamed to match its actual hue when Privacy claimed real purple.) */
.review-icon-btn.review-icon-indigo i { color: #6366f1; }
.review-icon-btn.review-icon-indigo .review-icon-badge { background: #6366f1; }
.review-icon-btn.review-icon-indigo:hover i { color: #4f46e5; }
body.dark-mode .review-icon-btn.review-icon-indigo i { color: #a5b4fc; }

/* ---- Phone overflow chip (2026-07-30) ------------------------------------
   A phone toolbar cannot seat five 28px category icons plus the 26px conflict
   alert (~186px at the 4px gap). updateBadges() keeps the three most pressing
   categories and rolls the rest into this "+N" chip, so the remainder is still
   STATED rather than silently dropped. Always in the DOM; revealed by .visible
   only on a phone, and only when the hidden categories actually carry items. */
.review-overflow-chip {
    display: none;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    height: 26px;
    padding: 0 6px;
    font-size: 0.68rem;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    line-height: 1;
    color: var(--slate-600, #475569);
    background: var(--slate-100, #f1f5f9);
    border: 1px solid var(--slate-200, #e2e8f0);
    border-radius: var(--radius-full, 9999px);
    cursor: pointer;
    font-family: inherit;
}
.review-overflow-chip.visible { display: inline-flex; }
.review-overflow-chip:hover {
    color: var(--slate-800, #1e293b);
    border-color: var(--slate-300, #cbd5e1);
}
body.dark-mode .review-overflow-chip {
    color: var(--slate-300, #cbd5e1);
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
}
/* Categories that lost their slot. display:none (not visibility:hidden)
   because the whole point is to reclaim their WIDTH — a hidden-but-laid-out
   icon would defeat the exercise. */
.review-icon-btn.rc-icon-slotted-out { display: none !important; }

/* Urgency-based badge backgrounds (override category colors)
   Tokens come from STATUS_PRESENTATION. */
.review-icon-badge.urgency-green {
    background: var(--rc-status-available) !important;
}

/* The urgency colour on the badge IS the signal; the pop animation cues that
   the count changed. The extra glow ring was a third layer on the same badge,
   so it's gone — the coloured fill carries urgency on its own. */
.review-icon-badge.urgency-amber {
    background: var(--rc-status-tentative) !important;
    animation: badgePop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.review-icon-badge.urgency-red {
    background: var(--rc-status-busy) !important;
    animation: badgePop 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Dark Mode */
body.dark-mode .review-icons-wrapper {
    background: linear-gradient(135deg, rgba(51, 65, 85, 0.5) 0%, rgba(51, 65, 85, 0.3) 100%);
    border-color: var(--slate-600);
}

body.dark-mode .review-icons-wrapper:hover {
    background: linear-gradient(135deg, rgba(51, 65, 85, 0.6) 0%, rgba(51, 65, 85, 0.4) 100%);
    border-color: var(--slate-500);
}

body.dark-mode .review-icons-label {
    color: var(--slate-300);
}

body.dark-mode .review-total-count {
    color: var(--primary-400);
    background: var(--slate-700);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

body.dark-mode .review-icon-btn:hover {
    background: rgba(255, 255, 255, 0.1);
}

body.dark-mode .review-icon-btn.review-icon-teal i,
body.dark-mode .review-icon-btn.review-icon-amber i { color: #2dd4bf; }
body.dark-mode .review-icon-btn.review-icon-blue i,
body.dark-mode .review-icon-btn.review-icon-violet i { color: #60a5fa; }
body.dark-mode .review-icon-btn.review-icon-cyan i { color: #a78bfa; }
body.dark-mode .review-icon-btn.review-icon-emerald i { color: #34d399; }

/* ============================================
   REVIEW MODAL - FULL-SCREEN PREMIUM CONTAINER
   ============================================ */
.review-modal .modal-content {
    /* Full-bleed review surface: the modal earns its size with data, not chrome.
       Wider + taller than the old 1400px/94vh so the queue gets the room. */
    max-width: min(1600px, 96vw);
    width: 96%;
    min-height: 70vh;
    max-height: 96vh;
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.98) 0%, rgba(248, 250, 252, 0.98) 100%);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border: 1px solid rgba(203, 213, 225, 0.4);
    border-radius: var(--radius-2xl);
    box-shadow: var(--shadow-xl);
    overflow: hidden;
    padding: 0;
    display: flex;
    flex-direction: column;
}

/* Old modal-header is removed from HTML; hide if still present */
.review-modal .modal-header {
    display: none;
}

/* ============================================
   INTEGRATED DASHBOARD HEADER (rendered by JS)
   ============================================ */
/* ============================================
   REVIEW CENTER HEADER
   ============================================
   Clean modal-header style matching other modals
   (Propose, Event, Insights).
   ============================================ */
.review-dashboard-header {
    display: flex;
    align-items: center;
    gap: 10px;
    /* Phase D: the header scrolls away now, so its only job is to orient the
       user at the top — slimmed 12/10 → 8/8 vertical pad + removed the bottom
       border (the sticky bar below carries its own divider once scrolled), so
       the band is ~14px shorter and the tab bar sits right beneath it. */
    padding: 8px 20px;
    flex-shrink: 0;
    background: var(--surface-primary, #fff);
    position: relative;
}

.review-dashboard-header::before {
    display: none;
}

.review-dashboard-header .rdh-title {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--slate-800, #1e293b);
    letter-spacing: -0.01em;
    margin: 0;
    white-space: nowrap;
}

.review-dashboard-header .rdh-title i {
    font-size: 15px;
    color: var(--primary-500, #14b8a6);
}

/* Filter tabs - mode-pill colored style (matches Propose modal) */
.review-dashboard-header .rdh-filters {
    display: inline-flex;
    align-items: center;
    margin-left: auto;
    gap: 2px;
    padding: 3px;
    background: var(--slate-100, #f1f5f9);
    border-radius: var(--radius-full, 9999px);
}

.review-dashboard-header .rdh-filters .filter-tab {
    background: transparent;
    color: var(--slate-500, #64748b);
    border: none;
    border-radius: var(--radius-full, 9999px);
    padding: 5px 12px;
    font-size: 0.75rem;
    font-weight: 500;
    cursor: pointer;
    /* Explicit props (not transition:all) per the visibility-trap guard. */
    transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
    display: flex;
    align-items: center;
    gap: 4px;
    font-family: inherit;
}

/* Semantic category colour AT REST — the filter carries the same colour the
   rest of the app uses for work (blue) / personal (pink) events, so the
   segmented control reads as "these are your work / personal calendars",
   not a third neutral palette. All stays the app's primary teal. The icon
   is always tinted; the muted label inherits a desaturated tint so the
   inactive segments don't shout. Canonical tokens (css/main.css:109-119)
   keep this in lockstep with event chips + privacy badges. */
.review-dashboard-header .rdh-filters .filter-tab[data-filter="work"] i {
    color: var(--category-work, #3b82f6);
}
.review-dashboard-header .rdh-filters .filter-tab[data-filter="personal"] i {
    color: var(--category-personal, #f472b6);
}
.review-dashboard-header .rdh-filters .filter-tab[data-filter="all"] i {
    color: var(--primary-500, #14b8a6);
}

.review-dashboard-header .rdh-filters .filter-tab:hover:not(.active) {
    color: var(--slate-700, #334155);
    background: rgba(255, 255, 255, 0.55);
}

/* ACTIVE — each segment fills with a tint of its own category colour and
   sets its text/icon to the darker on-tint shade. Scoped per data-filter so
   no single neutral rule can flatten them (the old override did exactly
   that — it forced teal on every active segment via specificity). */
.review-dashboard-header .rdh-filters .filter-tab.active {
    box-shadow: var(--shadow-sm, 0 1px 2px rgba(0,0,0,0.06));
    font-weight: 600;
}
.review-dashboard-header .rdh-filters .filter-tab[data-filter="all"].active {
    background: var(--surface-primary, #fff);
    color: var(--primary-600, #0d9488);
}
.review-dashboard-header .rdh-filters .filter-tab[data-filter="work"].active {
    background: color-mix(in srgb, var(--category-work, #3b82f6) 14%, #fff);
    color: var(--category-work-darker, #1d4ed8);
}
.review-dashboard-header .rdh-filters .filter-tab[data-filter="work"].active i {
    color: var(--category-work-darker, #1d4ed8);
}
.review-dashboard-header .rdh-filters .filter-tab[data-filter="personal"].active {
    background: color-mix(in srgb, var(--category-personal, #f472b6) 16%, #fff);
    color: var(--category-personal-darker, #db2777);
}
.review-dashboard-header .rdh-filters .filter-tab[data-filter="personal"].active i {
    color: var(--category-personal-darker, #db2777);
}

/* Review Center sync button — now uses shared `.sync-action sync-action--icon`
   token (see css/calendar-views.css). The legacy `.rdh-sync-btn` rules used
   to live here. */

.review-dashboard-header .rdh-help-btn {
    background: transparent;
    color: var(--slate-400, #94a3b8);
    border: none;
    border-radius: var(--radius-full, 9999px);
    width: 28px;
    height: 28px;
    padding: 0;
    font-size: 13px;
    cursor: pointer;
    transition: all 0.15s ease;
    display: flex;
    align-items: center;
    justify-content: center;
}

.review-dashboard-header .rdh-help-btn:hover {
    background: var(--slate-100, #f1f5f9);
    color: var(--slate-600, #475569);
}

body.dark-mode .review-dashboard-header .rdh-help-btn {
    color: var(--slate-400, #94a3b8);
}

body.dark-mode .review-dashboard-header .rdh-help-btn:hover {
    background: var(--slate-700, #334155);
    color: var(--slate-200, #e2e8f0);
}

/* ---- Header overflow ("⋯") menu (2026-07-11 chrome slim-down) -------------
   Low-frequency header actions (keyboard shortcuts, and whatever else outgrows
   the top row later) live behind a single "⋯" button so the header carries
   only title + status chips + Sync + overflow + close. */
.rc-tabrow .rdh-overflow { position: relative; display: inline-flex; }
.rc-tabrow .rdh-overflow-btn {
    background: transparent;
    color: var(--slate-400, #94a3b8);
    border: none;
    border-radius: var(--radius-full, 9999px);
    width: 32px;
    height: 32px;
    padding: 0;
    font-size: 15px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: background-color 0.15s ease, color 0.15s ease;
}
.rc-tabrow .rdh-overflow-btn:hover,
.rc-tabrow .rdh-overflow-btn[aria-expanded="true"] {
    background: var(--slate-100, #f1f5f9);
    color: var(--slate-600, #475569);
}
.rdh-overflow-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 30;
    min-width: 200px;
    padding: 6px;
    background: var(--surface-primary, #fff);
    border: 1px solid var(--slate-200, #e2e8f0);
    border-radius: 12px;
    box-shadow: 0 12px 32px rgba(15, 23, 42, 0.14);
}
.rdh-overflow-menu[hidden] { display: none; }
/* ONE REFRESH PER VIEWPORT (2026-08-29, user: "Policy standard and refresh seem
   legacy and unnecessary").
   Refresh exists twice: the inline #rdh-sync-btn on the strip, and #rdh-sync-item
   in this menu. That is deliberate but VIEWPORT-SPLIT, not simultaneous — the
   inline button is hidden below 480px (see the .rc-navrow rule ~13687) so the
   menu row can take over on a phone. Above that breakpoint both were rendered,
   so the menu opened onto a Refresh sitting one click deeper than the Refresh
   already on screen. Hide the deeper copy wherever the inline one is showing.
   `display:none` (not visibility/opacity) so it leaves the tab order and the
   screen-reader menu too — a duplicate announced twice is the same bug. */
@media (min-width: 481px) {
    .rdh-overflow-menu #rdh-sync-item { display: none; }
}
.rdh-overflow-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    background: transparent;
    border: none;
    border-radius: 8px;
    font-size: 13px;
    font-family: inherit;
    color: var(--slate-700, #334155);
    cursor: pointer;
    text-align: left;
    transition: background-color 0.12s ease;
}
.rdh-overflow-item:hover,
.rdh-overflow-item:focus-visible { background: var(--slate-100, #f1f5f9); outline: none; }
.rdh-overflow-item i { width: 16px; text-align: center; color: var(--slate-400, #94a3b8); }
body.dark-mode .rc-tabrow .rdh-overflow-btn:hover,
body.dark-mode .rc-tabrow .rdh-overflow-btn[aria-expanded="true"] {
    background: var(--slate-700, #334155);
    color: var(--slate-200, #e2e8f0);
}
body.dark-mode .rdh-overflow-menu {
    background: var(--surface-secondary, #1e293b);
    border-color: var(--slate-700, #334155);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
}
body.dark-mode .rdh-overflow-item { color: var(--slate-200, #e2e8f0); }
body.dark-mode .rdh-overflow-item:hover,
body.dark-mode .rdh-overflow-item:focus-visible { background: var(--slate-700, #334155); }

/* The team-fairness chip lives INSIDE this menu as a row (it was an inline
   header pill). It still carries its own pill class (.rdh-fairness-chip) so the
   dot·band·score internals keep their styling — but the OUTER pill chrome
   (rounded bg, border, fixed height, margin-left) must yield to the full-width
   menu-row layout. These overrides strip the pill shell while leaving the inner
   spans intact, and the fairness band word keeps its canonical hue.
   (.rdh-sent-chip selectors dropped 2026-08-06 — no renderer emits that chip;
   "Sent by me" is a sub-tab of Proposals.) */
.rdh-overflow-menu .rdh-fairness-chip {
    /* Re-assert the .rdh-overflow-item row layout over the pill rules. */
    display: flex;
    width: 100%;
    height: auto;
    margin: 0;
    padding: 8px 10px;
    gap: 10px;
    border: none;
    background: transparent;
    border-radius: 8px;
    justify-content: flex-start;
}
.rdh-overflow-menu .rdh-fairness-chip:hover,
.rdh-overflow-menu .rdh-fairness-chip:focus-visible {
    background: var(--slate-100, #f1f5f9);
    border: none;
    box-shadow: none;
    outline: none;
}
body.dark-mode .rdh-overflow-menu .rdh-fairness-chip {
    background: transparent;
    border: none;
}
body.dark-mode .rdh-overflow-menu .rdh-fairness-chip:hover,
body.dark-mode .rdh-overflow-menu .rdh-fairness-chip:focus-visible {
    background: var(--slate-700, #334155);
}
/* Fairness dot/label/band/score: keep the canonical hue; push the numeric score
   to the right edge of the row so it reads like a menu value. */
.rdh-overflow-menu .rdh-fairness-chip .rc-tf-band { margin-left: 2px; }
.rdh-overflow-menu .rdh-fairness-chip .rc-tf-score { margin-left: auto; }

.rc-tabrow .rdh-close-btn {
    background: var(--slate-100, #f1f5f9);
    color: var(--slate-500, #64748b);
    border: none;
    border-radius: var(--radius-full, 9999px);
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.15s ease;
    font-size: 13px;
    flex-shrink: 0;
}

.rc-tabrow .rdh-close-btn:hover {
    background: var(--slate-200, #e2e8f0);
    color: var(--slate-700, #334155);
}

body.dark-mode .review-dashboard-header {
    background: var(--slate-900, #0f172a);
}

body.dark-mode .review-dashboard-header .rdh-title {
    color: var(--slate-200, #e2e8f0);
}

body.dark-mode .review-dashboard-header .rdh-filters {
    background: var(--slate-800, #1e293b);
}

body.dark-mode .review-dashboard-header .rdh-filters .filter-tab {
    color: var(--slate-400, #94a3b8);
}

body.dark-mode .review-dashboard-header .rdh-filters .filter-tab:hover:not(.active) {
    color: var(--slate-300, #cbd5e1);
    background: var(--slate-700, #334155);
}

/* Dark-mode rest tints — lighter category shades for contrast on slate. */
body.dark-mode .review-dashboard-header .rdh-filters .filter-tab[data-filter="work"] i {
    color: var(--category-work-light, #60a5fa);
}
body.dark-mode .review-dashboard-header .rdh-filters .filter-tab[data-filter="personal"] i {
    color: var(--category-personal-light, #f9a8d4);
}
body.dark-mode .review-dashboard-header .rdh-filters .filter-tab[data-filter="all"] i {
    color: var(--primary-300, #5eead4);
}

/* Dark-mode active — per-segment category tint on slate, matching the light
   rule's semantics so Work/Personal keep their colour identity. */
body.dark-mode .review-dashboard-header .rdh-filters .filter-tab.active {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
body.dark-mode .review-dashboard-header .rdh-filters .filter-tab[data-filter="all"].active {
    background: var(--slate-700, #334155);
    color: var(--primary-300, #5eead4);
}
body.dark-mode .review-dashboard-header .rdh-filters .filter-tab[data-filter="work"].active {
    background: color-mix(in srgb, var(--category-work, #3b82f6) 26%, var(--slate-800, #1e293b));
    color: var(--category-work-lighter, #93c5fd);
}
body.dark-mode .review-dashboard-header .rdh-filters .filter-tab[data-filter="work"].active i {
    color: var(--category-work-lighter, #93c5fd);
}
body.dark-mode .review-dashboard-header .rdh-filters .filter-tab[data-filter="personal"].active {
    background: color-mix(in srgb, var(--category-personal, #f472b6) 26%, var(--slate-800, #1e293b));
    color: var(--category-personal-lighter, #fbcfe8);
}
body.dark-mode .review-dashboard-header .rdh-filters .filter-tab[data-filter="personal"].active i {
    color: var(--category-personal-lighter, #fbcfe8);
}

body.dark-mode .rc-tabrow .rdh-close-btn {
    background: var(--slate-700, #334155);
    color: var(--slate-400, #94a3b8);
}

body.dark-mode .rc-tabrow .rdh-close-btn:hover {
    background: var(--slate-600, #475569);
    color: var(--slate-200, #e2e8f0);
}

/* Dashboard content fills remaining space */
.review-dashboard-content {
    /* The modal body. Does NOT scroll itself — it clips to the modal height and
       hands its full box to `.review-dashboard`, which is the scroll viewport
       (Phase D: header scrolls away, sticky bar pins). overflow:hidden keeps the
       rounded modal corners clean over the inner scroll. */
    flex: 1;
    min-height: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    /* Fill the modal body outright. Was calc(94vh - 48px) — the 94vh was coupled
       to .modal-content's old max-height and the -48px was dead slack from the
       now display:none .modal-header. As a flex:1/min-height:0/overflow:hidden
       child of a column flex parent, 100% is well-defined and decouples from vh
       so the shell height can change without a second edit here. */
    max-height: 100%;
    padding: 0;
}

#close-review-modal {
    position: relative;
    z-index: 100;
    cursor: pointer !important;
    pointer-events: auto !important;
}

body.dark-mode .review-modal .modal-content {
    background: linear-gradient(180deg, rgba(30, 41, 59, 0.98) 0%, rgba(15, 23, 42, 0.98) 100%);
    border-color: rgba(71, 85, 105, 0.4);
}

.review-dashboard {
    /* Phase D: the WHOLE panel is the scroll viewport now — the header scrolls
       AWAY with the content and only the .rc-sticky-bar pins. min-height:0 +
       flex:1 lets it fill the modal body and own overflow. (Was a non-scrolling
       flex column wrapping a pinned .rc-frame; that kept ~130px of chrome
       permanently above the fold.) */
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0;
    display: block;
}

/* Sticky navigation: tab bar · triage · search · progress. Scrolls UP with the
   header, then pins at the top of the viewport so the controls reached mid-task
   stay one glance away at any depth. The header above it scrolls fully away.
   z-index keeps cards from showing through; the surface bg + a hairline border
   (only once scrolled) separate it from the list beneath. */
.rc-sticky-bar {
    position: sticky;
    top: 0;
    z-index: 5;
    background: var(--surface-primary, #fff);
    padding: 10px 18px 0;
    border-bottom: 1px solid transparent;
    transition: padding 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}

/* Compact state — applied by attachScrollShrink() once the header has scrolled
   out of view. Tightens vertical padding and reveals the divider/shadow so the
   pinned strip reads as ~36px of chrome over the data, not a tall band. */
.rc-sticky-bar.rc-scrolled {
    padding: 6px 18px 6px;
    border-bottom-color: var(--slate-200, #e2e8f0);
    box-shadow: 0 2px 6px rgba(15, 23, 42, 0.06);
}
body.dark-mode .rc-sticky-bar {
    background: var(--slate-900, #0f172a);
}
body.dark-mode .rc-sticky-bar.rc-scrolled {
    border-bottom-color: var(--slate-700, #334155);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4);
}

/* The card list — normal flow under the sticky bar. No longer owns overflow
   (the whole panel scrolls); keeps only horizontal padding + bottom gap. */
.review-tab-content {
    padding: 8px 18px 16px;
}

/* Sync spin animation */
@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

/* ============================================
   FILTER TABS (All/Work/Personal)
   Base styles used by header filter tabs
   ============================================ */
.filter-tab {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 5px 12px;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--slate-500);
    background: transparent;
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: all 0.15s ease;
    white-space: nowrap;
}

.filter-tab:hover:not(.active) {
    color: var(--slate-700);
    background: rgba(255, 255, 255, 0.5);
}

.filter-tab.active {
    font-weight: 600;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
}

/* Base (unscoped) semantic active treatment — fallback for any .filter-tab
   used outside the Review Center header. Routes through canonical category
   tokens (css/main.css:109-119) so work=blue / personal=pink stay in lockstep
   with event chips + privacy badges across the app. */
/* All filter - teal */
.filter-tab[data-filter="all"].active {
    color: var(--primary-600);
    background: rgba(20, 184, 166, 0.1);
    border: 1px solid rgba(20, 184, 166, 0.2);
}

/* Work filter - blue */
.filter-tab[data-filter="work"].active {
    color: var(--category-work-darker, #1d4ed8);
    background: color-mix(in srgb, var(--category-work, #3b82f6) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--category-work, #3b82f6) 22%, transparent);
}

/* Personal filter - pink */
.filter-tab[data-filter="personal"].active {
    color: var(--category-personal-darker, #db2777);
    background: color-mix(in srgb, var(--category-personal, #f472b6) 11%, transparent);
    border: 1px solid color-mix(in srgb, var(--category-personal, #f472b6) 24%, transparent);
}

.filter-tab i {
    font-size: 0.75rem;
    flex-shrink: 0;
}

body.dark-mode .filter-tab {
    color: var(--slate-400);
}

body.dark-mode .filter-tab:hover:not(.active) {
    color: var(--slate-200);
    background: var(--slate-700);
}

body.dark-mode .filter-tab.active {
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}

body.dark-mode .filter-tab[data-filter="all"].active {
    color: var(--primary-300);
    background: rgba(20, 184, 166, 0.15);
    border: 1px solid rgba(20, 184, 166, 0.25);
}

body.dark-mode .filter-tab[data-filter="work"].active {
    color: #93c5fd;
    background: rgba(59, 130, 246, 0.15);
    border: 1px solid rgba(59, 130, 246, 0.25);
}

body.dark-mode .filter-tab[data-filter="personal"].active {
    color: #f9a8d4;
    background: rgba(244, 114, 182, 0.15);
    border: 1px solid rgba(244, 114, 182, 0.25);
}

/* ============================================
   TRIAGE STRIP (Phase B) — cross-tab "what needs me now?" band, sits
   between the search/date bar and the tab bar. It now renders ONLY when
   there's something urgent (expiring / conflicts); otherwise the JS returns
   '' and this band takes zero space. The fairness chip that used to live
   here — and forced the band to always reserve height — moved to the header.
   ============================================ */
/* Tab row: the tab bar on the left and the triage chips ("2 expiring soon",
   conflicts) right-aligned opposite them on the SAME row, so the urgent
   cross-tab counts read as a status readout beside the navigation rather than
   as a separate band that adds height. The row wraps on narrow widths so the
   chips drop below the tabs instead of overflowing. */
.rc-tabrow {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px 10px;
    margin-bottom: 10px;
    transition: margin-bottom 0.18s ease;
}
.rc-scrolled .rc-tabrow {
    margin-bottom: 0;
}

/* ============================================================
   TWO-ROW STICKY STRIP (2026-08-04)
   ============================================================
   The strip was ONE wrap-enabled row carrying five independent control groups
   (brand, tabs, triage, search+filters, actions). With `flex-wrap: wrap` and no
   priority between them, WHICH group dropped to a second line depended on the
   viewport and the current label lengths — so the layout was emergent, and the
   31 media queries in this file spent most of their effort hiding one control
   at a time to keep everything on one line.

   Now there are two rows with distinct jobs, and each is allowed to be simple:
     .rc-navrow  — WHERE YOU ARE: brand, tabs, close. Never wraps.
     .rc-toolrow — WHAT YOU'RE LOOKING AT: triage, search, filters.

   This removes the contention rather than suppressing its symptoms, which is
   what lets the phone rules stay short.
   ============================================================ */
.rc-navrow {
    flex-wrap: nowrap;          /* the whole point — no emergent second line */
    gap: 8px;
    min-width: 0;
}
/* Tabs take the flexible middle and SCROLL if their labels ever exceed it,
   instead of wrapping the action cluster onto its own line. min-width:0 is
   required for a flex child to be allowed to shrink below its content size. */
.rc-navrow .review-tabs {
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
}
.rc-navrow .review-tabs::-webkit-scrollbar { display: none; }
/* Buttons SHARE the track they're given (2026-08-06). The rule above stretches
   the pill container to fill the nav row, but the buttons stayed `flex: 0 1 auto`
   — content-sized. Measured at 1440px that left four tabs using 360px of a 770px
   track: 410px (53%) of empty grey pill trailing off to the right, with the tabs
   bunched at the left edge.

   `flex-grow: 1` lets them divide the slack so each icon+label centres in its own
   equal share. The other two thirds of the shorthand matter just as much:

     flex-shrink: 0   — the nav row's siblings (title ~118px, search+filters ~289px,
                        actions ~104px) are all fixed-size, so around 769px the tabs
                        are left barely 126px. With shrink enabled the buttons
                        collapsed to 28px each and ellipsis ate every label whole.
     flex-basis: auto — content width is the FLOOR, so growth is the only degree of
                        freedom. A basis of 0 divides evenly but hands the row no
                        protection when the track is narrower than the labels.

   Once the track can't seat the labels, `.rc-navrow .review-tabs { overflow-x }`
   above scrolls them — the designed fallback, and better than four unreadable
   stubs. No breakpoint here on purpose: this reads the space actually available
   rather than guessing from viewport width, so the tablet range is covered too.
   The phone rules (max-width:480px, ~9150) still win by specificity+order, and
   should — there the ACTIVE tab intentionally takes the slack while the rest
   collapse to icons. */
.rc-navrow .review-tab {
    flex: 1 0 auto;
}
/* The action cluster is fixed-size and always last — it must never be the
   thing that gets squeezed, since it owns Close. */
.rc-navrow .rdh-actions {
    flex: 0 0 auto;
    margin-left: auto;
}
/* Search + filters MIGRATE onto the nav row when this tab has no triage anchors
   (2026-08-04 follow-up). The tool row only earns its vertical space when it
   carries triage on the left; with nothing to balance against it was two
   right-floated icon buttons alone in a full-height band — the "unnecessary
   white space" the user reported. Here they sit between the tabs and the action
   cluster, both fixed-size, so the scrollable tabs absorb the difference. */
.rc-navrow .rc-inline-controls {
    flex: 0 0 auto;
    margin-left: auto;
    gap: 6px;
}
/* When the controls ride the nav row, the ACTION cluster no longer needs its
   own auto margin — the controls already pushed everything right, and a second
   auto margin would open a dead gutter between them. */
.rc-navrow .rc-inline-controls ~ .rdh-actions {
    margin-left: 0;
}

.rc-toolrow {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: 8px;
    min-width: 0;
    margin-bottom: 10px;
    transition: margin-bottom 0.18s ease;
}
/* Triage leads, controls trail. Triage may shrink (its segments self-hide when
   nothing is urgent); the controls keep their width so the filter affordance
   stays tappable. */
.rc-toolrow .rc-triage-strip {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
}
.rc-toolrow .rc-inline-controls {
    flex: 0 0 auto;
    margin-left: auto;
}
/* Scrolled state: the tool row is the FIRST thing to go. Once the user is
   reading the list they are oriented, so the pinned strip collapses to the nav
   row alone (tabs + close) and the list gets those pixels back. */
.rc-scrolled .rc-toolrow {
    margin-bottom: 0;
}

/* ============================================
   IN-STRIP BRAND + ACTIONS (2026-07-12 full-modal redesign)
   The old .review-dashboard-header row was dissolved into this single pinned
   strip. renderStripBrand() leads the row (brand), renderHeaderActions() trails
   it (sync · ⋯ · close). .rc-inline-controls (search+filters) carries
   margin-left:auto (see below), so everything from the controls onward clusters
   at the right edge while brand + tabs stay left.
   ============================================ */
.rc-tabrow .rdh-title {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--slate-800, #1e293b);
    letter-spacing: -0.01em;
    margin: 0;
    white-space: nowrap;
    flex-shrink: 0;
}
.rc-tabrow .rdh-title i {
    font-size: 15px;
    color: var(--primary-500, #14b8a6);
}
body.dark-mode .rc-tabrow .rdh-title {
    color: var(--slate-200, #e2e8f0);
}

/* Right-aligned action cluster: sync, overflow, close. Sits after the inline
   controls (which own margin-left:auto), so it hugs the strip's right edge. */
.rdh-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

.rc-triage-strip {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px 8px;
    padding: 0 2px;
    /* Push the chips to the right edge, opposite the tabs on the same row. */
    margin-left: auto;
}

.rc-triage-seg {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border-radius: var(--radius-full, 9999px);
    border: 1px solid transparent;
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 600;
    cursor: pointer;
    /* Explicit props (not transition:all) per the visibility-trap guard. */
    transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.rc-triage-seg .rc-triage-count { font-weight: 800; font-variant-numeric: tabular-nums; }
.rc-triage-seg i { font-size: 11px; }

/* Expiring-soon = amber (act before it auto-decides). */
.rc-triage-urgent {
    color: #92400e;
    background: color-mix(in srgb, var(--rc-status-tentative, #f59e0b) 14%, transparent);
    border-color: color-mix(in srgb, var(--rc-status-tentative, #f59e0b) 30%, transparent);
}
.rc-triage-urgent i { color: var(--rc-status-tentative, #f59e0b); }
.rc-triage-urgent:hover { background: color-mix(in srgb, var(--rc-status-tentative, #f59e0b) 22%, transparent); }

/* Conflicts = busy red (canonical token, no hue drift). */
.rc-triage-conflict {
    color: var(--rc-status-busy, #dc2626);
    background: color-mix(in srgb, var(--rc-status-busy, #dc2626) 12%, transparent);
    border-color: color-mix(in srgb, var(--rc-status-busy, #dc2626) 28%, transparent);
}
.rc-triage-conflict:hover { background: color-mix(in srgb, var(--rc-status-busy, #dc2626) 20%, transparent); }

/* Awaiting = the plain backlog count. Calm slate, not an urgency colour — it
   only rides along when the strip is already up for a time-sensitive reason. */
.rc-triage-awaiting {
    color: var(--slate-600, #475569);
    background: rgba(148, 163, 184, 0.14);
    border-color: rgba(148, 163, 184, 0.32);
}
.rc-triage-awaiting i { color: var(--slate-500, #64748b); }
.rc-triage-awaiting:hover { background: rgba(148, 163, 184, 0.22); }
body.dark-mode .rc-triage-awaiting { color: var(--slate-300, #cbd5e1); }

.rc-triage-seg:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--review-focus-ring, rgba(20, 184, 166, 0.4));
}

/* Compact team-fairness chip — lives in the HEADER row now (was the triage
   strip). Sits in the previously-dead space between the title and the
   calendar filter. Sized to the header's 28px control height. The .rc-tf-*
   inner classes are shared with nothing else now but kept stable.

   Colour: the chip CARRIES the canonical band hue rather than reducing it to
   a lone 8px dot on a flat-grey field. --rc-tf-color is set inline to the
   band's --fv-l* token (review-dashboard.js renderHeaderFairnessChip), so the
   tint, border, and band word all derive from the SAME canonical source the
   per-card .rc-fairness-chip and the fairness dashboard use — no bespoke
   palette. The "Fairness" label + score stay neutral slate so the score reads
   as a number, not a verdict, and the hue lands on the one word it describes. */
.rdh-fairness-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    /* Sit just after the title, in what used to be dead space. The filter
       group keeps its own margin-left:auto and stays hard-right, so this
       chip simply fills the gap between title and filters. When there's no
       fairness history the chip isn't rendered and the gap returns to the
       filter's auto-margin — no layout breakage either way. */
    margin-left: 14px;
    padding: 4px 10px;
    height: 28px;
    border-radius: var(--radius-full, 9999px);
    /* Soft tint of the canonical band colour — same color-mix grammar as the
       per-card .rc-fairness-chip, kept light so the header stays calm. */
    border: 1px solid color-mix(in srgb, var(--rc-tf-color, var(--primary-500, #14b8a6)) 28%, transparent);
    background: color-mix(in srgb, var(--rc-tf-color, var(--primary-500, #14b8a6)) 9%, var(--slate-50, #f8fafc));
    font-size: var(--rc-font-secondary, 12px);
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.rdh-fairness-chip:hover {
    background: color-mix(in srgb, var(--rc-tf-color, var(--primary-500, #14b8a6)) 15%, var(--slate-50, #f8fafc));
    border-color: color-mix(in srgb, var(--rc-tf-color, var(--primary-500, #14b8a6)) 42%, transparent);
}
.rdh-fairness-chip:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--review-focus-ring, rgba(20, 184, 166, 0.4));
}
/* Fallback for browsers without color-mix() — quiet slate chrome, band hue
   still carried by the dot + band word below (which use the token directly). */
@supports not (background: color-mix(in srgb, red 9%, white)) {
    .rdh-fairness-chip {
        background: var(--slate-50, #f8fafc);
        border-color: var(--slate-200, #e2e8f0);
    }
    .rdh-fairness-chip:hover {
        background: var(--slate-100, #f1f5f9);
        border-color: var(--slate-300, #cbd5e1);
    }
}
.rc-tf-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--rc-tf-color, var(--primary-500, #14b8a6));
}
/* "Fairness" — quiet leading label so the number reads as a fairness score,
   not a bare count. Kept lighter than the band word so it doesn't compete. */
.rc-tf-label { color: var(--slate-500); font-weight: 600; }
/* Band word carries the canonical hue — it's the qualitative read; the score
   beside it is the quantitative one and stays neutral. The hue is DARKENED
   toward slate-900 so the mid-ramp amber (--fv-l5 #fbbf24) reads on the near-
   white chip; every band keeps its own hue, just deepened for text contrast
   (the dot + tint carry the lighter, true token value). */
.rc-tf-band {
    font-weight: 700;
    color: color-mix(in srgb, var(--rc-tf-color, var(--slate-700)) 70%, var(--slate-900, #0f172a));
}
@supports not (color: color-mix(in srgb, red 70%, black)) {
    .rc-tf-band { color: var(--rc-tf-color, var(--slate-700)); }
}
.rc-tf-score { font-weight: 800; color: var(--slate-800); font-variant-numeric: tabular-nums; }

/* Dark mode: --fv-l* already resolves to its dark-mode hex (fairness-view.css
   owns both), so the same color-mix grammar lands a readable tint on the
   slate-800 header. Higher mix % than light mode because the dark surface
   needs more colour to register. */
body.dark-mode .rdh-fairness-chip {
    background: color-mix(in srgb, var(--rc-tf-color, var(--primary-500, #14b8a6)) 16%, var(--slate-800, #1e293b));
    border-color: color-mix(in srgb, var(--rc-tf-color, var(--primary-500, #14b8a6)) 38%, transparent);
}
body.dark-mode .rdh-fairness-chip:hover {
    background: color-mix(in srgb, var(--rc-tf-color, var(--primary-500, #14b8a6)) 24%, var(--slate-800, #1e293b));
    border-color: color-mix(in srgb, var(--rc-tf-color, var(--primary-500, #14b8a6)) 50%, transparent);
}
@supports not (background: color-mix(in srgb, red 9%, white)) {
    body.dark-mode .rdh-fairness-chip {
        background: var(--slate-800, #1e293b);
        border-color: var(--slate-700, #334155);
    }
    body.dark-mode .rdh-fairness-chip:hover { background: var(--slate-700, #334155); }
}
body.dark-mode .rc-tf-label { color: var(--slate-400); }
body.dark-mode .rc-tf-score { color: var(--slate-100); }
/* Dark mode: the --fv-l* tokens are already lightened for dark surfaces, so
   the band word uses the raw token (no darkening — that would sink it into
   the dark chip). */
body.dark-mode .rc-tf-band { color: var(--rc-tf-color, var(--slate-200)); }

/* On narrow headers, drop the band word so the chip can't crowd the filter
   group. The "Fairness" label INTENTIONALLY stays (it's the thing that makes
   the score legible) so the chip reads "Fairness 68", never a bare "68". */
@media (max-width: 560px) {
    .rdh-fairness-chip .rc-tf-band { display: none; }
    .rdh-fairness-chip { margin-left: 8px; }
}
body.dark-mode .rc-triage-urgent { color: #fbbf24; }
body.dark-mode .rc-triage-conflict { color: #f87171; }

/* ============================================
   MAIN TAB NAVIGATION (mode-pill style)
   ============================================ */
.review-tabs {
    display: inline-flex;
    gap: 2px;
    padding: 3px;
    /* No bottom margin: the enclosing .rc-tabrow now owns the gap below the
       tab/triage row (the triage chips sit on the same line, right-aligned). */
    margin-bottom: 0;
    background: var(--slate-100, #f1f5f9);
    border-radius: var(--radius-full, 9999px);
}

.review-tab {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 6px 12px;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--slate-500);
    background: transparent;
    border: none;
    border-radius: var(--radius-full, 9999px);
    cursor: pointer;
    transition: all 0.2s ease;
    font-family: inherit;
}

.review-tab .tab-icon {
    font-size: 0.7rem;
}

/* Tab labels are always shown now. Previously they were hidden below 480px
   (icon-only tabs), which made the row cryptic on a phone — you couldn't tell
   what 📅/☰/👁 meant. With the "Requested" tab demoted to a "Sent by me" view
   there are three tabs (Scheduled / Proposals / Privacy), and three labelled
   tabs fit a 390px row cleanly (the mobile layout below makes them share the
   width evenly). See the @media (max-width:480px) tab block further down. */
.review-tab .tab-label {
    display: inline;
}

.review-tab:hover {
    color: var(--slate-700);
    background: rgba(255, 255, 255, 0.5);
}

.review-tab.active {
    color: var(--white, #fff);
    box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.06));
    font-weight: 600;
}

/* Default active color if no color class specified */
.review-tab.active:not([class*="tab-"]) {
    background: linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%);
    color: var(--white, #fff);
    border: none;
}

.review-tab .tab-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    font-size: 0.6rem;
    font-weight: 700;
    color: white;
    background: rgba(255, 255, 255, 0.3);
    border-radius: var(--radius-full);
    margin-left: 2px;
}

/* Conflict warning riding the Scheduled tab (2026-08-15 redesign). This
   replaced the triage strip's conflicts segment so a conflict costs ZERO
   extra rows of chrome. Red is deliberate and exclusive: in this product
   red means conflict/danger and nothing else, so the one red chip on the
   resting layout is the conflict warning. Always a COUNT, never a bare
   dot (user rule 2026-08-11). Identity-tint rules below must not
   recolor it, hence the explicit colour on every state.
   2026-08-17, owner: "conflict tab still uses an ugly red circle". The
   solid red fill read as a near-circular disc next to the SOFT-TINT
   sibling badges (.tab-badge is translucent; the active tabs themselves
   are 14% tints). The mobile treatment of this same warning was already
   moved to the tint idiom (.review-conflict-icon.has-items, ~546); this
   brings the desktop badge into the same family: soft red tint, red ink,
   glyph and count on one line. Ink is DARKER than the tint's own red
   because the tint composites over light tab underlays; #991b1b clears
   4.5:1 even on the active teal tab, where #b91c1c does not. */
.review-tab .tab-conflict-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    height: 16px;
    padding: 0 6px;
    margin-left: 3px;
    font-size: 0.6rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: #991b1b;
    background: color-mix(in srgb, var(--rc-conflict-red, #dc2626) 12%, transparent);
    border-radius: var(--radius-full);
    cursor: pointer;
    white-space: nowrap;
}
.review-tab .tab-conflict-badge i {
    font-size: 0.55rem;
}
/* Hover affordance is a ring, not a deeper fill: the active-tab idiom in
   this row is an inset ring, and a ring leaves the composited background
   (and so the count's contrast) untouched in both modes. */
.review-tab .tab-conflict-badge:hover {
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--rc-conflict-red, #dc2626) 55%, transparent);
}
.review-tab .tab-conflict-badge:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--rc-conflict-red, #dc2626);
}
.review-tab.active .tab-conflict-badge {
    color: #991b1b;
    background: color-mix(in srgb, var(--rc-conflict-red, #dc2626) 12%, transparent);
}
/* Dark mode leans on the lighter conflict red (#f87171, the same hue the
   dark triage chip and dark focus ring already use) because the canonical
   red tints to near-black over slate-800. Ink is red-300 rather than
   red-400: the badge can sit on the ACTIVE teal tab's own tint, and only
   #fca5a5 keeps the count above 4.5:1 on that composite. */
body.dark-mode .review-tab .tab-conflict-badge {
    color: #fca5a5;
    background: color-mix(in srgb, #f87171 14%, transparent);
}
body.dark-mode .review-tab .tab-conflict-badge:hover {
    box-shadow: inset 0 0 0 1px rgba(248, 113, 113, 0.55);
}
body.dark-mode .review-tab .tab-conflict-badge:focus-visible {
    box-shadow: 0 0 0 2px var(--slate-900, #0f172a), 0 0 0 4px #f87171;
}

body.dark-mode .review-tabs {
    background: var(--slate-800, #1e293b);
}

body.dark-mode .review-tab {
    color: var(--slate-400);
}

body.dark-mode .review-tab:hover {
    color: var(--slate-200);
    background: var(--slate-700);
}

body.dark-mode .review-tab.active {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

body.dark-mode .review-tab.active:not([class*="tab-"]) {
    background: linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%);
    color: var(--white, #fff);
    border: none;
}

/* ============================================
   COLOR-CODED TABS (2026-08-04 unified redesign)

   Tab identity comes from js/config/review-tab-identity.js — the SAME
   registry the launcher icon strip renders from, so a `tab-<color>` block
   must exist here for every color the registry names (teal / blue /
   emerald / purple / indigo). These are categorical (tab identity), not
   status — kept hardcoded so a status palette refresh can't recolor them.

   ONE flat treatment for every tab (the old mix of three gradients + one
   tinted style read as four unrelated controls, and two themes were
   referenced but never defined so those tabs rendered unthemed):
   - inactive: muted label, identity-colored icon
   - active:   identity tint bg + inset identity ring + dark identity text
   The ring is an inset box-shadow, not a border, so activation never
   changes layout width.
   ============================================ */

/* Teal — Events (scheduled for you) */
.review-tab.tab-teal .tab-icon { color: var(--primary-500); }
.review-tab.tab-teal:hover:not(.active) {
    color: var(--primary-600);
    background: rgba(20, 184, 166, 0.08);
}
.review-tab.tab-teal.active {
    background: rgba(20, 184, 166, 0.14);
    color: var(--primary-700, #0f766e);
    box-shadow: inset 0 0 0 1.5px rgba(20, 184, 166, 0.55);
}
.review-tab.tab-teal.active .tab-icon { color: var(--primary-700, #0f766e); }
.review-tab.tab-teal.active .tab-badge {
    background: rgba(20, 184, 166, 0.2);
    color: var(--primary-700, #0f766e);
}
.review-tab.tab-teal .tab-badge {
    background: rgba(20, 184, 166, 0.15);
    color: var(--primary-700);
}

/* Blue — Proposals (voting) */
.review-tab.tab-blue .tab-icon { color: #3b82f6; }
.review-tab.tab-blue:hover:not(.active) {
    color: #2563eb;
    background: rgba(59, 130, 246, 0.08);
}
.review-tab.tab-blue.active {
    background: rgba(59, 130, 246, 0.14);
    color: #1d4ed8;
    box-shadow: inset 0 0 0 1.5px rgba(59, 130, 246, 0.55);
}
.review-tab.tab-blue.active .tab-icon { color: #1d4ed8; }
.review-tab.tab-blue.active .tab-badge {
    background: rgba(59, 130, 246, 0.2);
    color: #1d4ed8;
}
.review-tab.tab-blue .tab-badge {
    background: rgba(59, 130, 246, 0.15);
    color: #1d4ed8;
}

/* Emerald — Sent by me (sub-tab identity; also its launcher icon) */
.review-tab.tab-emerald .tab-icon { color: #10b981; }
.review-tab.tab-emerald:hover:not(.active) {
    color: #059669;
    background: rgba(16, 185, 129, 0.08);
}
.review-tab.tab-emerald.active {
    background: rgba(16, 185, 129, 0.14);
    color: #047857;
    box-shadow: inset 0 0 0 1.5px rgba(16, 185, 129, 0.55);
}
.review-tab.tab-emerald.active .tab-icon { color: #047857; }
.review-tab.tab-emerald.active .tab-badge {
    background: rgba(16, 185, 129, 0.2);
    color: #047857;
}
.review-tab.tab-emerald .tab-badge {
    background: rgba(16, 185, 129, 0.15);
    color: #047857;
}

/* Purple — Privacy. Purple is the app-wide privacy hue
   (privacy-visual-config.js: purple = private/protective). */
.review-tab.tab-purple .tab-icon { color: var(--visibility-private, #8b5cf6); }
.review-tab.tab-purple:hover:not(.active) {
    color: #7c3aed;
    background: rgba(139, 92, 246, 0.08);
}
.review-tab.tab-purple.active {
    background: rgba(139, 92, 246, 0.14);
    color: #6d28d9;
    box-shadow: inset 0 0 0 1.5px rgba(139, 92, 246, 0.55);
}
.review-tab.tab-purple.active .tab-icon { color: #6d28d9; }
.review-tab.tab-purple.active .tab-badge {
    background: rgba(139, 92, 246, 0.2);
    color: #6d28d9;
}
.review-tab.tab-purple .tab-badge {
    background: rgba(139, 92, 246, 0.15);
    color: #6d28d9;
}

/* Indigo — Requests (people asking to join). Indigo, not violet:
   #7c3aed is a reserved status hue (canonical-shading-guards). */
.review-tab.tab-indigo .tab-icon { color: #6366f1; }
.review-tab.tab-indigo:hover:not(.active) {
    color: #4f46e5;
    background: rgba(99, 102, 241, 0.08);
}
.review-tab.tab-indigo.active {
    background: rgba(99, 102, 241, 0.14);
    color: #4338ca;
    box-shadow: inset 0 0 0 1.5px rgba(99, 102, 241, 0.55);
}
.review-tab.tab-indigo.active .tab-icon { color: #4338ca; }
.review-tab.tab-indigo.active .tab-badge {
    background: rgba(99, 102, 241, 0.2);
    color: #4338ca;
}
.review-tab.tab-indigo .tab-badge {
    background: rgba(99, 102, 241, 0.15);
    color: #4338ca;
}

/* Dark Mode - Color-coded tabs
   Same flat model; tints deepen, text lightens for contrast.
   ============================================ */
body.dark-mode .review-tab.tab-teal .tab-icon { color: var(--primary-400); }
body.dark-mode .review-tab.tab-teal:hover:not(.active) {
    color: var(--primary-300);
    background: rgba(20, 184, 166, 0.12);
}
body.dark-mode .review-tab.tab-teal.active {
    background: rgba(20, 184, 166, 0.22);
    color: #5eead4;
    box-shadow: inset 0 0 0 1.5px rgba(45, 212, 191, 0.5);
}
body.dark-mode .review-tab.tab-teal.active .tab-icon { color: #5eead4; }
body.dark-mode .review-tab.tab-teal.active .tab-badge {
    background: rgba(20, 184, 166, 0.3);
    color: #5eead4;
}
body.dark-mode .review-tab.tab-teal .tab-badge {
    background: rgba(20, 184, 166, 0.25);
    color: var(--primary-300, #5eead4);
}

body.dark-mode .review-tab.tab-blue .tab-icon { color: #60a5fa; }
body.dark-mode .review-tab.tab-blue:hover:not(.active) {
    color: #93c5fd;
    background: rgba(59, 130, 246, 0.12);
}
body.dark-mode .review-tab.tab-blue.active {
    background: rgba(59, 130, 246, 0.22);
    color: #93c5fd;
    box-shadow: inset 0 0 0 1.5px rgba(96, 165, 250, 0.5);
}
body.dark-mode .review-tab.tab-blue.active .tab-icon { color: #93c5fd; }
body.dark-mode .review-tab.tab-blue.active .tab-badge {
    background: rgba(59, 130, 246, 0.3);
    color: #93c5fd;
}
body.dark-mode .review-tab.tab-blue .tab-badge {
    background: rgba(59, 130, 246, 0.25);
    color: #93c5fd;
}

body.dark-mode .review-tab.tab-emerald .tab-icon { color: #34d399; }
body.dark-mode .review-tab.tab-emerald:hover:not(.active) {
    color: #6ee7b7;
    background: rgba(16, 185, 129, 0.12);
}
body.dark-mode .review-tab.tab-emerald.active {
    background: rgba(16, 185, 129, 0.22);
    color: #6ee7b7;
    box-shadow: inset 0 0 0 1.5px rgba(52, 211, 153, 0.5);
}
body.dark-mode .review-tab.tab-emerald.active .tab-icon { color: #6ee7b7; }
body.dark-mode .review-tab.tab-emerald.active .tab-badge {
    background: rgba(16, 185, 129, 0.3);
    color: #6ee7b7;
}
body.dark-mode .review-tab.tab-emerald .tab-badge {
    background: rgba(16, 185, 129, 0.25);
    color: #6ee7b7;
}

body.dark-mode .review-tab.tab-purple .tab-icon { color: #a78bfa; }
body.dark-mode .review-tab.tab-purple:hover:not(.active) {
    color: #c4b5fd;
    background: rgba(139, 92, 246, 0.12);
}
body.dark-mode .review-tab.tab-purple.active {
    background: rgba(139, 92, 246, 0.22);
    color: #c4b5fd;
    box-shadow: inset 0 0 0 1.5px rgba(167, 139, 250, 0.5);
}
body.dark-mode .review-tab.tab-purple.active .tab-icon { color: #c4b5fd; }
body.dark-mode .review-tab.tab-purple.active .tab-badge {
    background: rgba(139, 92, 246, 0.3);
    color: #c4b5fd;
}
body.dark-mode .review-tab.tab-purple .tab-badge {
    background: rgba(139, 92, 246, 0.25);
    color: #c4b5fd;
}

body.dark-mode .review-tab.tab-indigo .tab-icon { color: #a5b4fc; }
body.dark-mode .review-tab.tab-indigo:hover:not(.active) {
    color: #c7d2fe;
    background: rgba(99, 102, 241, 0.12);
}
body.dark-mode .review-tab.tab-indigo.active {
    background: rgba(99, 102, 241, 0.22);
    color: #c7d2fe;
    box-shadow: inset 0 0 0 1.5px rgba(165, 180, 252, 0.5);
}
body.dark-mode .review-tab.tab-indigo.active .tab-icon { color: #c7d2fe; }
body.dark-mode .review-tab.tab-indigo.active .tab-badge {
    background: rgba(99, 102, 241, 0.3);
    color: #c7d2fe;
}
body.dark-mode .review-tab.tab-indigo .tab-badge {
    background: rgba(99, 102, 241, 0.25);
    color: #c7d2fe;
}

/* ============================================
   CONFLICTS PANEL
   ============================================ */
.conflicts-panel {
    padding: 16px;
}

/* ONE header row (2026-08-15 redesign): back + title + live count share a
   single line. The old chrome stacked this header on a second full-width
   progress band ("Conflict N of M" + bar), so the first card started two
   bands down; the count is a short phrase and rides the line instead. */
.conflicts-panel-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
    flex-wrap: wrap;
}

.conflicts-panel-header h3 {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    color: var(--slate-800);
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

/* The warning glyph on the title is the panel's identity: red, because red
   means exactly conflict/danger in this product. */
.conflicts-title-icon {
    color: var(--rc-conflict-red, #dc2626);
    font-size: 0.85rem;
}

.conflicts-header-count {
    margin-left: auto;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--slate-500);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.back-to-scheduled-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: none;
    border-radius: var(--radius-full);
    background: var(--slate-100);
    color: var(--slate-600);
    font-size: 0.75rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s ease;
}

.back-to-scheduled-btn:hover {
    background: var(--slate-200);
    color: var(--slate-800);
}

.conflicts-list {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

/* Conflict card uses standard Review chrome (translucent white + slate
   border) so it sits in the same visual family as scheduled/proposals/
   outgoing cards. Red is reserved for the left-border accent + the
   overlap pill + the timeline overlap band, mirroring the per-category
   accent pattern used elsewhere. */
.conflict-item {
    position: relative;
    background: var(--review-card-bg);
    /* Glass, radius, padding and hover now come from the SAME tokens
       .review-item uses (2026-08-22, user: "the conflict tab ... clashes with
       my app in style"). Previously this card reached past the review-center
       scale into the global one for --radius-lg (16px, twice every other card
       in the panel), hard-coded its padding to 12px/14px, dropped the
       backdrop-filter every sibling card has, and defined no :hover at all —
       so conflict cards read as inert tiles from a different product. */
    backdrop-filter: blur(8px);
    border: 1px solid var(--review-card-border);
    border-left: 3px solid var(--rc-status-busy);
    border-radius: var(--rc-radius-card);
    padding: var(--rc-spacing-card);
    box-shadow: var(--review-card-shadow);
    display: flex;
    flex-direction: column;
    gap: var(--rc-spacing-section);
    transition: all 0.15s ease;
}

/* Same lift + teal ring as .review-item. The left border stays red — it is the
   category accent for "overlap" — but the hover affordance is now shared, so a
   conflict card behaves like every other card in the Review Center. */
.conflict-item:hover {
    border-color: var(--primary-300);
    border-left-color: var(--rc-status-busy);
    box-shadow: var(--shadow-md), 0 0 0 2px rgba(20, 184, 166, 0.08);
    transform: translateY(-1px);
}

/* Compact header: overlap pill + date/range meta + the whole-conflict
   "Keep both" action, all on ONE row, like Find Times' best-time-card
   #rank + info row.
   THREE children now (2026-08-15 redesign: Keep both left its own footer
   band), so this packs from the start and lets .keep-both-btn claim the
   right edge with margin-left:auto. space-between would have stranded
   .conflict-card-meta in the middle of the line. */
.conflict-card-header {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 10px;
    flex-wrap: wrap;
}

.conflict-overlap-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 9px;
    border-radius: var(--radius-full);
    background: rgba(220, 38, 38, 0.08);
    border: 1px solid rgba(220, 38, 38, 0.25);
    color: var(--rc-status-busy);
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    white-space: nowrap;
}

.conflict-overlap-pill i {
    font-size: 0.72rem;
}

.conflict-card-meta {
    display: inline-flex;
    align-items: baseline;
    gap: 8px;
    font-variant-numeric: tabular-nums;
    color: var(--slate-600);
}

.conflict-card-date {
    font-size: 0.72rem;
    font-weight: 500;
    color: var(--slate-500);
}

.conflict-card-range {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--slate-700);
}

/* ============================================
   CONFLICT MINI-BOARD (2026-08-15 redesign)
   The card body speaks the BOARD's grammar: one row per event, exactly
   like a timezone row (name on the left, hour track on the right), plus
   that row's actions at the far end. Colour canon (owner rule):
     - event spans  = BUSY slate  var(--status-busy)  #64748b
       (a proposed/tentative event keeps the stripe treatment, in slate;
        event blocks are NEVER orange/amber here)
     - empty track  = var(--status-empty)  #e2e8f0 (never white)
     - RED is reserved for the ONE conflict element: the overlap column
       crossing both rows, like the board's scanner column.
   ============================================ */
.rcx-board {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* [label | track | actions]: the track column is shared by every row of
   the board (including the axis row), so bars and ticks stay aligned. */
.rcx-row {
    display: grid;
    grid-template-columns: minmax(76px, 148px) minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
}

.rcx-row-label {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.rcx-row-name {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--slate-800);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

/* Tiny status swatch tying the label to its bar. Same tokens as the bar. */
.rcx-row-swatch {
    flex-shrink: 0;
    width: 8px;
    height: 8px;
    border-radius: 2px;
    background: var(--status-busy, #64748b);
}
.rcx-row-swatch[data-status="tentative"] {
    background-image: repeating-linear-gradient(
        45deg,
        rgba(255, 255, 255, 0.5) 0 2px,
        transparent 2px 4px
    );
}

.rcx-row-attendees {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    flex-shrink: 0;
    font-size: 0.66rem;
    font-weight: 600;
    color: var(--slate-500);
}
.rcx-row-attendees i { font-size: 0.6rem; }

/* Proposal rows in a conflict card (2026-08-19): the entry is a proposed time,
   not a booking — the pill says so inline, using the SAME "Proposed" noun the
   event modal status line and chips use (no new vocabulary). */
.rcx-row-proposal-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 0.65rem;
    font-weight: 600;
    color: var(--slate-500);
    padding: 1px 6px;
    border-radius: var(--radius-full);
    border: 1px dashed var(--slate-300, #cbd5e1);
    white-space: nowrap;
    flex-shrink: 0;
}
body.dark-mode .rcx-row-proposal-pill {
    color: var(--slate-400, #94a3b8);
    border-color: var(--slate-600, #475569);
}

/* The hour track: the board's empty tint, hour gridlines, one bar. */
.rcx-track {
    position: relative;
    height: 22px;
    min-width: 0;
    background: var(--status-empty, #e2e8f0);
    border-radius: 4px;
    overflow: hidden;
}

.rcx-gridlines {
    position: absolute;
    inset: 0;
    pointer-events: none;
}
.rcx-gridline {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 1px;
    background: rgba(255, 255, 255, 0.75);
}

/* The event's span: solid busy slate, exactly the board's busy block. */
.rcx-span {
    position: absolute;
    top: 2px;
    bottom: 2px;
    border-radius: 3px;
    background: var(--status-busy, #64748b);
    min-width: 2px;
}
/* Proposed/tentative keeps the board's stripe treatment IN SLATE. Never
   amber/orange: those are not this product's event-block vocabulary, and
   red must stay unique to the conflict column. */
.rcx-span[data-status="tentative"] {
    background-image: repeating-linear-gradient(
        45deg,
        rgba(255, 255, 255, 0.35) 0 4px,
        transparent 4px 8px
    );
}

.rcx-span-label {
    position: absolute;
    top: 50%;
    left: 5px;
    transform: translateY(-50%);
    font-size: 9.5px;
    font-weight: 600;
    line-height: 1;
    color: #fff;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    pointer-events: none;
    text-shadow: 0 0 2px rgba(0, 0, 0, 0.35);
}
.rcx-span-label-out .rcx-span-label {
    left: calc(100% + 4px);
    color: var(--slate-600, #475569);
    text-shadow: none;
}

/* THE red element: the overlap column. A wash + dashed edges over the
   track, repeated at the same coordinates on both rows so it reads as one
   column crossing them, the way the board's scanner column crosses rows. */
.rcx-overlap {
    position: absolute;
    top: 0;
    height: 100%;
    background: color-mix(in srgb, var(--rc-conflict-red, #dc2626) 22%, transparent);
    border-left: 1.5px dashed var(--rc-conflict-red, #dc2626);
    border-right: 1.5px dashed var(--rc-conflict-red, #dc2626);
    pointer-events: none;
}

/* Hour axis under the tracks; sits in the same grid column as the tracks
   so its ticks line up with the gridlines above. */
.rcx-axis-row { min-height: 14px; }
.rcx-axis {
    position: relative;
    height: 14px;
    min-width: 0;
}
.rcx-tick {
    position: absolute;
    top: 0;
    transform: translateX(-50%);
    font-size: 10px;
    color: var(--slate-500);
    font-variant-numeric: tabular-nums;
    line-height: 1;
    white-space: nowrap;
}
.rcx-tick.is-edge:first-child .rcx-tick-label {
    display: inline-block;
    transform: translateX(calc(50% - 1px));
}
.rcx-tick.is-edge:last-child .rcx-tick-label {
    display: inline-block;
    transform: translateX(calc(-50% + 1px));
}

/* Phones: tighter label column; the action buttons are already icon-only
   at this width (see the .conflict-action-btn rule below), so the row
   still fits [label | track | two icons] on a 390px screen with no
   orphan band and no second line. Interior ticks go; edge ticks stay. */
@media (max-width: 480px) {
    .rcx-row {
        grid-template-columns: minmax(56px, 92px) minmax(0, 1fr) auto;
        gap: 6px;
    }
    .rcx-row-name { font-size: 0.72rem; }
    .rcx-row-attendees { display: none; }
    .rcx-tick:not(.is-edge) { display: none; }
    /* The track clips (overflow:hidden), so a label floated past a narrow
       bar would be cut at the track edge. Keep every label inside its bar,
       smaller, so the "when" stays readable. */
    .rcx-span-label,
    .rcx-span-label-out .rcx-span-label {
        left: 3px;
        color: #fff;
        text-shadow: 0 0 2px rgba(0, 0, 0, 0.35);
        font-size: 8.5px;
        max-width: calc(100% - 4px);
        overflow: hidden;
        text-overflow: ellipsis;
    }
}

.conflict-event-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    min-width: 0;
}

/* Action buttons echo Find Times' compact vote-button sizing — smaller
   than the old 36px chunky version, but still keeps the text label at
   desktop widths so Cancel vs Decline stays unambiguous. */
.conflict-action-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    height: 28px;
    padding: 0 10px;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    font-size: 0.74rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
    white-space: nowrap;
}

.conflict-action-btn i {
    font-size: 0.72rem;
}

.conflict-action-btn.reschedule-btn {
    background: var(--slate-50);
    color: var(--slate-700);
    border-color: var(--slate-200);
}

.conflict-action-btn.reschedule-btn:hover {
    background: #eff6ff;
    color: #1d4ed8;
    border-color: #bfdbfe;
}

.conflict-action-btn.decline-conflict-btn,
.conflict-action-btn.cancel-conflict-btn {
    background: var(--slate-50);
    color: var(--slate-700);
    border-color: var(--slate-200);
}

.conflict-action-btn.decline-conflict-btn:hover,
.conflict-action-btn.cancel-conflict-btn:hover {
    background: #fef2f2;
    color: #b91c1c;
    border-color: #fecaca;
}

/* "Keep both" applies to the whole conflict, so it rides the card header
   line (right edge) instead of buying a footer band of its own. */
.conflict-card-header .keep-both-btn {
    margin-left: auto;
}

/* The overlap pill now also names WHEN the overlap is, so the diagram
   does not need a floating label of its own. */
.conflict-overlap-pill-range {
    font-weight: 500;
    font-variant-numeric: tabular-nums;
}

/* Narrow viewports: drop button labels to icons-only when there's no room. */
@media (max-width: 480px) {
    .conflict-action-btn span {
        display: none;
    }
    .conflict-action-btn {
        padding: 0 8px;
        min-width: 28px;
    }
    /* EXCEPT "Keep both" (2026-08-16, user: "accept overlap button is not well
       understandable"). A double-tick with no word is unreadable: nothing about
       ✓✓ says "accept this overlap and stop flagging it", and unlike the other
       two actions here it is not undoable by simply doing it again. Reschedule
       (a clock-arrow) and Decline (an ×) are conventional enough to survive as
       glyphs; this one is not, and it is the consequential one. Keep its word.
       Same rule as the webfont-glyph audit: a glyph must never be the ONLY
       carrier of meaning. */
    .conflict-action-btn.keep-both-btn span {
        display: inline;
    }
    .conflict-action-btn.keep-both-btn {
        padding: 0 10px;
        min-width: 0;
    }
}

/* Dark mode conflicts panel */
body.dark-mode .conflicts-panel-header h3 {
    color: var(--slate-200);
}

body.dark-mode .back-to-scheduled-btn {
    background: var(--slate-700);
    color: var(--slate-300);
}

body.dark-mode .back-to-scheduled-btn:hover {
    background: var(--slate-600);
    color: var(--slate-100);
}

body.dark-mode .conflict-item {
    background: var(--review-card-bg);
    border-color: var(--review-card-border);
    border-left-color: var(--rc-status-busy);
}

body.dark-mode .conflict-overlap-pill {
    background: rgba(248, 113, 113, 0.1);
    border-color: rgba(248, 113, 113, 0.3);
    color: #f87171;
}

body.dark-mode .conflict-card-date {
    color: var(--slate-400);
}

body.dark-mode .conflict-card-range {
    color: var(--slate-200);
}

/* Mini-board dark mode: the board's own dark inversion. Busy must LIFT
   (#94a3b8) and empty must DARKEN (#334155): "faint" on a dark board means
   darker, not lighter (2026-08-14 palette decision). */
body.dark-mode .rcx-row-name {
    color: var(--slate-200);
}
body.dark-mode .rcx-track {
    background: var(--slate-700, #334155);
}
body.dark-mode .rcx-gridline {
    background: rgba(15, 23, 42, 0.55);
}
body.dark-mode .rcx-span,
body.dark-mode .rcx-row-swatch {
    background-color: var(--slate-400, #94a3b8);
}
body.dark-mode .rcx-span-label-out .rcx-span-label {
    color: var(--slate-300, #cbd5e1);
}
body.dark-mode .rcx-overlap {
    background: color-mix(in srgb, var(--rc-conflict-red, #dc2626) 32%, transparent);
    border-left-color: rgba(248, 113, 113, 0.9);
    border-right-color: rgba(248, 113, 113, 0.9);
}
body.dark-mode .rcx-tick {
    color: var(--slate-400);
}
body.dark-mode .rcx-row-attendees {
    color: var(--slate-400);
}

body.dark-mode .conflict-action-btn.reschedule-btn,
body.dark-mode .conflict-action-btn.decline-conflict-btn,
body.dark-mode .conflict-action-btn.cancel-conflict-btn {
    background: var(--slate-800);
    color: var(--slate-300);
    border-color: var(--slate-700);
}

body.dark-mode .conflict-action-btn.reschedule-btn:hover {
    background: rgba(59, 130, 246, 0.18);
    color: #93c5fd;
    border-color: rgba(59, 130, 246, 0.4);
}

body.dark-mode .conflict-action-btn.decline-conflict-btn:hover,
body.dark-mode .conflict-action-btn.cancel-conflict-btn:hover {
    background: rgba(248, 113, 113, 0.18);
    color: #fca5a5;
    border-color: rgba(248, 113, 113, 0.4);
}

/* (The full-width CONFLICT PROGRESS band, "Conflict N of M" text + bar +
   stats, was retired in the 2026-08-15 redesign. Its information lives in
   .conflicts-header-count on the single header row.) */

/* Conflict completion state */
.conflicts-complete {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 48px 24px;
    text-align: center;
}

.conflicts-complete i {
    font-size: 3rem;
    color: var(--primary-500);
    animation: successPop 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

.conflicts-complete span {
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--slate-600);
}

@keyframes successPop {
    0% { transform: scale(0); }
    50% { transform: scale(1.1); }
    100% { transform: scale(1); }
}

/* ============================================
   CONFLICT RESOLUTION ANIMATIONS
   ============================================ */

/* Resolution overlay appears on decline — red/declined style */
/* Confirmation that the action landed. Was a 93%-opaque red sheet across the
   whole card — an alarm-coloured takeover for what is usually a routine,
   expected choice, and louder than anything else in the Review Center (a
   .review-item confirms with a small inline strip). Toned to a translucent
   wash so the card underneath stays readable while it slides out: the user
   should be able to see WHAT they just resolved, not have it blanked out. */
.conflict-item .resolution-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: rgba(254, 242, 242, 0.92);
    color: #b91c1c;
    font-size: var(--rc-font-body, 13px);
    font-weight: 600;
    border-radius: inherit;
    box-shadow: inset 0 0 0 1px rgba(220, 38, 38, 0.25);
    z-index: 10;
    animation: overlayIn 200ms ease-out;
}

.conflict-item .resolution-overlay i {
    font-size: 1.25rem;
}

.conflict-item .resolution-overlay span {
    max-width: 260px;
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
}

/* Dim the declined event side in a conflict pair for clarity */
.conflict-event.declined-side {
    opacity: 0.3;
    filter: grayscale(0.5);
    transition: opacity 200ms ease, filter 200ms ease;
}

@keyframes overlayIn {
    from { opacity: 0; transform: scale(0.95); }
    to { opacity: 1; transform: scale(1); }
}

/* Card slides out after resolution */
.conflict-item.resolved {
    animation: slideOutLeft 400ms ease-out forwards;
    pointer-events: none;
}

@keyframes slideOutLeft {
    0% { transform: translateX(0); opacity: 1; }
    100% {
        transform: translateX(-100%);
        opacity: 0;
        height: 0;
        margin: 0;
        padding: 0;
        border-width: 0;
    }
}

/* Next card entrance animation */
.conflict-item.entering {
    animation: slideInRight 300ms ease-out;
}

/* Highlight pulse plays briefly when arriving from a conflict badge.
   The animation is the entire effect — no persistent box-shadow on the
   base rule, so the card returns to its normal Review chrome once the
   pulse finishes. (Previously the rule baked in a permanent red 2px
   ring, which made the panel look like a fire alarm.) */
.conflict-item.conflict-highlight {
    animation: conflictPulse 1.5s ease-out;
}

@keyframes conflictPulse {
    0%   { box-shadow: 0 0 0 4px rgba(220, 38, 38, 0.55), 0 2px 16px rgba(220, 38, 38, 0.35); }
    60%  { box-shadow: 0 0 0 2px rgba(220, 38, 38, 0.35), 0 2px 10px rgba(220, 38, 38, 0.2); }
    100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0), 0 0 0 rgba(220, 38, 38, 0); }
}

@keyframes slideInRight {
    from { transform: translateX(30px); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
}

body.dark-mode .conflicts-complete span {
    color: var(--slate-300);
}

body.dark-mode .conflict-item .resolution-overlay {
    /* Was rgba(20,184,166,.9) — TEAL. The same "Declined"/"Cancelled" overlay
       read as danger in light mode and as success in dark mode; a theme must
       not change what an action MEANS. Same red channel as light, darkened. */
    background: rgba(69, 10, 10, 0.92);
    color: #fca5a5;
    box-shadow: inset 0 0 0 1px rgba(239, 68, 68, 0.3);
}

/* ============================================
   SUB-TABS (Awaiting / Actioned toggle)
   Matches Propose Modal pill-style tabs
   ============================================ */
.review-sub-tabs {
    display: inline-flex;
    gap: 2px;
    padding: 3px;
    /* 12px→8px (2026-07-12 densify): shaves a little vertical chrome above the
       card list without crowding the sub-tab pill. */
    margin-bottom: 8px;
    background: var(--slate-100);
    border-radius: var(--radius-full, 9999px);
}

.sub-tab {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 5px 14px;
    border-radius: var(--radius-full, 9999px);
    font-size: 0.75rem;
    font-weight: 500;
    background: transparent;
    border: none;
    color: var(--slate-500);
    cursor: pointer;
    transition: all 0.15s ease;
}

.sub-tab:hover:not(.active) {
    background: rgba(255, 255, 255, 0.5);
    color: var(--slate-700);
}

.sub-tab.active {
    background: white;
    color: var(--primary-600);
    font-weight: 600;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

.sub-tab i {
    font-size: 0.65rem;
}

.sub-tab .sub-tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 16px;
    padding: 0 5px;
    border-radius: 8px;
    font-size: 0.625rem;
    font-weight: 600;
    background: var(--slate-200);
    color: var(--slate-600);
}

.sub-tab.active .sub-tab-count {
    background: var(--primary-100);
    color: var(--primary-700);
}

/* "Accept all safe (N)" one-shot — the headline velocity affordance. Full-width
   and primary so it reads as "clear the boring ones," sitting above the list. */
.rc-accept-safe-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    margin: 4px 0 2px;
    padding: 11px 14px;
    min-height: 44px;
    font-size: 14px;
    font-weight: 600;
}
.rc-accept-safe-hint {
    margin: 0 0 12px;
    font-size: 12px;
    color: var(--text-secondary, #64748b);
    text-align: center;
}
body.dark-mode .rc-accept-safe-hint { color: #94a3b8; }

/* Requests bulk-approve bar (2026-08-06). Same shape as the "Accept all safe"
   affordance above so the two bulk controls in the panel read as one idea:
   button centred, quiet explanatory hint beneath naming exactly what it acts
   on. */
.rc-requests-bulk {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 4px 0 12px;
}
.rc-requests-bulk-hint {
    font-size: 12px;
    color: var(--text-secondary, #64748b);
    text-align: center;
    max-width: 44ch;
}
body.dark-mode .rc-requests-bulk-hint { color: #94a3b8; }

/* States what a capped organizational group is hiding, rather than truncating
   silently — a shortened list that says nothing reads as the whole list. */
.review-group-truncated {
    margin: 4px 12px 10px;
    font-size: 12px;
    color: var(--text-secondary, #64748b);
    text-align: center;
}
body.dark-mode .review-group-truncated { color: #94a3b8; }

/* "N snoozed · Bring back" — a quiet row so snoozed items stay discoverable. */
.rc-snoozed-link {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    margin: 0 0 12px;
    padding: 8px 12px;
    min-height: 40px;
    background: transparent;
    border: 1px dashed var(--slate-300, #cbd5e1);
    border-radius: var(--radius-md, 8px);
    color: var(--text-secondary, #64748b);
    font-size: 13px;
    cursor: pointer;
}
.rc-snoozed-link:hover { background: var(--slate-50, #f8fafc); }
.rc-snoozed-link .rc-snoozed-action {
    margin-left: auto;
    font-weight: 600;
    color: var(--primary-600, #0d9488);
}
body.dark-mode .rc-snoozed-link { border-color: var(--slate-600, #475569); color: #94a3b8; }
body.dark-mode .rc-snoozed-link:hover { background: var(--slate-800, #1e293b); }

/* RSVP single-tap actions for 1-2-slot proposals — full-width stacked buttons,
   each commits on click (no rank step, no Submit). Replaces the ranked ballot's
   checkbox + Submit row when there are only one or two times to choose between. */
.rc-rsvp-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
}
.rc-rsvp-actions .rc-rsvp-yes,
.rc-rsvp-actions .rc-rsvp-no {
    width: 100%;
    justify-content: center;
    min-height: 44px;
}

/* "Deal with these first" — compact cross-source urgency strip at the top of the
   awaiting view. The merged-feed value (most-urgent across scheduled+proposals)
   without a 4th tab. Each row jumps to its source. */
.rc-urgent-strip {
    margin: 0 0 14px;
    padding: 10px 12px;
    background: color-mix(in srgb, var(--primary-500, #14b8a6) 7%, var(--surface-primary, #fff));
    border: 1px solid color-mix(in srgb, var(--primary-500, #14b8a6) 22%, transparent);
    border-radius: var(--radius-md, 8px);
}
.rc-urgent-head {
    display: flex; align-items: center; gap: 6px;
    font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.3px;
    color: var(--primary-700, #0f766e);
    margin-bottom: 6px;
}
.rc-urgent-row {
    display: flex; align-items: center; gap: 8px;
    width: 100%;
    padding: 8px 6px;
    min-height: 40px;
    background: transparent; border: none;
    border-top: 1px solid color-mix(in srgb, var(--primary-500, #14b8a6) 12%, transparent);
    cursor: pointer;
    font-size: 13px;
    color: var(--text-primary, #0f172a);
    text-align: left;
}
.rc-urgent-row:first-of-type { border-top: none; }
.rc-urgent-row:hover { background: color-mix(in srgb, var(--primary-500, #14b8a6) 8%, transparent); }
.rc-urgent-glyph { color: var(--primary-600, #0d9488); font-size: 12px; flex-shrink: 0; }
.rc-urgent-title { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rc-urgent-due { flex-shrink: 0; font-weight: 600; color: var(--rc-status-warning, #b45309); font-size: 12px; }
.rc-urgent-row .fa-chevron-right { flex-shrink: 0; font-size: 11px; color: var(--slate-400, #94a3b8); }
body.dark-mode .rc-urgent-strip { background: color-mix(in srgb, var(--primary-500, #14b8a6) 12%, var(--slate-800, #1e293b)); }
body.dark-mode .rc-urgent-row { color: var(--slate-200, #e2e8f0); }

/* The "Sent by me" header chip (.rdh-sent-chip / -count / -label / -empty, plus
   its dark-mode and ≤420px blocks) was REMOVED 2026-08-06 — about 55 lines
   styling markup no renderer emitted. "Sent by me" is the third sub-tab of
   Proposals (SUB_TABS.proposals.sent); its count rides the Proposals tab badge
   and the sub-tab's own count, so nothing is lost. */

/* "Back" link + view title for the demoted "Sent by me" view (no tab button
   is active there, so the user needs an explicit way back to the tabs). */
.rc-back-to-tabs {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 6px 10px 6px 6px;
    min-height: 40px;
    margin-bottom: 4px;
    background: transparent;
    border: none;
    color: var(--slate-500, #64748b);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    border-radius: var(--radius-md, 8px);
}
.rc-back-to-tabs:hover { background: var(--slate-100, #f1f5f9); color: var(--slate-700, #334155); }
.rc-view-title {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 12px;
    font-size: 15px;
    font-weight: 600;
    color: var(--slate-700, #334155);
}
.rc-view-title i { color: var(--slate-400, #94a3b8); }
body.dark-mode .rc-back-to-tabs { color: var(--slate-400, #94a3b8); }
body.dark-mode .rc-back-to-tabs:hover { background: var(--slate-700, #334155); color: var(--slate-200, #e2e8f0); }
body.dark-mode .rc-view-title { color: var(--slate-200, #e2e8f0); }

/* Dark mode sub-tabs */
body.dark-mode .review-sub-tabs {
    background: var(--slate-800);
}

body.dark-mode .sub-tab {
    color: var(--slate-400);
}

body.dark-mode .sub-tab:hover:not(.active) {
    background: var(--slate-700);
    color: var(--slate-200);
}

body.dark-mode .sub-tab.active {
    background: var(--slate-700);
    color: var(--primary-400);
}

body.dark-mode .sub-tab .sub-tab-count {
    background: var(--slate-700);
    color: var(--slate-300);
}

body.dark-mode .sub-tab.active .sub-tab-count {
    background: rgba(20, 184, 166, 0.2);
    color: var(--primary-300);
}

/* ============================================
   REVIEW ITEMS
   ============================================ */
.review-items {
    display: flex;
    flex-direction: column;
    gap: 10px;
    /* Reset native ul/li styling — semantic list, no bullets/indent */
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Phase C (C4): use the width on large screens — the awaiting card list goes
   2-up. align-items:start keeps cards their natural height (no stretch-to-match
   ragged rows). If ANY card is expanded (settings/details open) the grid drops
   back to a single column so the open card gets full width — :has() guards
   against a cramped expansion.
   2026-07-12 full-modal redesign: breakpoint lowered 1200px→1040px so the 2-up
   density win kicks in on laptops now that the shell is full-bleed (up to
   min(1600px,96vw)), not just wide desktops. This is the single biggest lever
   for "more decisions per screen". */
@media (min-width: 1040px) {
    .review-items {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        align-items: start;
        gap: 10px 14px;
    }
    .review-items:has(.review-item-settings-panel[style*="block"]),
    .review-items:has(.rc-card-details[style*="block"]) {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* Conflicts go 2-up too, so entering the panel doesn't halve the number of
   decisions on screen — the one place where seeing MORE at once matters most,
   since the complaint is about handling many in one session. Held to a wider
   breakpoint than .review-items (1040px): each card carries a two-lane timeline
   plus an axis, which needs real width before it can be split in half. */
@media (min-width: 1280px) {
    .conflicts-list {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        align-items: start;
        gap: 10px 14px;
    }
}

.review-item {
    background: var(--review-card-bg);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1px solid var(--review-card-border);
    border-radius: var(--rc-radius-card);
    padding: var(--rc-spacing-card);
    box-shadow: var(--review-card-shadow);
    transition: all 0.15s ease;
}

.review-item:hover {
    border-color: var(--primary-300);
    box-shadow: var(--shadow-md), 0 0 0 2px rgba(20, 184, 166, 0.08);
    transform: translateY(-1px);
}

.review-item.urgent {
    border-color: var(--review-urgent);
    border-left-width: 4px;
    background: linear-gradient(135deg, var(--review-urgent-light) 0%, var(--review-card-bg) 100%);
}

.review-item.urgent:hover {
    box-shadow: var(--shadow-md), 0 0 0 3px rgba(239, 68, 68, 0.15);
}

/* Item Header — compact title row */
.review-item-header {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 4px;
    flex-wrap: wrap;
}

/* Meta line for review items (dot-separated) */
.review-meta-line {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0;
    font-size: var(--rc-font-secondary);
    color: var(--slate-500);
    margin-bottom: 4px;
}

.review-meta-line > span {
    white-space: nowrap;
}

.review-meta-line > span:not(:last-child):not(.review-meta-right)::after {
    content: "\00B7";
    margin: 0 6px;
    color: var(--slate-300);
}

/* Right-aligned zone in review meta line (trust/quota/auto-accept badges) */
.review-meta-right {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
    flex-shrink: 0;
}

body.dark-mode .review-meta-line {
    color: var(--slate-400);
}

body.dark-mode .review-meta-line > span:not(:last-child)::after {
    color: var(--slate-600);
}

/* Urgency Badges */
.urgency-badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 7px;
    font-size: var(--rc-font-tiny, 10px);
    font-weight: 500;
    border-radius: var(--radius-full);
    letter-spacing: 0.2px;
}

.urgency-badge.urgency-today {
    background: rgba(239, 68, 68, 0.08);
    color: var(--rc-status-busy);
    border: 1px solid rgba(239, 68, 68, 0.2);
}

.urgency-badge.urgency-tomorrow {
    background: rgba(245, 158, 11, 0.08);
    /* Darker amber for legibility on light background — see --rc-status-tentative
       comment in :root; future -strong token would replace this. */
    color: #b45309;
    border: 1px solid rgba(245, 158, 11, 0.2);
}

.urgency-badge.urgency-later {
    background: var(--slate-100);
    color: var(--slate-500);
    border: 1px solid var(--slate-200);
}

body.dark-mode .urgency-badge.urgency-today {
    background: linear-gradient(135deg, rgba(185, 28, 28, 0.3) 0%, rgba(220, 38, 38, 0.2) 100%);
    color: #fca5a5;
    border-color: rgba(248, 113, 113, 0.4);
}

body.dark-mode .urgency-badge.urgency-tomorrow {
    background: linear-gradient(135deg, rgba(194, 65, 12, 0.3) 0%, rgba(234, 88, 12, 0.2) 100%);
    color: #fdba74;
    border-color: rgba(251, 146, 60, 0.4);
}

body.dark-mode .urgency-badge.urgency-later {
    background: var(--slate-700);
    color: var(--slate-400);
    border-color: var(--slate-600);
}

/* Fairness chip on review-card title row.
   Echoes the Find Times .best-time-fairness-badge grammar — same icon
   (scale-balanced), same 5-band color ramp via --fv-l*, same Excellent/
   Balanced/Mixed/Stretched/Overloaded vocabulary. Sized smaller than
   the propose-modal version so it sits next to the urgency badge
   without dominating the card header. */
.rc-fairness-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 7px;
    font-size: var(--rc-font-tiny, 10px);
    font-weight: 500;
    border-radius: var(--radius-full);
    letter-spacing: 0.2px;
    color: var(--rc-fairness-color, var(--slate-700));
    background: color-mix(in srgb, var(--rc-fairness-color, var(--slate-500)) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--rc-fairness-color, var(--slate-500)) 25%, transparent);
    white-space: nowrap;
}

.rc-fairness-chip i {
    font-size: 0.7em;
    opacity: 0.85;
}

/* Fallback for browsers without color-mix() — use the tint directly,
   which is darker but still respects the band's hue identity. */
@supports not (background: color-mix(in srgb, red 10%, transparent)) {
    .rc-fairness-chip {
        background: transparent;
        border-color: currentColor;
        opacity: 0.85;
    }
}

body.dark-mode .rc-fairness-chip {
    /* In dark mode, color-mix lightens the chip background just enough
       to stay readable on the slate-800 card surface. */
    background: color-mix(in srgb, var(--rc-fairness-color, var(--slate-400)) 15%, transparent);
    border-color: color-mix(in srgb, var(--rc-fairness-color, var(--slate-400)) 35%, transparent);
}

/* Review item border accents for urgency */
.review-item.urgency-today {
    border-left: 3px solid var(--rc-status-busy);
}

.review-item.urgency-tomorrow {
    /* Routed through the attention accent (Stage A) rather than tentative
       amber — original code chose orange deliberately for the "act soon"
       prompt; the token preserves intent. */
    border-left: 3px solid var(--rc-accent-attention-strong);
}

.status-select {
    padding: 4px 24px 4px 10px;
    font-size: 12px;
    font-weight: 600;
    color: var(--slate-600);
    background: var(--slate-100);
    border: 1px solid var(--slate-200);
    border-radius: var(--radius-md);
    cursor: pointer;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'%3E%3Cpath fill='%2364748b' d='M2.5 4L5 6.5L7.5 4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 8px center;
}

body.dark-mode .status-select {
    color: var(--slate-300);
    background-color: var(--slate-700);
    border-color: var(--slate-600);
}

.review-item-title {
    font-size: var(--rc-font-heading);
    font-weight: 600;
    color: var(--slate-800);
    line-height: 1.3;
}

body.dark-mode .review-item-title {
    color: var(--slate-100);
}


.scheduled-by-prominent {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--slate-600);
}

.scheduled-by-prominent i {
    color: var(--primary-500);
    font-size: 13px;
}

.scheduled-by-prominent strong {
    color: var(--slate-800);
}

body.dark-mode .scheduled-by-prominent {
    color: var(--slate-400);
}

body.dark-mode .scheduled-by-prominent strong {
    color: var(--slate-100);
}

/* Trust Indicator */
.trust-indicator {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    font-size: 11px;
    font-weight: 500;
    border-radius: var(--radius-full);
}

.trust-indicator i {
    font-size: 10px;
}

.trust-label {
    font-weight: 600;
}

.trust-auto-accept {
    opacity: 0.8;
    font-weight: 400;
}

/* Trust level colors. green/amber reuse traffic-light tokens for visual
   consistency with the rest of the status surfaces; blue is categorical
   (organizational); slate is the unknown/default. */
.trust-indicator.trust-green {
    color: var(--rc-status-working);
    background: rgba(34, 197, 94, 0.12);
}

.trust-indicator.trust-blue {
    color: #2563eb;
    background: rgba(59, 130, 246, 0.12);
}

.trust-indicator.trust-amber {
    /* Darker amber for legibility — see urgency-tomorrow comment. */
    color: #d97706;
    background: rgba(245, 158, 11, 0.12);
}

.trust-indicator.trust-slate {
    color: var(--slate-600);
    background: rgba(100, 116, 139, 0.12);
}

body.dark-mode .trust-indicator.trust-green {
    color: #4ade80;
    background: rgba(34, 197, 94, 0.2);
}

body.dark-mode .trust-indicator.trust-blue {
    color: #60a5fa;
    background: rgba(59, 130, 246, 0.2);
}

body.dark-mode .trust-indicator.trust-amber {
    color: #fbbf24;
    background: rgba(245, 158, 11, 0.2);
}

body.dark-mode .trust-indicator.trust-slate {
    color: var(--slate-400);
    background: rgba(148, 163, 184, 0.15);
}

/* Trust level styling on review item.
   organizational uses brand blue (categorical, not status); trusted/known
   reuse the available/tentative status tokens to read consistently with
   the rest of the traffic-light surfaces. */
.review-item.trust-level-organizational {
    border-left: 4px solid #3b82f6;
}

.review-item.trust-level-trusted {
    border-left: 4px solid var(--rc-status-available);
}

.review-item.trust-level-known {
    border-left: 4px solid var(--rc-status-tentative);
}

.review-item.trust-level-unknown {
    border-left: 4px solid var(--slate-400);
}

/* Quota Badge */
/* Quota summary strip — sits once above the awaiting list. */
.rc-quota-summary {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 8px;
}
.rc-quota-summary .quota-badge { margin-left: 0; }

.quota-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px;
    font-size: 11px;
    font-weight: 600;
    border-radius: var(--radius-full);
    margin-left: auto;
}

.quota-badge i {
    font-size: 10px;
}

.quota-badge.quota-green {
    color: var(--rc-status-working);
    background: rgba(34, 197, 94, 0.12);
}

.quota-badge.quota-amber {
    /* Darker amber for legibility — see urgency-tomorrow note. */
    color: #d97706;
    background: rgba(245, 158, 11, 0.12);
}

.quota-badge.quota-red {
    color: var(--rc-status-busy);
    background: rgba(239, 68, 68, 0.12);
}

body.dark-mode .quota-badge.quota-green {
    color: #4ade80;
    background: rgba(34, 197, 94, 0.2);
}

body.dark-mode .quota-badge.quota-amber {
    color: #fbbf24;
    background: rgba(245, 158, 11, 0.2);
}

body.dark-mode .quota-badge.quota-red {
    color: #f87171;
    background: rgba(239, 68, 68, 0.2);
}

/* Quota Over State */
.quota-badge.quota-over {
    font-weight: 700;
}

/* Pending Hours Hint */
/* Muted "Schedulable:" qualifier so "Xh available" can't be read as the
   app's separate free-to-meet availability concept. */
.quota-badge-label {
    font-weight: 500;
    opacity: 0.7;
    margin-right: 1px;
}

.quota-pending-hint {
    font-size: 10px;
    font-weight: 500;
    opacity: 0.7;
    margin-left: 2px;
}

/* Enhanced Tooltip Styling */
.quota-badge[title] {
    cursor: help;
    position: relative;
}

.quota-badge[title]:hover::after {
    content: attr(title);
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    padding: 8px 12px;
    background: var(--slate-900);
    color: white;
    font-size: 11px;
    font-weight: 500;
    border-radius: var(--radius-md);
    white-space: nowrap;
    z-index: var(--z-dropdown);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    pointer-events: none;
}

.quota-badge[title]:hover::before {
    content: '';
    position: absolute;
    bottom: calc(100% + 2px);
    left: 50%;
    transform: translateX(-50%);
    border: 6px solid transparent;
    border-top-color: var(--slate-900);
    z-index: var(--z-dropdown);
    pointer-events: none;
}

body.dark-mode .quota-badge[title]:hover::after {
    background: var(--slate-100);
    color: var(--slate-900);
}

body.dark-mode .quota-badge[title]:hover::before {
    border-top-color: var(--slate-100);
}

/* Status Badge */
.review-status-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    font-size: 12px;
    font-weight: 600;
    border-radius: var(--radius-full);
    white-space: nowrap;
}

.review-status-badge.in-review {
    color: var(--review-warning);
    background: var(--review-warning-light);
}

.review-status-badge.in-review::before {
    content: '';
    width: 8px;
    height: 8px;
    background: var(--review-warning);
    border-radius: 50%;
}

.review-status-badge.accepted {
    color: var(--review-success);
    background: var(--review-success-light);
}

.review-status-badge.accepted::before {
    content: '\f00c';
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    font-size: 10px;
}

@keyframes statusPulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.5; }
}


.review-date {
    font-weight: 500;
}

.review-time {
    color: var(--slate-500);
}

.review-event-type {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: 10px;
    font-weight: 600;
    padding: 1px 7px;
    border-radius: var(--radius-full);
    text-transform: capitalize;
}

.review-type-work {
    background: rgba(59, 130, 246, 0.1);
    color: #2563eb;
    border: 1px solid rgba(59, 130, 246, 0.25);
}

.review-type-personal {
    background: rgba(244, 114, 182, 0.1);
    color: #db2777;
    border: 1px solid rgba(244, 114, 182, 0.25);
}

/* Quota-assigned shift items use the shift palette (amber) so they're
   distinguishable from generic work meetings in the inbox. */
.review-type-shift {
    background: rgba(245, 158, 11, 0.12);
    color: #b45309;
    border: 1px solid rgba(245, 158, 11, 0.3);
}
.review-item:has(.review-type-shift) {
    border-left: 3px solid rgba(245, 158, 11, 0.55);
}

/* Time-off proposals from the workbench (eventType: 'leave'). Teal so
   they're visually distinct from shift items, which they'll often sit
   next to in the inbox. */
.review-type-leave {
    background: rgba(20, 184, 166, 0.12);
    color: #0f766e;
    border: 1px solid rgba(20, 184, 166, 0.3);
}
.review-item:has(.review-type-leave) {
    border-left: 3px solid rgba(20, 184, 166, 0.55);
}

.review-duration {
    font-size: 11px;
    color: var(--slate-400);
    display: inline-flex;
    align-items: center;
    gap: 3px;
}

body.dark-mode .review-type-work {
    background: rgba(59, 130, 246, 0.2);
    color: #60a5fa;
    border-color: rgba(59, 130, 246, 0.35);
}

body.dark-mode .review-type-personal {
    background: rgba(244, 114, 182, 0.2);
    color: #f9a8d4;
    border-color: rgba(244, 114, 182, 0.35);
}

body.dark-mode .review-type-shift {
    background: rgba(245, 158, 11, 0.22);
    color: #fbbf24;
    border-color: rgba(245, 158, 11, 0.4);
}

body.dark-mode .review-type-leave {
    background: rgba(20, 184, 166, 0.22);
    color: #5eead4;
    border-color: rgba(20, 184, 166, 0.4);
}

body.dark-mode .review-duration {
    color: var(--slate-500);
}

.review-time::before {
    content: '·';
    margin-right: 8px;
}

/* Item Meta */
.review-item-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
    font-size: 13px;
}

.scheduled-by {
    color: var(--slate-500);
}

.scheduled-by::before {
    content: '\f007';
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    margin-right: 6px;
    font-size: 11px;
}

body.dark-mode .scheduled-by {
    color: var(--slate-400);
}

/* Auto-accept Timer */
.auto-accept-timer {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    font-size: 12px;
    font-weight: 500;
    color: var(--slate-600);
    background: var(--slate-100);
    border-radius: var(--radius-full);
}

.auto-accept-timer.urgent {
    color: var(--review-urgent);
    background: var(--review-urgent-light);
    font-weight: 600;
}

body.dark-mode .auto-accept-timer {
    color: var(--slate-300);
    background: var(--slate-700);
}

/* Review Note */
.review-note {
    padding: 6px 10px;
    margin-bottom: var(--rc-spacing-section);
    font-size: var(--rc-font-secondary);
    color: var(--slate-600);
    background: var(--slate-50);
    border-radius: var(--rc-radius-btn);
    border-left: 3px solid var(--primary-400);
}

.review-note .note-label {
    font-weight: 600;
    color: var(--slate-700);
}

body.dark-mode .review-note {
    color: var(--slate-300);
    background: rgba(255, 255, 255, 0.05);
}

body.dark-mode .review-note .note-label {
    color: var(--slate-200);
}

/* ============================================
   SETTINGS TOGGLE & PANEL
   ============================================ */
.settings-toggle-btn {
    display: flex;
    align-items: center;
    gap: 5px;
    width: 100%;
    padding: 5px 10px;
    margin-bottom: 4px;
    font-size: var(--rc-font-caption);
    font-weight: 600;
    color: var(--slate-500);
    background: var(--slate-50);
    border: 1px solid var(--slate-200);
    border-radius: var(--rc-radius-btn);
    cursor: pointer;
    transition: all 0.15s ease;
}

.settings-toggle-btn:hover {
    color: var(--primary-700);
    background: var(--primary-50);
    border-color: var(--primary-300);
}

.settings-toggle-btn i:first-child {
    font-size: var(--rc-font-caption);
    color: var(--slate-400);
    transition: color 0.15s ease;
}

.settings-toggle-btn:hover i:first-child {
    color: var(--primary-500);
}

.settings-chevron {
    margin-left: auto;
    font-size: 12px;
    transition: transform var(--transition-base);
}

.settings-chevron.expanded {
    transform: rotate(180deg);
}

body.dark-mode .settings-toggle-btn {
    color: var(--slate-300);
    background: linear-gradient(135deg, var(--slate-800) 0%, var(--slate-700) 100%);
    border-color: var(--slate-600);
}

body.dark-mode .settings-toggle-btn:hover {
    color: var(--primary-300);
    background: linear-gradient(135deg, rgba(20, 184, 166, 0.1) 0%, var(--slate-700) 100%);
    border-color: var(--primary-500);
}

/* Settings Panel */
.review-item-settings-panel {
    padding: 20px;
    margin-bottom: 16px;
    background: linear-gradient(135deg, var(--slate-50) 0%, white 100%);
    border: 1px solid var(--slate-200);
    border-radius: var(--radius-lg);
    animation: slideDown 0.2s ease-out;
}

@keyframes slideDown {
    from {
        opacity: 0;
        transform: translateY(-8px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.settings-section {
    padding: 16px 0;
    border-bottom: 1px solid var(--slate-100);
}

.settings-section:last-child {
    border-bottom: none;
    padding-bottom: 0;
}

.settings-section:first-child {
    padding-top: 0;
}

.settings-label {
    display: block;
    font-size: 12px;
    font-weight: 700;
    color: var(--slate-500);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    margin-bottom: 12px;
}

body.dark-mode .review-item-settings-panel {
    background: linear-gradient(135deg, var(--slate-800) 0%, var(--slate-700) 100%);
    border-color: var(--slate-600);
}

body.dark-mode .settings-section {
    border-color: var(--slate-600);
}

body.dark-mode .settings-label {
    color: var(--slate-400);
}

/* ============================================
   VISIBILITY OPTIONS
   ============================================ */
/* SEGMENTED, like the synced rows (2026-08-16, user: "Clicking the options
   could be better designed"). Three detached outlined buttons separated by a
   10px gap read as three independent toggles; this is ONE question with three
   answers, so it gets one track. Excludes .rc-vis-apply-btn, which also
   carries .visibility-btn but is a CONFIRM, not a choice. */
.visibility-options {
    display: flex;
    gap: 0;
    /* NO WRAP (2026-08-16, measured on the live render): the inherited
       flex-wrap:wrap let the three segments overlap each other by 81px at
       390px, because each kept its natural width inside a narrower track.
       A segmented control is one row by definition — let the segments SHARE
       the width instead of overflowing it. */
    flex-wrap: nowrap;
    width: 100%;
    padding: 2px;
    border: 1px solid var(--border-color, #e2e8f0);
    border-radius: 8px;
    background: var(--slate-100, #f1f5f9);
}
.visibility-options .visibility-btn:not(.rc-vis-apply-btn) {
    /* Equal shares of the track, and allowed to shrink below content width. */
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
    white-space: nowrap;
    border-color: transparent;
    background: transparent;
    border-radius: 6px;
    font-weight: 500;
}
.visibility-options .visibility-btn:not(.rc-vis-apply-btn) + .visibility-btn:not(.rc-vis-apply-btn) {
    box-shadow: inset 1px 0 0 var(--slate-200, #e2e8f0);
}
/* Drop the divider on the segment AFTER the selected/hovered one, and on the
   selected one ITSELF. box-shadow does not stack across rules — the later or
   more specific declaration REPLACES it — so without this the adjacent-sibling
   divider above out-specified the active rule and the selected segment lost
   its lift entirely (measured on the live render: inset divider only, no
   elevation). Suppress the divider here so the lift below is what survives. */
.visibility-options .visibility-btn.active + .visibility-btn:not(.rc-vis-apply-btn),
.visibility-options .visibility-btn:hover + .visibility-btn:not(.rc-vis-apply-btn),
.visibility-options .visibility-btn.active:not(.rc-vis-apply-btn) + .visibility-btn:not(.rc-vis-apply-btn) {
    box-shadow: none;
}
.visibility-options .visibility-btn:not(.rc-vis-apply-btn):hover {
    background: rgba(255, 255, 255, 0.6);
}
/* Selected lifts on a white card and keeps its level hue in the text/icon,
   rather than flooding the row with a saturated teal fill.
   `:not(.rc-vis-apply-btn):not(:disabled)` is doing SPECIFICITY work, not
   filtering: the adjacent-sibling divider rule above is a compound selector
   and would otherwise replace this box-shadow, leaving the selection with no
   elevation at all. */
.visibility-options .visibility-btn.active:not(.rc-vis-apply-btn):not(:disabled) {
    background: var(--bg-primary, #fff);
    border-color: var(--border-color, #e2e8f0);
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
    font-weight: 600;
}
.visibility-options .visibility-btn.active[data-visibility="hidden"] { color: #7c3aed; }
.visibility-options .visibility-btn.active[data-visibility="busy"] { color: #b45309; }
.visibility-options .visibility-btn.active[data-visibility="full"] { color: var(--rc-status-working); }
.visibility-options .visibility-btn.active:not(.rc-vis-apply-btn) i { color: inherit; }

body.dark-mode .visibility-options {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
}
body.dark-mode .visibility-options .visibility-btn.active:not(.rc-vis-apply-btn) {
    background: var(--slate-700, #334155);
    border-color: var(--slate-600, #475569);
}

.visibility-btn {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 6px 12px;
    font-size: 12px;
    font-weight: 500;
    color: var(--slate-600);
    background: white;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: all var(--transition-fast);
}

.visibility-btn:hover {
    color: var(--slate-800);
    background: var(--slate-50);
    border-color: var(--slate-300);
}

.visibility-btn.active {
    color: white;
    background: var(--primary-500);
    border-color: transparent;
    box-shadow: 0 2px 8px rgba(20, 184, 166, 0.3);
}

.visibility-btn i {
    font-size: 11px;
}

/* Visibility level colours (2026-08-04): Purple=Private, Amber=Busy,
   Green=Shared — the app-wide privacy scale from privacy-visual-config.js
   (purple = private/protective, matching the day-panel pill and board
   presets). Replaces the old traffic-light red for "hidden", which read as
   error/danger here while every other surface painted the level purple. */
.visibility-btn[data-visibility="hidden"] i {
    color: var(--visibility-private, #8b5cf6);
}

.visibility-btn[data-visibility="busy"] i {
    color: var(--rc-status-tentative);
}

.visibility-btn[data-visibility="full"] i {
    color: var(--rc-status-available);
}

/* Hidden/Private - Purple */
.visibility-btn[data-visibility="hidden"]:hover {
    color: #7c3aed;
    background: rgba(139, 92, 246, 0.08);
    border-color: rgba(139, 92, 246, 0.3);
}

.visibility-btn[data-visibility="hidden"].active {
    color: white;
    background: var(--visibility-private, #8b5cf6);
    border-color: transparent;
    box-shadow: 0 2px 8px rgba(139, 92, 246, 0.3);
}

/* Busy - Amber */
.visibility-btn[data-visibility="busy"]:hover {
    /* Darker amber for legibility on tinted background — see urgency-tomorrow note. */
    color: #d97706;
    background: rgba(245, 158, 11, 0.08);
    border-color: rgba(245, 158, 11, 0.3);
}

.visibility-btn[data-visibility="busy"].active {
    color: white;
    background: var(--rc-status-tentative);
    border-color: transparent;
    box-shadow: 0 2px 8px rgba(245, 158, 11, 0.3);
}

/* Full/Open - Green */
.visibility-btn[data-visibility="full"]:hover {
    color: var(--rc-status-working);
    background: rgba(34, 197, 94, 0.08);
    border-color: rgba(34, 197, 94, 0.3);
}

.visibility-btn[data-visibility="full"].active {
    color: white;
    background: var(--rc-status-available);
    border-color: transparent;
    box-shadow: 0 2px 8px rgba(34, 197, 94, 0.3);
}

body.dark-mode .visibility-btn {
    color: var(--slate-300);
    background: var(--slate-700);
    border-color: var(--slate-600);
}

body.dark-mode .visibility-btn:hover {
    color: var(--slate-100);
    background: var(--slate-600);
}

/* Dark mode visibility colours (purple / amber / green) */
body.dark-mode .visibility-btn[data-visibility="hidden"] i {
    color: #a78bfa;
}

body.dark-mode .visibility-btn[data-visibility="busy"] i {
    color: #fbbf24;
}

body.dark-mode .visibility-btn[data-visibility="full"] i {
    color: #4ade80;
}

body.dark-mode .visibility-btn[data-visibility="hidden"]:hover {
    color: #a78bfa;
    background: rgba(139, 92, 246, 0.15);
    border-color: rgba(167, 139, 250, 0.4);
}

body.dark-mode .visibility-btn[data-visibility="hidden"].active {
    color: white;
    background: var(--visibility-private, #8b5cf6);
}

body.dark-mode .visibility-btn[data-visibility="busy"]:hover {
    color: #fbbf24;
    background: rgba(245, 158, 11, 0.15);
    border-color: rgba(245, 158, 11, 0.4);
}

body.dark-mode .visibility-btn[data-visibility="busy"].active {
    color: white;
    background: var(--rc-status-tentative);
}

body.dark-mode .visibility-btn[data-visibility="full"]:hover {
    color: #4ade80;
    background: rgba(34, 197, 94, 0.15);
    border-color: rgba(34, 197, 94, 0.4);
}

body.dark-mode .visibility-btn[data-visibility="full"].active {
    color: white;
    background: var(--rc-status-available);
}

/* ============================================
   AUTO-ACCEPT CONFIG
   ============================================ */
.auto-accept-config {
    display: flex;
    align-items: center;
    gap: 24px;
    flex-wrap: wrap;
}

/* Premium Toggle Switch */
.toggle-switch {
    display: flex;
    align-items: center;
    gap: 12px;
    cursor: pointer;
}

.toggle-switch input[type="checkbox"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
}

.toggle-slider {
    position: relative;
    width: 44px;
    height: 24px;
    background: var(--slate-200);
    border-radius: var(--radius-full);
    transition: all var(--transition-fast);
}

.toggle-slider::after {
    content: '';
    position: absolute;
    top: 3px;
    left: 3px;
    width: 18px;
    height: 18px;
    background: white;
    border-radius: 50%;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
    transition: transform var(--transition-fast);
}

.toggle-switch input[type="checkbox"]:checked + .toggle-slider {
    background: var(--primary-500);
}

.toggle-switch input[type="checkbox"]:checked + .toggle-slider::after {
    transform: translateX(20px);
}

.toggle-switch input[type="checkbox"]:focus + .toggle-slider {
    box-shadow: var(--focus-ring-shadow);
}

.toggle-label {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--slate-700);
}

body.dark-mode .toggle-slider {
    background: var(--slate-600);
}

body.dark-mode .toggle-slider::after {
    background: var(--slate-200);
}

body.dark-mode .toggle-label {
    color: var(--slate-200);
}

/* Period Selector */
.auto-accept-period {
    display: flex;
    align-items: center;
    gap: 10px;
    transition: opacity var(--transition-fast);
}

.auto-accept-period.disabled {
    opacity: 0.4;
    pointer-events: none;
}

.auto-accept-period label {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--slate-600);
}

.auto-accept-period-select {
    padding: 6px 28px 6px 10px;
    font-size: 12px;
    font-weight: 500;
    color: var(--slate-700);
    background: white;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius-md);
    cursor: pointer;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M3 4.5L6 7.5L9 4.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    transition: all var(--transition-fast);
}

.auto-accept-period-select:hover {
    border-color: var(--slate-300);
}

.auto-accept-period-select:focus {
    outline: none;
    border-color: var(--primary-400);
    box-shadow: var(--focus-ring-shadow);
}

body.dark-mode .auto-accept-period label {
    color: var(--slate-400);
}

body.dark-mode .auto-accept-period-select {
    color: var(--slate-200);
    background-color: var(--slate-700);
    border-color: var(--slate-600);
}

/* ============================================
   PERMISSION CONFIG
   ============================================ */
.permission-config {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.permission-level-select {
    padding: 6px 30px 6px 10px;
    font-size: 12px;
    font-weight: 500;
    color: var(--slate-700);
    background: white;
    border: 1px solid var(--slate-200);
    border-radius: 6px;
    cursor: pointer;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%2364748b' d='M3 4.5L6 7.5L9 4.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    min-width: 180px;
    transition: all var(--transition-fast);
}

.permission-level-select:hover {
    border-color: var(--slate-300);
}

.permission-level-select:focus {
    outline: none;
    border-color: var(--primary-400);
    box-shadow: var(--focus-ring-shadow);
}

body.dark-mode .permission-level-select {
    color: var(--slate-200);
    background-color: var(--slate-700);
    border-color: var(--slate-600);
}

/* Revoke Access Button */
.revoke-access-btn {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 6px 14px;
    font-size: 12px;
    font-weight: 500;
    color: var(--review-urgent);
    background: var(--review-urgent-light);
    border: 1px solid rgba(239, 68, 68, 0.2);
    border-radius: 6px;
    cursor: pointer;
    transition: all 0.15s ease;
}

.revoke-access-btn:hover {
    color: white;
    background: var(--review-urgent);
    border-color: var(--review-urgent);
}

.revoke-access-btn i {
    font-size: 11px;
}

body.dark-mode .revoke-access-btn {
    background: rgba(239, 68, 68, 0.15);
    border-color: rgba(239, 68, 68, 0.3);
}

/* ============================================
   ACTION BUTTONS & INPUT
   ============================================ */
.review-item-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.review-note-input {
    width: 100%;
    padding: 6px 10px;
    font-size: 12px;
    font-family: inherit;
    color: var(--slate-700);
    background: white;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius-md);
    transition: all var(--transition-fast);
}

.review-note-input::placeholder {
    color: var(--slate-400);
}

.review-note-input:focus {
    outline: none;
    border-color: var(--primary-400);
    box-shadow: var(--focus-ring-shadow);
}

body.dark-mode .review-note-input {
    color: var(--slate-200);
    background: var(--slate-700);
    border-color: var(--slate-600);
}

body.dark-mode .review-note-input::placeholder {
    color: var(--slate-500);
}

/* Action buttons row (trust-based) */
.review-actions-row {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    flex-wrap: wrap;
    /* 10→6px (2026-07-12 densify): the card body's own gap already separates the
       actions from the status line; the extra 4px just grew every card. */
    margin-top: 6px;
}

/* .review-actions-row .btn sizing now inherits from .review-panel .btn reset */

.review-actions-row .btn i {
    margin-right: 4px;
    font-size: 11px;
}

/* Accepted (actioned) card: a read-only status + Undo, left-aligned so it
   reads as a state rather than a fresh decision. */
.review-actions-actioned {
    justify-content: space-between;
}
.rc-actioned-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--rc-status-available, #16a34a);
}
.rc-actioned-badge i { font-size: 12px; }
body.dark-mode .rc-actioned-badge { color: #4ade80; }
/* Tentative accepts read amber (the tentative status hue), not green. */
.rc-actioned-badge.rc-actioned-tentative { color: var(--rc-status-tentative, #f59e0b); }
body.dark-mode .rc-actioned-badge.rc-actioned-tentative { color: #fbbf24; }

/* Danger outline button for Decline */
.btn.btn-danger-outline {
    color: var(--rc-status-busy);
    background: transparent;
    border: 1px solid rgba(239, 68, 68, 0.3);
}

.btn.btn-danger-outline:hover {
    color: white;
    background: var(--rc-status-busy);
    border-color: var(--rc-status-busy);
}

body.dark-mode .btn.btn-danger-outline {
    color: #f87171;
    border-color: rgba(248, 113, 113, 0.3);
}

body.dark-mode .btn.btn-danger-outline:hover {
    color: white;
    background: #ef4444;
}

/* Icon button for more options */
.btn.btn-icon {
    width: 36px;
    height: 36px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--slate-100);
    border: 1px solid var(--slate-200);
    border-radius: var(--radius-md);
    color: var(--slate-500);
    cursor: pointer;
    transition: all var(--transition-fast);
}

.btn.btn-icon:hover {
    background: var(--slate-200);
    color: var(--slate-700);
}

body.dark-mode .btn.btn-icon {
    background: var(--slate-700);
    border-color: var(--slate-600);
    color: var(--slate-400);
}

body.dark-mode .btn.btn-icon:hover {
    background: var(--slate-600);
    color: var(--slate-200);
}

/* More options dropdown */
.more-options-dropdown {
    position: relative;
    z-index: 10;
}

.dropdown-menu {
    position: absolute;
    bottom: 100%;
    right: 0;
    margin-bottom: 4px;
    min-width: 200px;
    padding: 6px;
    background: white;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    z-index: 100;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    /* Explicit props, not `all`: animating `all` on a visibility-toggled
       element animates `visibility` and can leave the menu lingering /
       flickering (the presets-visibility-desync trap). */
    transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s ease;
}

.dropdown-menu.show {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

body.dark-mode .dropdown-menu {
    background: var(--slate-800);
    border-color: var(--slate-700);
}

.dropdown-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 7px 12px;
    font-size: 12px;
    font-weight: 500;
    color: var(--slate-700);
    background: transparent;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    text-align: left;
    transition: all 0.15s ease;
}

.dropdown-item:hover {
    background: var(--slate-100);
    color: var(--slate-900);
}

.dropdown-item i {
    width: 14px;
    font-size: 11px;
    color: var(--slate-500);
}

body.dark-mode .dropdown-item {
    color: var(--slate-300);
}

body.dark-mode .dropdown-item:hover {
    background: var(--slate-700);
    color: var(--slate-100);
}

body.dark-mode .dropdown-item i {
    color: var(--slate-400);
}

/* Legacy action buttons */
.action-buttons {
    display: flex;
    gap: 6px;
}

.action-buttons .btn {
    padding: 6px 14px;
    font-size: 12px;
    font-weight: 500;
    border-radius: 6px;
    cursor: pointer;
    transition: all 0.15s ease;
    white-space: nowrap;
}

.action-buttons .btn-primary {
    color: white;
    background: var(--primary-500);
    border: none;
}

.action-buttons .btn-primary:hover {
    background: var(--primary-600);
}

.action-buttons .btn i {
    margin-right: 4px;
    font-size: 11px;
}

.action-buttons .btn-secondary {
    color: var(--slate-600);
    background: white;
    border: 1px solid var(--slate-200);
}

.action-buttons .btn-secondary:hover {
    color: var(--slate-800);
    background: var(--slate-50);
    border-color: var(--slate-300);
}

body.dark-mode .action-buttons .btn-secondary {
    color: var(--slate-300);
    background: var(--slate-700);
    border-color: var(--slate-600);
}

body.dark-mode .action-buttons .btn-secondary:hover {
    color: var(--slate-100);
    background: var(--slate-600);
}

/* Review Hint */
.review-hint {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 12px;
    font-size: 12px;
    color: var(--slate-400);
    font-style: italic;
}

.review-hint i {
    color: var(--slate-300);
    font-size: 11px;
}

body.dark-mode .review-hint {
    color: var(--slate-500);
}

body.dark-mode .review-hint i {
    color: var(--slate-500);
}

/* ============================================
   REVIEW GROUP (Accept All)
   ============================================ */
.review-group {
    margin-bottom: 24px;
}

.review-group-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    margin-bottom: 12px;
    background: rgba(20, 184, 166, 0.05);
    border: 1px solid var(--primary-200);
    border-radius: var(--radius-md);
}

.group-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.group-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--slate-800);
}

.group-count {
    font-size: 11px;
    color: var(--slate-500);
}

.accept-all-btn {
    padding: 6px 14px;
    font-size: 12px;
    font-weight: 600;
    color: white;
    background: var(--primary-500);
    border: none;
    border-radius: 6px;
    cursor: pointer;
    transition: all 0.15s ease;
}

.accept-all-btn:hover {
    background: var(--primary-600);
}

.accept-all-btn i {
    margin-right: 4px;
}

.group-name i {
    color: var(--primary-500);
    margin-right: 6px;
}

body.dark-mode .review-group-header {
    background: linear-gradient(135deg, rgba(20, 184, 166, 0.15) 0%, var(--slate-800) 100%);
    border-color: var(--primary-600);
}

body.dark-mode .group-name {
    color: var(--slate-100);
}

body.dark-mode .group-count {
    color: var(--slate-400);
}

/* ============================================
   EMPTY STATES
   ============================================ */
.review-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 36px 20px;
    text-align: center;
}

/* Retry button in the per-tab error state (was inline-styled in the JS). */
.review-retry-btn {
    margin-top: 8px;
    padding: 6px 16px;
    border-radius: 6px;
    border: 1px solid var(--border-color, #e2e8f0);
    background: var(--bg-secondary, #f8fafc);
    color: var(--text-primary, #334155);
    font-weight: 600;
    cursor: pointer;
}
.review-retry-btn:hover { background: var(--slate-200, #e2e8f0); }
body.dark-mode .review-retry-btn {
    border-color: var(--slate-700, #334155);
    background: var(--slate-800, #1e293b);
    color: var(--slate-200, #e2e8f0);
}

.review-empty .empty-icon {
    font-size: 36px;
    margin-bottom: 12px;
    opacity: 0.5;
}

.review-empty .empty-icon i {
    color: var(--primary-400);
}

.review-empty p {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--slate-500);
}

body.dark-mode .review-empty p {
    color: var(--slate-400);
}

/* ============================================
   PROPOSALS TAB
   ============================================ */

/* All caught up message */
.proposals-all-voted {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 16px;
    margin-bottom: 14px;
    background: linear-gradient(135deg, rgba(16, 185, 129, 0.08) 0%, rgba(16, 185, 129, 0.03) 100%);
    border: 1px solid rgba(16, 185, 129, 0.2);
    border-radius: var(--radius-lg);
    text-align: center;
}

.all-voted-icon {
    font-size: 28px;
    color: var(--rc-status-available);
    margin-bottom: 8px;
}

.all-voted-text {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--slate-800);
    margin: 0 0 2px 0;
}

.all-voted-subtext {
    font-size: 0.75rem;
    color: var(--slate-500);
    margin: 0;
}

body.dark-mode .proposals-all-voted {
    background: linear-gradient(135deg, rgba(16, 185, 129, 0.15) 0%, rgba(16, 185, 129, 0.08) 100%);
    border-color: rgba(16, 185, 129, 0.3);
}

body.dark-mode .all-voted-icon {
    color: #34d399;
}

body.dark-mode .all-voted-text {
    color: var(--slate-100);
}

body.dark-mode .all-voted-subtext {
    color: var(--slate-400);
}

/* Proposals Sections (Needs Vote / Already Voted) */
.proposals-section {
    margin-bottom: 24px;
}

.proposals-section:last-child {
    margin-bottom: 0;
}

.proposals-section-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    margin-bottom: 16px;
    background: var(--slate-50);
    border-radius: var(--radius-lg);
    border-left: 4px solid var(--review-warning);
}

.proposals-section-pending .proposals-section-header {
    border-left-color: var(--review-warning);
    background: linear-gradient(135deg, rgba(245, 158, 11, 0.08) 0%, var(--slate-50) 100%);
}

.proposals-section-voted .proposals-section-header {
    border-left-color: var(--review-success);
    background: linear-gradient(135deg, rgba(16, 185, 129, 0.08) 0%, var(--slate-50) 100%);
}

.section-icon {
    font-size: 14px;
    color: var(--review-warning);
}

.section-icon.voted {
    color: var(--review-success);
}

.section-title {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--slate-700);
    flex: 1;
}

.section-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    font-size: 12px;
    font-weight: 700;
    color: white;
    background: var(--review-warning);
    border-radius: var(--radius-full);
}

.proposals-section-voted .section-count {
    background: var(--review-success);
}

body.dark-mode .proposals-section-header {
    background: var(--slate-800);
}

body.dark-mode .proposals-section-pending .proposals-section-header {
    background: linear-gradient(135deg, rgba(245, 158, 11, 0.12) 0%, var(--slate-800) 100%);
}

body.dark-mode .proposals-section-voted .proposals-section-header {
    background: linear-gradient(135deg, rgba(16, 185, 129, 0.12) 0%, var(--slate-800) 100%);
}

body.dark-mode .section-title {
    color: var(--slate-200);
}

body.dark-mode .section-icon {
    color: #fbbf24;
}

body.dark-mode .section-icon.voted {
    color: #34d399;
}

.proposals-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    /* The first card carries the priority badge (.proposal-priority-badge,
       top:-6px overhang). Without clearance the badge tucks up under the
       sub-tab strip above and its top is clipped. 8px lets the overhang
       sit clear of the strip. */
    padding-top: 8px;
}

.proposal-item {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--rc-spacing-section);
    padding: var(--rc-spacing-card);
    background: var(--review-card-bg, white);
    border: 1px solid var(--slate-200);
    border-radius: var(--rc-radius-card);
    transition: all 0.2s ease;
}

.proposal-item:hover {
    border-color: var(--primary-200);
    box-shadow: 0 2px 8px rgba(20, 184, 166, 0.08);
}

.proposal-header {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-bottom: var(--rc-spacing-section);
}

/* Title row: [Type Badge] Title [Voted] [Mode] */
.proposal-title-row {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

/* Right-aligned deadline in title row */
.proposal-title-right {
    display: flex;
    align-items: center;
    gap: 4px;
    margin-left: auto;
    flex-shrink: 0;
    white-space: nowrap;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
}

body.dark-mode .proposal-title-right {
    color: var(--slate-400);
}

/* Meta line */
.proposal-meta-line {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0;
    font-size: var(--rc-font-secondary);
    color: var(--slate-500);
}

.proposal-meta-line > span {
    white-space: nowrap;
}

.proposal-meta-line > span:not(:last-child):not(.proposal-meta-right)::after {
    content: "\00B7";
    margin: 0 6px;
    color: var(--slate-300);
}

/* Right-aligned zone in meta line (participants + voted) */
.proposal-meta-right {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-left: auto;
    flex-shrink: 0;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
}

.proposal-meta-right > span {
    white-space: nowrap;
}

body.dark-mode .proposal-meta-right {
    color: var(--slate-400);
}

/* Vote progress chip — bar + count, sits in proposal-meta-right */
.proposal-vote-progress {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.proposal-vote-progress-bar {
    display: inline-block;
    width: 48px;
    height: 4px;
    background: var(--slate-200);
    border-radius: 2px;
    overflow: hidden;
}

.proposal-vote-progress-fill {
    display: block;
    height: 100%;
    background: var(--rc-status-available);
    border-radius: 2px;
    transition: width 200ms ease;
}

.proposal-vote-progress-text {
    font-size: var(--rc-font-caption, 11px);
    font-variant-numeric: tabular-nums;
}

body.dark-mode .proposal-vote-progress-bar {
    background: var(--slate-600);
}

/* Deadline area (used in proposal meta-right) */
.proposal-deadline-area {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
    white-space: nowrap;
}

.proposal-deadline-area > i {
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-400);
}

.proposal-deadline-label {
    font-weight: 500;
    color: var(--slate-500);
}

.proposal-deadline-value {
    font-weight: 600;
    color: var(--slate-700);
}

/* Urgency colors on deadline area. high uses red-500 for the surrounding
   text and red-600 (--rc-status-busy) for the strong value, deliberately
   one ramp step apart for emphasis. */
.proposal-deadline-area.urgency-high {
    color: #ef4444;
}

.proposal-deadline-area.urgency-high > i,
.proposal-deadline-area.urgency-high .proposal-deadline-label {
    color: #ef4444;
}

.proposal-deadline-area.urgency-high .proposal-deadline-value {
    color: var(--rc-status-busy);
    font-weight: 700;
}

.proposal-deadline-area.urgency-medium {
    color: var(--rc-status-tentative);
}

.proposal-deadline-area.urgency-medium > i,
.proposal-deadline-area.urgency-medium .proposal-deadline-label {
    /* Darker amber for legibility — see urgency-tomorrow comment. */
    color: #d97706;
}

.proposal-deadline-area.urgency-medium .proposal-deadline-value {
    color: #b45309;
    font-weight: 700;
}

/* Dark mode deadline area */
body.dark-mode .proposal-deadline-area {
    color: var(--slate-400);
}

body.dark-mode .proposal-deadline-area > i {
    color: var(--slate-500);
}

body.dark-mode .proposal-deadline-label {
    color: var(--slate-400);
}

body.dark-mode .proposal-deadline-value {
    color: var(--slate-200);
}

body.dark-mode .proposal-deadline-area.urgency-high,
body.dark-mode .proposal-deadline-area.urgency-high > i,
body.dark-mode .proposal-deadline-area.urgency-high .proposal-deadline-label {
    color: #f87171;
}

body.dark-mode .proposal-deadline-area.urgency-high .proposal-deadline-value {
    color: #fca5a5;
}

/* Location line */
.proposal-location-line {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
    padding: 0;
}

.proposal-location-line i {
    font-size: 10px;
    color: var(--slate-400);
}

body.dark-mode .proposal-location-line {
    color: var(--slate-400);
}

body.dark-mode .proposal-location-line i {
    color: var(--slate-500);
}

/* Status line: voting status + you voted indicator */
.proposal-status-line {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-600);
    padding: 2px 0;
}

/* A5 — team golden-window banner. A calm, full-width context strip that
   frames the proposal's options against the team's best window. Tinted by
   window quality but deliberately low-key (it's context, not an action). */
.rc-golden-window {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 8px;
    margin: 4px 0 2px;
    padding: 5px 10px;
    border-radius: var(--rc-radius-btn, 8px);
    font-size: var(--rc-font-secondary, 12px);
    background: color-mix(in srgb, var(--rc-gw-tone, #14b8a6) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--rc-gw-tone, #14b8a6) 28%, transparent);
    color: var(--slate-700);
}
.rc-golden-window > i { color: var(--rc-gw-tone, #14b8a6); }
.rc-gw-label { color: var(--slate-500); }
.rc-gw-time { font-weight: 700; color: var(--slate-800); }
.rc-gw-reach { margin-left: auto; color: var(--slate-500); font-weight: 600; }
/* Muted "flexible: 8am-8pm" suffix — the wider workable span as quiet context
   on the SAME line as the best-fit window, never a second coloured strip. It
   sits to the right of reach; on a narrow card it wraps under, still grey. */
.rc-gw-flex {
    color: var(--slate-400);
    font-weight: 500;
    font-size: 11px;
}
.rc-gw-excellent { --rc-gw-tone: #16a34a; }
.rc-gw-good      { --rc-gw-tone: #22c55e; }
.rc-gw-fair      { --rc-gw-tone: #f59e0b; }
.rc-gw-limited   { --rc-gw-tone: #f97316; }

/* No-fit fallback: shown when no window the full length of the meeting clears
   the quality bar. It is the widest workable SPAN, not a fitting slot, so it
   reads calm and non-committal — a flat wash and no star, the icon already
   signals "range" rather than "the answer". */
.rc-golden-window--span {
  background: color-mix(in srgb, var(--rc-gw-tone, #14b8a6) 8%, transparent);
}
.rc-golden-window--span .rc-gw-label { font-weight: 600; }

body.dark-mode .rc-golden-window { color: var(--slate-200); }
body.dark-mode .rc-gw-time { color: var(--slate-100); }
body.dark-mode .rc-gw-label,
body.dark-mode .rc-gw-reach { color: var(--slate-400); }

/* ── "Why these times" disclosure (hierarchy pass) ───────────────────────────
   The golden-window banner, the fairness note, and the per-slot impact /
   who's-free chips are CONTEXT, not the decision. They collapse behind one
   quiet toggle so the card face leads with the rankable slots. */
.proposal-why-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 4px 0 2px;
    padding: 4px 10px;
    background: var(--slate-50, #f8fafc);
    border: 1px solid var(--slate-200, #e2e8f0);
    border-radius: var(--radius-full, 9999px);
    color: var(--slate-500, #64748b);
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.proposal-why-toggle > i:first-child { font-size: 11px; color: var(--slate-400, #94a3b8); }
.proposal-why-toggle:hover {
    background: var(--slate-100, #f1f5f9);
    border-color: var(--slate-300, #cbd5e1);
    color: var(--slate-700, #334155);
}
.proposal-why-toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--review-focus-ring, rgba(20, 184, 166, 0.4));
}
.proposal-why-chev { font-size: 10px; transition: transform 0.18s ease; }
.proposal-why-toggle[aria-expanded="true"] .proposal-why-chev { transform: rotate(180deg); }
.proposal-why-detail {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
body.dark-mode .proposal-why-toggle {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
    color: var(--slate-400, #94a3b8);
}
body.dark-mode .proposal-why-toggle:hover { background: var(--slate-700, #334155); color: var(--slate-200, #e2e8f0); }

/* Per-slot impact + who's-free (and their column headers) are detail: hidden
   on the card face, revealed in step with the "Why these times" toggle. The
   rank circle, date, time, and the live vote bar stay on the face. */
.proposal-detail-collapsed .option-info-detail { display: none; }

/* A6 — fairness-impact note: a gentle heads-up that someone's been
   carrying off-hours load. Amber, low-key, info-not-alarm. */
.rc-fairness-note {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 2px 0;
    padding: 4px 10px;
    border-radius: var(--rc-radius-btn, 8px);
    font-size: var(--rc-font-secondary, 12px);
    color: #92400e;
    background: color-mix(in srgb, var(--rc-status-tentative, #f59e0b) 12%, transparent);
}
.rc-fairness-note > i { color: var(--rc-status-tentative, #f59e0b); }
body.dark-mode .rc-fairness-note { color: #fbbf24; background: rgba(245, 158, 11, 0.12); }

.status-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
}

.status-dot.status-open {
    background: var(--rc-status-available);
    box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.2);
}

.status-dot.status-closed {
    background: var(--slate-400);
}

.status-dot.status-pending {
    background: var(--rc-status-tentative);
    box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.2);
}

.status-dot.status-expired {
    background: var(--rc-status-busy);
    box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2);
}

.status-sep {
    color: var(--slate-300);
    margin: 0 2px;
}

.status-you-voted {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--rc-status-available);
    font-weight: 500;
}

.status-you-voted.unavailable {
    color: var(--rc-status-busy);
}

.status-you-voted i {
    font-size: 10px;
}

body.dark-mode .proposal-status-line {
    color: var(--slate-400);
}

body.dark-mode .status-dot.status-open {
    box-shadow: 0 0 0 2px rgba(34, 197, 94, 0.3);
}

body.dark-mode .status-dot.status-closed {
    background: var(--slate-500);
}

body.dark-mode .status-dot.status-pending {
    box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.3);
}

body.dark-mode .status-dot.status-expired {
    box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.3);
}

body.dark-mode .status-sep {
    color: var(--slate-600);
}

body.dark-mode .status-you-voted {
    color: #34d399;
}

body.dark-mode .status-you-voted.unavailable {
    color: #f87171;
}

/* Description line — truncated, expandable */
.proposal-description-line {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
    line-height: 1.3;
    cursor: pointer;
    padding: 2px 0;
}

.proposal-description-line i {
    font-size: 10px;
    color: var(--slate-400);
    flex-shrink: 0;
}

.desc-expand-hint {
    font-size: var(--rc-font-tiny, 10px);
    color: var(--slate-400);
    font-style: italic;
    margin-left: 4px;
    flex-shrink: 0;
}

.proposal-description-line:hover {
    color: var(--slate-700);
}

.proposal-description-line:hover .desc-expand-hint {
    color: var(--primary-500);
}

body.dark-mode .proposal-description-line {
    color: var(--slate-400);
}

body.dark-mode .proposal-description-line:hover {
    color: var(--slate-300);
}

body.dark-mode .desc-expand-hint {
    color: var(--slate-500);
}

/* Slots never arrived (2026-08-06). Replaces the ballot chrome on a proposal
   whose times failed to sync, so the card stops asking the user to rank times
   it never showed. Amber, not red: nothing is broken for the user to fix, the
   data just has not landed yet. */
.proposal-slots-missing {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: var(--rc-spacing-section, 10px);
    padding: 12px;
    border: 1px solid color-mix(in srgb, var(--status-tentative, #f59e0b) 40%, transparent);
    border-radius: 8px;
    background: color-mix(in srgb, var(--status-tentative, #f59e0b) 8%, transparent);
}
.proposal-slots-missing > i {
    color: var(--status-tentative, #f59e0b);
    flex-shrink: 0;
}
.proposal-slots-missing-copy {
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    min-width: 0;
}
.proposal-slots-missing-copy > strong {
    font-size: var(--rc-font-body, 13px);
    line-height: 1.35;
}
.proposal-slots-missing-copy > span {
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-600);
    line-height: 1.35;
}
.proposal-slots-refresh {
    flex-shrink: 0;
    white-space: nowrap;
}
body.dark-mode .proposal-slots-missing-copy > span { color: var(--slate-400); }
@media (max-width: 520px) {
    /* The button drops below the copy rather than squeezing it to a few
       characters on a phone, where this card is most likely to be seen. */
    .proposal-slots-missing { flex-wrap: wrap; }
    .proposal-slots-refresh { width: 100%; justify-content: center; }
}

/* Options section — contains header, options, tip */
.proposal-options-section {
    border-top: 1px solid var(--slate-200);
    padding-top: var(--rc-spacing-section, 10px);
}

body.dark-mode .proposal-options-section {
    border-top-color: var(--slate-600);
}

/* Column headers above option rows */
.proposal-options-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 12px 6px 12px;
    /* wrap so .options-header-hint can take a full line of its own below the
       label + column headers rather than squeezing them (2026-08-06) */
    flex-wrap: wrap;
}

.options-header-label {
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
    font-weight: 500;
}

/* One-line legend teaching the rank circle's cycle (2026-08-06). Takes a full
   line of its own beneath the label so it never competes with the column
   headers for the same row, and reads as guidance (lighter, smaller) rather
   than as another control. */
.options-header-hint {
    flex-basis: 100%;
    order: 3;
    font-size: var(--rc-font-tertiary, 11px);
    color: var(--slate-400);
    line-height: 1.35;
    margin-top: 2px;
}

body.dark-mode .options-header-hint {
    color: var(--slate-500);
}

.options-header-columns {
    display: flex;
    align-items: center;
    gap: 16px;
}

.col-header {
    font-size: var(--rc-font-tiny, 10px);
    color: var(--slate-400);
    font-weight: 500;
    text-transform: lowercase;
    letter-spacing: 0.3px;
}

.col-header.col-fairness {
    min-width: 50px;
    text-align: center;
}

.col-header.col-reachable {
    min-width: 56px;
    text-align: center;
}

.col-header.col-votes {
    min-width: 70px;
    text-align: center;
}

body.dark-mode .options-header-label {
    color: var(--slate-400);
}

body.dark-mode .col-header {
    color: var(--slate-500);
}

/* Tip text below options */
.proposal-tip-text {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px 0;
    font-size: var(--rc-font-tiny, 10px);
    color: var(--slate-400);
    font-style: italic;
}

.proposal-tip-text i {
    font-size: 10px;
    color: #f59e0b;
}

body.dark-mode .proposal-tip-text {
    color: var(--slate-500);
}

body.dark-mode .proposal-meta-line {
    color: var(--slate-400);
}

body.dark-mode .proposal-meta-line > span:not(:last-child):not(.proposal-meta-right)::after {
    color: var(--slate-600);
}

/* Voted badge in header */
.proposal-voted-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 8px;
    font-size: var(--rc-font-tiny);
    font-weight: 600;
    /* ONE green per pill (2026-08-29). The fill and border are emerald
       #10b981 (= `--success`, the hue this sheet's whole "emerald" tab family
       already uses for a done/succeeded signal), but the glyph was
       `--rc-status-available` #22c55e — a different green — so an 8px pill
       carried two of them. "You voted" is a SUCCESS state, not an availability
       reading, so the emerald is the correct channel here and the text was the
       outlier. Matched to --success rather than repainting the fill. */
    color: var(--success, #10b981);
    background: rgba(16, 185, 129, 0.12);
    border: 1px solid rgba(16, 185, 129, 0.25);
    border-radius: var(--rc-radius-pill);
    white-space: nowrap;
}

.proposal-voted-badge i {
    font-size: 10px;
}

.proposal-voted-badge.unavailable {
    color: var(--slate-500);
    background: rgba(100, 116, 139, 0.12);
    border-color: rgba(100, 116, 139, 0.25);
}

body.dark-mode .proposal-voted-badge {
    color: #34d399;
    background: rgba(16, 185, 129, 0.2);
    border-color: rgba(16, 185, 129, 0.35);
}

body.dark-mode .proposal-voted-badge.unavailable {
    color: var(--slate-400);
    background: rgba(148, 163, 184, 0.15);
    border-color: rgba(148, 163, 184, 0.3);
}

/* Voted proposal styling */
.proposal-item.proposal-voted {
    opacity: 0.85;
    border-color: rgba(16, 185, 129, 0.3);
}

.proposal-item.proposal-voted:hover {
    opacity: 1;
}

/* Priority/Urgency visual differentiation for proposals */
/* High urgency (deadline within 24h) - Red indicator */
/* Urgency is carried by the border-left alone — the coloured glow ring that
   used to layer on top was a second accent competing for the same signal, so
   the card kept the plain shadow and reads with one clear urgency cue. */
.proposal-item.urgency-high {
    border-left: 4px solid var(--rc-status-busy);
}


/* Medium urgency (deadline 1-3 days) - Amber indicator */
.proposal-item.urgency-medium {
    border-left: 4px solid var(--rc-status-tentative);
}


/* Low urgency (deadline > 3 days) - Default/subtle indicator */
.proposal-item.urgency-low {
    border-left: 4px solid var(--accent, #14b8a6);
}

/* Priority number badge for ranked items. The NUMERAL conveys rank, so a
   single calm slate badge does the job — the previous three per-rank gradient
   hues (orange/teal/purple) were three more competing accents fighting the
   urgency border and fairness chip for the eye. One quiet token, every rank. */
.proposal-priority-badge {
    position: absolute;
    top: -6px;
    left: -6px;
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--slate-600, #475569);
    color: white;
    font-size: 11px;
    font-weight: 700;
    border-radius: 50%;
    box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.15));
    z-index: 2;
}

body.dark-mode .proposal-priority-badge {
    background: var(--slate-500, #64748b);
}

/* Dark mode proposal cards */
body.dark-mode .proposal-item {
    background: var(--slate-800);
    border-color: var(--slate-700);
}

body.dark-mode .proposal-item:hover {
    border-color: var(--primary-600);
}

/* Dark mode urgency */
body.dark-mode .proposal-item.urgency-high {
    border-left-color: #f87171;
}


body.dark-mode .proposal-item.urgency-medium {
    border-left-color: #fbbf24;
}


body.dark-mode .proposal-item.urgency-low {
    border-left-color: var(--accent, #2dd4bf);
}

/* Voted confirmation in actions */
.voted-confirmation {
    display: flex;
    align-items: center;
    gap: 5px;
    margin-right: auto;
    font-size: var(--rc-font-secondary);
    font-weight: 500;
    color: var(--rc-status-available);
}

.voted-confirmation i {
    font-size: 14px;
}

body.dark-mode .voted-confirmation {
    color: #34d399;
}

/* Your Rankings Section (Already Voted) */
.proposal-your-votes {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 10px 12px;
    background: var(--slate-50);
    border-radius: var(--rc-radius-btn);
    margin-bottom: var(--rc-spacing-section);
    border: 1px solid var(--slate-200);
}

.your-votes-label {
    font-size: var(--rc-font-caption);
    font-weight: 600;
    color: var(--slate-600);
    text-transform: uppercase;
    letter-spacing: 0.03em;
    display: flex;
    align-items: center;
    gap: 6px;
}

.your-votes-label i {
    color: var(--amber-500);
}

.your-votes-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.vote-rank {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    font-size: 0.875rem;
    font-weight: 500;
    background: white;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius-md);
    color: var(--slate-700);
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.04);
}

.vote-rank-disc {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--slate-500);
    background: var(--slate-100);
    border: 2px solid var(--slate-300);
}

.vote-rank-ordinal {
    font-weight: 700;
    font-size: 0.75rem;
    color: var(--slate-500);
    min-width: 28px;
}

.vote-rank-time {
    flex: 1;
    font-weight: 500;
}

/* Vote-rank medal palette (gold/silver/bronze). Intrinsic medal colors,
   not status — kept hardcoded so the status palette can change without
   recoloring podium positions. */
.vote-rank.rank-gold {
    background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
    border-color: #f59e0b;
    color: #78350f;
}
.vote-rank.rank-gold .vote-rank-disc {
    background: linear-gradient(135deg, #fbbf24, #f59e0b);
    border-color: #d97706;
    color: #78350f;
}
.vote-rank.rank-gold .vote-rank-ordinal { color: #b45309; }

.vote-rank.rank-silver {
    background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
    border-color: #94a3b8;
    color: #334155;
}
.vote-rank.rank-silver .vote-rank-disc {
    background: linear-gradient(135deg, #cbd5e1, #94a3b8);
    border-color: #64748b;
    color: #334155;
}
.vote-rank.rank-silver .vote-rank-ordinal { color: #475569; }

.vote-rank.rank-bronze {
    background: linear-gradient(135deg, #fef4e8 0%, #fed7aa 100%);
    border-color: #b45309;
    color: #9a3412;
}
.vote-rank.rank-bronze .vote-rank-disc {
    background: linear-gradient(135deg, #d97706, #b45309);
    border-color: #92400e;
    color: white;
}
.vote-rank.rank-bronze .vote-rank-ordinal { color: #c2410c; }

.vote-rank.rank-other .vote-rank-disc {
    background: var(--slate-100);
    border-color: var(--slate-300);
    color: var(--slate-500);
}

body.dark-mode .proposal-your-votes {
    background: var(--slate-800);
    border-color: var(--slate-700);
}

body.dark-mode .your-votes-label {
    color: var(--slate-400);
}

body.dark-mode .vote-rank {
    background: var(--slate-700);
    border-color: var(--slate-600);
    color: var(--slate-200);
}

body.dark-mode .vote-rank-disc {
    background: var(--slate-800);
    border-color: var(--slate-500);
    color: var(--slate-300);
}

body.dark-mode .vote-rank-ordinal {
    color: var(--slate-400);
}

body.dark-mode .vote-rank.rank-gold {
    background: linear-gradient(135deg, rgba(251, 191, 36, 0.18) 0%, rgba(251, 191, 36, 0.28) 100%);
    border-color: #fbbf24;
    color: #fcd34d;
}
body.dark-mode .vote-rank.rank-gold .vote-rank-ordinal { color: #fbbf24; }

body.dark-mode .vote-rank.rank-silver {
    background: linear-gradient(135deg, rgba(148, 163, 184, 0.18) 0%, rgba(148, 163, 184, 0.28) 100%);
    border-color: #94a3b8;
    color: #cbd5e1;
}
body.dark-mode .vote-rank.rank-silver .vote-rank-ordinal { color: #cbd5e1; }

body.dark-mode .vote-rank.rank-bronze {
    background: linear-gradient(135deg, rgba(251, 146, 60, 0.18) 0%, rgba(251, 146, 60, 0.28) 100%);
    border-color: #fb923c;
    color: #fed7aa;
}
body.dark-mode .vote-rank.rank-bronze .vote-rank-ordinal { color: #fdba74; }

/* Closed proposal summary (shown when voting is closed — replaces the
   voting surface with a winning-slot recap or a "no votes" note) */
.proposal-closed-summary {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 12px;
    margin: 8px 0 12px 0;
    background: var(--slate-50, #f8fafc);
    border: 1px solid var(--slate-200);
    border-radius: var(--rc-radius-btn);
}
.proposal-closed-winner {
    background: rgba(34, 197, 94, 0.06);
    border-color: rgba(34, 197, 94, 0.35);
}
.closed-summary-icon {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--slate-200);
    color: var(--slate-600);
    font-size: 13px;
}
.closed-summary-winner-icon {
    background: linear-gradient(135deg, #fbbf24, #f59e0b);
    color: #78350f;
}
.closed-summary-body {
    flex: 1;
    min-width: 0;
}
.closed-summary-headline {
    font-size: 13px;
    font-weight: 600;
    color: var(--slate-700);
    letter-spacing: 0.01em;
}
.closed-summary-sub {
    font-size: 12px;
    color: var(--slate-500);
    margin-top: 2px;
}
.closed-summary-winner-line {
    margin-top: 4px;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    font-size: 13px;
    color: var(--slate-800);
}
.closed-winner-date { font-weight: 600; }
.closed-winner-sep { color: var(--slate-400); }
.closed-winner-time { font-weight: 500; }
.closed-winner-votes {
    margin-left: auto;
    font-size: 11px;
    font-weight: 600;
    color: #15803d;
    padding: 2px 8px;
    background: rgba(34, 197, 94, 0.12);
    border-radius: 999px;
}
body.dark-mode .proposal-closed-summary {
    background: var(--slate-800);
    border-color: var(--slate-700);
}
body.dark-mode .proposal-closed-winner {
    background: rgba(34, 197, 94, 0.1);
    border-color: rgba(34, 197, 94, 0.4);
}
body.dark-mode .closed-summary-icon {
    background: var(--slate-700);
    color: var(--slate-300);
}
body.dark-mode .closed-summary-headline { color: var(--slate-200); }
body.dark-mode .closed-summary-sub { color: var(--slate-400); }
body.dark-mode .closed-summary-winner-line { color: var(--slate-100); }
body.dark-mode .closed-winner-votes {
    color: #4ade80;
    background: rgba(34, 197, 94, 0.15);
}

/* Change vote button */
.change-vote-btn {
    padding: 6px 14px;
    font-size: 12px;
    font-weight: 500;
    color: var(--slate-600);
    background: white;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: all var(--transition-fast);
}

.change-vote-btn:hover {
    color: var(--primary-700);
    background: var(--primary-50);
    border-color: var(--primary-300);
}

.change-vote-btn i {
    margin-right: 5px;
}

body.dark-mode .change-vote-btn {
    color: var(--slate-300);
    background: var(--slate-700);
    border-color: var(--slate-600);
}

body.dark-mode .change-vote-btn:hover {
    color: var(--primary-300);
    background: rgba(20, 184, 166, 0.1);
    border-color: var(--primary-500);
}

.proposal-title {
    font-size: var(--rc-font-heading);
    font-weight: 600;
    color: var(--slate-800);
}


body.dark-mode .proposal-title {
    color: var(--slate-100);
}

.sync-badge {
    display: inline-flex;
    align-items: center;
    margin-left: 6px;
    font-size: 12px;
    vertical-align: middle;
}
.sync-badge.sync-offline {
    color: var(--amber-500, #f59e0b);
}
.sync-badge.sync-error {
    color: var(--red-500, #ef4444);
}
body.dark-mode .sync-badge.sync-offline {
    color: var(--amber-400, #fbbf24);
}
body.dark-mode .sync-badge.sync-error {
    color: var(--red-400, #f87171);
}

.proposal-proposer {
    font-size: 12px;
    color: var(--slate-400);
}


body.dark-mode .proposal-proposer {
    color: var(--slate-500);
}

/* Polling Mode Badges */
.mode-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 7px;
    font-size: var(--rc-font-tiny);
    font-weight: 500;
    border-radius: var(--rc-radius-pill);
    margin-left: 4px;
}

.mode-badge i {
    font-size: 9px;
}

/* "Which group is this?" badge (2026-07-06). A quiet neutral pill shown on
   proposal + privacy items ONLY in the aggregate Home view, so a multi-group
   user can tell which board an item belongs to when several boards' items mix
   in one list. Deliberately understated (slate, not a brand colour) — it's
   context, not an action. */
.rc-group-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    font-size: var(--rc-font-tiny);
    font-weight: 500;
    border-radius: var(--rc-radius-pill);
    margin-left: 4px;
    color: var(--slate-600, #475569);
    background: var(--slate-100, #f1f5f9);
    border: 1px solid var(--slate-200, #e2e8f0);
    max-width: 12rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.rc-group-badge i {
    font-size: 9px;
    flex-shrink: 0;
    opacity: 0.75;
}
/* On the privacy rows the badge sits under the meta line rather than inline. */
.synced-row-info .rc-group-badge {
    margin-left: 0;
    margin-top: 4px;
}
body.dark-mode .rc-group-badge {
    color: var(--slate-300, #cbd5e1);
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
}

.mode-manager {
    color: #6366f1;
    background: rgba(99, 102, 241, 0.1);
    border: 1px solid rgba(99, 102, 241, 0.2);
}

.mode-collaborative {
    color: #0891b2;
    background: rgba(8, 145, 178, 0.1);
    border: 1px solid rgba(8, 145, 178, 0.2);
}

body.dark-mode .mode-manager {
    color: #a5b4fc;
    background: rgba(99, 102, 241, 0.15);
    border-color: rgba(99, 102, 241, 0.3);
}

body.dark-mode .mode-collaborative {
    color: #67e8f9;
    background: rgba(8, 145, 178, 0.15);
    border-color: rgba(8, 145, 178, 0.3);
}

/* Proposal Description */
.proposal-description {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    font-size: 12px;
    color: var(--slate-500);
    padding: 6px 10px;
    background: var(--slate-50);
    border-radius: 6px;
    border-left: 2px solid var(--slate-200);
    line-height: 1.4;
}

.proposal-description i {
    color: var(--slate-400);
    font-size: 11px;
    margin-top: 2px;
}

body.dark-mode .proposal-description {
    color: var(--slate-400);
    background: var(--slate-800);
    border-color: var(--slate-600);
}


/* Proposal Type Badges */
.proposal-type-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 7px;
    border-radius: var(--rc-radius-pill);
    font-size: var(--rc-font-tiny);
    font-weight: 600;
    text-transform: capitalize;
    flex-shrink: 0;
}

.proposal-type-badge i {
    font-size: 9px;
}

/* Work badge - Blue (canonical) */
.proposal-type-work {
    background: rgba(59, 130, 246, 0.1);
    color: #2563eb;
    border: 1px solid rgba(59, 130, 246, 0.3);
}

/* Personal badge - Pink (canonical) */
.proposal-type-personal {
    background: rgba(244, 114, 182, 0.1);
    color: #db2777;
    border: 1px solid rgba(244, 114, 182, 0.3);
}

body.dark-mode .proposal-type-work {
    background: rgba(59, 130, 246, 0.2);
    color: #60a5fa;
    border-color: rgba(59, 130, 246, 0.4);
}

body.dark-mode .proposal-type-personal {
    background: rgba(244, 114, 182, 0.2);
    color: #f9a8d4;
    border-color: rgba(244, 114, 182, 0.4);
}

/* Proposal Duration & Participants */
.proposal-duration,
.proposal-participants {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: var(--rc-font-secondary);
    color: var(--slate-500);
}

.proposal-duration i,
.proposal-participants i {
    font-size: var(--rc-font-tiny);
    color: var(--slate-400);
}

body.dark-mode .proposal-duration,
body.dark-mode .proposal-participants {
    color: var(--slate-400);
}

body.dark-mode .proposal-duration i,
body.dark-mode .proposal-participants i {
    color: var(--slate-500);
}

/* Slot Fairness Badges - Numeric score */
.slot-fairness {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 7px;
    border-radius: var(--rc-radius-pill);
    font-size: var(--rc-font-tiny, 10px);
    font-weight: 600;
    white-space: nowrap;
    border: 1px solid transparent;
    transition: all 0.15s ease;
    min-width: 40px;
    justify-content: center;
}

.slot-fairness i {
    font-size: 8px;
}

/* Slot fairness ramp — derived from traffic-light palette so fairness
   reads the same as every other status surface. Differentiation comes
   from lightness, not hue-shift.
   Text colors (#15803d, #b45309, #c2410c, #b91c1c) are darker variants
   for legibility on the soft tinted backgrounds; they do not match the
   --rc-status-* tokens 1:1 and stay hardcoded until the canonical palette
   grows -strong variants. */
/* Canonical 5-band tints — derived from --fv-l2/l3/l5/l7/l8.
   Slot keys (excellent/good/fair/challenging/difficult) preserved for
   backward CSS compatibility; the 5 canonical bands map onto them in order:
       excellent  ← excellent  (--fv-l2 deep green)
       good       ← steady     (--fv-l3 canonical green)
       fair       ← mixed      (--fv-l5 canonical amber)
       challenging ← stretched (--fv-l7 light red)
       difficult  ← overloaded (--fv-l8 canonical busy red)
   No lime, no orange — pure traffic-light vocabulary. */
.slot-fairness-excellent {
    background: rgba(21, 128, 61, 0.14);
    color: #15803d;
    border-color: rgba(21, 128, 61, 0.35);
}
.slot-fairness-good {
    background: rgba(22, 163, 74, 0.14);
    color: #15803d;
    border-color: rgba(22, 163, 74, 0.35);
}
.slot-fairness-fair {
    background: rgba(251, 191, 36, 0.16);
    color: #b45309;
    border-color: rgba(251, 191, 36, 0.4);
}
.slot-fairness-challenging {
    background: rgba(239, 68, 68, 0.14);
    color: #b91c1c;
    border-color: rgba(239, 68, 68, 0.35);
}
.slot-fairness-difficult {
    background: rgba(220, 38, 38, 0.14);
    color: #b91c1c;
    border-color: rgba(220, 38, 38, 0.4);
}
/* Unscored slot: clearly NOT a rating on the impact scale. Neutral slate with
   a dashed border so it reads as "no data yet", not as a good-or-bad verdict. */
.slot-fairness-unknown {
    background: rgba(148, 163, 184, 0.12);
    color: var(--slate-500, #64748b);
    border: 1px dashed rgba(148, 163, 184, 0.5);
    font-style: italic;
}
body.dark-mode .slot-fairness-unknown {
    background: rgba(148, 163, 184, 0.16);
    color: var(--slate-400, #94a3b8);
    border-color: rgba(148, 163, 184, 0.45);
}

body.dark-mode .slot-fairness-excellent {
    background: rgba(21, 128, 61, 0.22);
    color: #4ade80;
    border-color: rgba(34, 197, 94, 0.5);
}
body.dark-mode .slot-fairness-good {
    background: rgba(22, 163, 74, 0.2);
    color: #86efac;
    border-color: rgba(22, 163, 74, 0.45);
}
body.dark-mode .slot-fairness-fair {
    background: rgba(251, 191, 36, 0.2);
    color: #fbbf24;
    border-color: rgba(251, 191, 36, 0.45);
}
body.dark-mode .slot-fairness-challenging {
    background: rgba(239, 68, 68, 0.22);
    color: #fca5a5;
    border-color: rgba(239, 68, 68, 0.5);
}
body.dark-mode .slot-fairness-difficult {
    background: rgba(220, 38, 38, 0.22);
    color: #f87171;
    border-color: rgba(220, 38, 38, 0.5);
}

/* Proposal Options — Compact Single-Row Layout */
.proposal-options {
    display: flex;
    flex-direction: column;
    gap: var(--rc-spacing-inline);
    margin-bottom: var(--rc-spacing-card);
}

.proposal-option {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px 10px;
    padding: 8px 12px;
    background: white;
    border: 1px solid var(--slate-200);
    border-radius: var(--rc-radius-btn);
    transition: background-color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
    cursor: pointer;
    font-size: var(--rc-font-body);
}

/* A3 — reachable-count chip beside the slot fairness badge */
.slot-reachable {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 600;
    white-space: nowrap;
}
.slot-reachable-all  { color: var(--rc-status-available, #22c55e); }
.slot-reachable-some { color: var(--rc-status-tentative, #f59e0b); }
.slot-reachable-none { color: var(--rc-status-busy, #dc2626); }
.slot-reachable i { font-size: 10px; opacity: 0.85; }

/* Inline unit word ("votes" / "free") appended on header-less surfaces
   (My-Proposals) so two adjacent X/Y chips self-distinguish without hover.
   Muted + smaller so the number stays the dominant glyph; inherits the
   chip's colour so the reachable tone still reads. */
.slot-chip-unit {
    margin-left: 3px;
    font-size: var(--rc-font-tiny, 10px);
    font-weight: 500;
    opacity: 0.65;
    text-transform: lowercase;
}

/* A2 — worst-hour participant peek: a full-width second line under the
   slot's main row (flex-wrap makes flex-basis:100% drop to its own line). */
.slot-participant-peek {
    flex-basis: 100%;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px 8px;
    margin-top: 2px;
    padding-left: 2px;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
}
.slot-participant-peek > i { font-size: 10px; opacity: 0.7; }

/* Phase 4 — the "who's affected" peeks are collapsed by default so the option
   rows read as a clean comparison; the per-proposal toggle reveals them. */
.proposal-options.peek-collapsed .slot-participant-peek { display: none; }
.proposal-peek-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 2px 0 0;
    padding: 3px 8px;
    background: none;
    border: none;
    cursor: pointer;
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 600;
    color: var(--slate-500);
    border-radius: var(--radius-md, 6px);
}
.proposal-peek-toggle:hover { color: var(--slate-700); background: rgba(148, 163, 184, 0.12); }
.proposal-peek-toggle i { font-size: 11px; }
body.dark-mode .proposal-peek-toggle { color: var(--slate-400); }
body.dark-mode .proposal-peek-toggle:hover { color: var(--slate-200); }
.slot-peek-person {
    display: inline-flex;
    align-items: baseline;
    gap: 3px;
    white-space: nowrap;
}
.slot-peek-time { color: var(--slate-400); font-variant-numeric: tabular-nums; }
.slot-peek-hard .slot-peek-time,
.slot-peek-hard { color: var(--rc-status-busy, #dc2626); font-weight: 600; }
.slot-peek-more { color: var(--slate-400); }

/* "Already accommodating" running count — amber (accommodation hue), distinct
   from the busy-red hard-hour marker. Heavy = this person is a top contributor
   right now, so the running cost reads stronger. */
.slot-peek-load {
    display: inline-flex;
    align-items: center;
    margin-left: 4px;
    padding: 0 6px;
    border-radius: var(--radius-full, 9999px);
    font-size: 11px;
    font-weight: 600;
    color: #b45309;
    background: color-mix(in srgb, var(--rc-status-tentative, #f59e0b) 14%, transparent);
}
.slot-peek-load-heavy {
    color: #92400e;
    background: color-mix(in srgb, var(--rc-status-tentative, #f59e0b) 24%, transparent);
}

body.dark-mode .slot-participant-peek { color: var(--slate-400); }
body.dark-mode .slot-peek-time { color: var(--slate-500); }
body.dark-mode .slot-peek-hard,
body.dark-mode .slot-peek-hard .slot-peek-time { color: #f87171; }
body.dark-mode .slot-peek-load { color: #fbbf24; background: rgba(245, 158, 11, 0.18); }
body.dark-mode .slot-peek-load-heavy { color: #fcd34d; background: rgba(245, 158, 11, 0.28); }

.proposal-option:hover {
    background: var(--slate-50);
    border-color: var(--slate-300);
}

body.dark-mode .proposal-option {
    background: var(--slate-700);
    border-color: var(--slate-600);
}

body.dark-mode .proposal-option:hover {
    background: var(--slate-600);
}

/* ── Temp-group poll cards (2026-08-23) ─────────────────────────────
   Host-side resolution of a "Guests vote on times" poll, rendered in the
   Proposals tab. Inherits .proposal-item / .proposal-option; these rules
   only add what a poll needs: the accept button pushed to the row's end,
   a leader highlight, and the Poll badge tone (teal — distinct from the
   blue work / pink personal event-type badges). */
.rc-poll-option {
    cursor: default; /* the ACTION is the button, the row itself is inert */
}

.rc-poll-option .rc-poll-accept {
    margin-left: auto;
    flex-shrink: 0;
    padding: 5px 12px;
    font-size: var(--rc-font-secondary, 12px);
}

/* Leader = the option most guests can make. One calm highlight, not a
   celebration: the host still decides. */
.rc-poll-option.rc-poll-top {
    border-color: var(--primary-400, #38bdf8);
    box-shadow: 0 0 0 1px var(--primary-400, #38bdf8) inset;
}

body.dark-mode .rc-poll-option.rc-poll-top {
    border-color: var(--primary-500, #0ea5e9);
    box-shadow: 0 0 0 1px var(--primary-500, #0ea5e9) inset;
}

.proposal-poll-badge {
    background: rgba(20, 184, 166, 0.1);
    color: #0d9488;
    border: 1px solid rgba(20, 184, 166, 0.3);
}

body.dark-mode .proposal-poll-badge {
    background: rgba(20, 184, 166, 0.16);
    color: #2dd4bf;
    border-color: rgba(45, 212, 191, 0.35);
}

.rc-poll-status {
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
}

body.dark-mode .rc-poll-status {
    color: var(--slate-400);
}

/* Narrow screens: the accept button drops to its own full-width line so the
   date/time and tally keep their room (WCAG 2.5.8: the target grows, never
   shrinks, when space is tight). */
@media (max-width: 480px) {
    .rc-poll-option .rc-poll-accept {
        margin-left: 0;
        flex-basis: 100%;
        justify-content: center;
    }
}

.option-label {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    font-weight: 500;
    color: var(--slate-700);
    cursor: pointer;
}

body.dark-mode .option-label {
    color: var(--slate-200);
}

.option-label input[type="radio"] {
    width: 18px;
    height: 18px;
    accent-color: var(--primary-500);
}

/* Compact Rank Circle */
.rank-circle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    min-width: 26px;
    border-radius: 50%;
    border: 2px dashed var(--slate-300);
    background: var(--slate-50);
    color: var(--slate-400);
    font-size: var(--rc-font-caption);
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s ease;
    padding: 0;
    font-family: inherit;
    flex-shrink: 0;
}

.rank-circle:hover {
    border-color: var(--primary-400);
    background: var(--primary-50);
    color: var(--primary-600);
}

.rank-circle.rank-selected {
    border: 2px solid var(--primary-500);
    background: var(--primary-500);
    color: white;
}

.rank-circle.rank-unavailable {
    border: 2px solid rgba(239, 68, 68, 0.4);
    background: rgba(239, 68, 68, 0.1);
    color: var(--rc-status-busy);
}

.rank-circle .rank-number {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    font-size: var(--rc-font-secondary);
    font-weight: 700;
    color: inherit;
    background: none;
    border-radius: 0;
}

/* The compact "mark unavailable" ✕ button was REMOVED 2026-08-06. Each slot
   carried two controls that both expressed availability - this ✕ and the rank
   circle - and the circle already rendered a ✕ of its own for the unavailable
   state, so the same glyph appeared twice per row, once as a readout and once
   as an action. The circle now cycles through unavailable instead.

   Worth recording why this button was also a liability on its own terms: it sat
   at `opacity: 0` until the row was hovered, so on desktop a core voting action
   was invisible at rest, and the @media (hover: none) fallback that fixed it on
   phones meant the two platforms showed different controls for the same task. */

/* Rank circles used to fill with gold / silver / bronze gradients for the top
   three choices. On a voting card that read as celebration — three more
   competing accents above the rank number that already conveys order. Hierarchy
   pass: every ranked circle now uses the SAME calm primary fill (inherited from
   .rank-selected above); the NUMBER carries the rank. The #1 row keeps the
   faintest primary wash so the top choice still stands out at a glance.
   (The Find Times results podium keeps its medals — those live on
   .vm-results-rank-badge, a different element, and are intentional there.) */
.rank-circle.rank-gold,
.rank-circle.rank-silver,
.rank-circle.rank-bronze {
    border: 2px solid var(--primary-500);
    background: var(--primary-500);
    color: white;
}

.proposal-option.rank-gold {
    background: color-mix(in srgb, var(--primary-500) 5%, transparent);
    border-color: color-mix(in srgb, var(--primary-500) 28%, transparent);
}

.proposal-option.rank-silver,
.proposal-option.rank-bronze {
    background: transparent;
    border-color: var(--slate-200, #e2e8f0);
}

/* Dark mode rank circle */
body.dark-mode .rank-circle {
    background: var(--slate-700);
    border-color: var(--slate-500);
    color: var(--slate-400);
}

body.dark-mode .rank-circle:hover {
    background: var(--slate-600);
    border-color: var(--primary-400);
    color: var(--slate-200);
}

body.dark-mode .rank-circle.rank-selected {
    background: var(--primary-500);
    border-color: var(--primary-400);
    color: white;
}

body.dark-mode .rank-circle.rank-unavailable {
    background: rgba(239, 68, 68, 0.15);
    border-color: rgba(239, 68, 68, 0.5);
    color: #f87171;
}

/* Dark mode medal circles */
body.dark-mode .rank-circle.rank-gold {
    background: linear-gradient(135deg, #fbbf24, #f59e0b);
    border-color: #fbbf24;
    color: #78350f;
}

body.dark-mode .proposal-option.rank-gold {
    background: rgba(251, 191, 36, 0.1);
    border-color: rgba(251, 191, 36, 0.4);
}

body.dark-mode .rank-circle.rank-silver {
    background: linear-gradient(135deg, #e2e8f0, #cbd5e1);
    border-color: #94a3b8;
    color: #1e293b;
}

body.dark-mode .proposal-option.rank-silver {
    background: rgba(148, 163, 184, 0.08);
    border-color: rgba(148, 163, 184, 0.35);
}

body.dark-mode .rank-circle.rank-bronze {
    background: linear-gradient(135deg, #f59e0b, #d97706);
    border-color: #d97706;
    color: white;
}

body.dark-mode .proposal-option.rank-bronze {
    background: rgba(217, 119, 6, 0.08);
    border-color: rgba(217, 119, 6, 0.35);
}


/* Compact inline option elements */
.option-date {
    font-size: var(--rc-font-secondary);
    color: var(--slate-500);
    white-space: nowrap;
    min-width: 70px;
}

.option-date-sep {
    color: var(--slate-300);
    font-size: var(--rc-font-secondary);
}

.option-time {
    flex: 1;
    font-size: var(--rc-font-body);
    font-weight: 600;
    color: var(--slate-900);
    white-space: nowrap;
    letter-spacing: -0.01em;
}

.option-duration {
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-500);
    white-space: nowrap;
    min-width: 30px;
    text-align: right;
}

/* Compact vote info (inline) — aligns with column headers */
.option-info-compact {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
}

.vote-bar-compact {
    display: inline-block;
    width: 40px;
    height: 5px;
    background: var(--slate-200);
    border-radius: 3px;
    overflow: hidden;
}

.vote-bar-compact .vote-fill {
    display: block;
    height: 100%;
    background: var(--primary-500);
    border-radius: 2px;
    transition: width 0.2s ease;
}

.vote-count-compact {
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 600;
    color: var(--slate-600);
    white-space: nowrap;
}

/* Shared per-slot vote bar wrapper (renderSlotVoteBar) — used by both the
   voting card and the My-Proposals card so the spread reads identically. */
.slot-vote {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

body.dark-mode .option-time {
    color: var(--slate-100);
}

body.dark-mode .option-date-sep {
    color: var(--slate-600);
}

body.dark-mode .option-date {
    color: var(--slate-400);
}

body.dark-mode .option-duration {
    color: var(--slate-500);
}

body.dark-mode .vote-bar-compact {
    background: var(--slate-600);
}

body.dark-mode .vote-count-compact {
    color: var(--slate-400);
}

/* ============================================
   RED DECLINE PANEL - Slide from right
   ============================================ */
.decline-panel-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.3);
    z-index: 200;
    display: flex;
    align-items: stretch;
    justify-content: flex-end;
}

.decline-panel {
    width: 380px;
    max-width: 90%;
    background: white;
    border-left: 4px solid var(--rc-status-busy);
    box-shadow: -8px 0 30px rgba(0, 0, 0, 0.15);
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform 0.25s ease;
}

.decline-panel.open {
    transform: translateX(0);
}

.decline-panel-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    background: linear-gradient(135deg, rgba(239, 68, 68, 0.08) 0%, rgba(220, 38, 38, 0.04) 100%);
    border-bottom: 1px solid rgba(239, 68, 68, 0.15);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--rc-status-busy);
}

.decline-panel-header i {
    font-size: 14px;
}

.decline-panel-close {
    margin-left: auto;
    background: none;
    border: none;
    color: var(--slate-400);
    cursor: pointer;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-full, 9999px);
    transition: all 0.15s ease;
}

.decline-panel-close:hover {
    background: rgba(239, 68, 68, 0.1);
    color: var(--rc-status-busy);
}

.decline-panel-body {
    flex: 1;
    padding: 20px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.decline-event-summary {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 12px;
    background: rgba(239, 68, 68, 0.05);
    border: 1px solid rgba(239, 68, 68, 0.15);
    border-radius: 8px;
}

.decline-event-summary strong {
    font-size: 0.8125rem;
    color: var(--slate-800);
}

.decline-event-time {
    font-size: 13px;
    color: var(--slate-500);
}

.decline-reason-group {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.decline-reason-group label {
    font-size: 13px;
    font-weight: 500;
    color: var(--slate-600);
}

.decline-reason-input {
    padding: 10px 12px;
    border: 1px solid var(--slate-200);
    border-radius: 8px;
    font-size: 13px;
    resize: vertical;
    font-family: inherit;
    transition: border-color 0.15s;
}

.decline-reason-input:focus {
    outline: none;
    border-color: #ef4444;
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
}

.decline-suggest-alt label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--slate-600);
    cursor: pointer;
}

.decline-alt-time-picker {
    display: flex;
    gap: 8px;
    margin-top: 8px;
}

.decline-alt-time-picker input {
    padding: 6px 10px;
    border: 1px solid var(--slate-200);
    border-radius: 6px;
    font-size: 13px;
    font-family: inherit;
}

.decline-panel-actions {
    display: flex;
    gap: 6px;
    padding: 12px 16px;
    border-top: 1px solid rgba(239, 68, 68, 0.15);
    justify-content: flex-end;
}

.decline-panel-cancel-btn {
    background: var(--slate-100);
    color: var(--slate-600);
    border: 1px solid var(--slate-200);
    padding: 6px 14px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s;
}

.decline-panel-cancel-btn:hover {
    background: var(--slate-200);
}

/* This pair (base red-500 → hover red-600) intentionally differs by one
   ramp step. Tokenizing the base would collapse the hover differentiation,
   so both sides stay hardcoded until --rc-status-busy gains a -strong sibling. */
.decline-panel-confirm-btn {
    background: #ef4444;
    color: white;
    border: none;
    padding: 6px 14px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 6px;
    transition: all 0.15s;
}

.decline-panel-confirm-btn:hover {
    background: #dc2626;
}

body.dark-mode .decline-panel {
    background: var(--slate-800);
    border-left-color: #f87171;
}

body.dark-mode .decline-panel-header {
    background: linear-gradient(135deg, rgba(239, 68, 68, 0.15) 0%, rgba(220, 38, 38, 0.08) 100%);
    color: #f87171;
}

body.dark-mode .decline-event-summary {
    background: rgba(239, 68, 68, 0.1);
    border-color: rgba(239, 68, 68, 0.2);
}

body.dark-mode .decline-event-summary strong {
    color: var(--slate-100);
}

body.dark-mode .decline-reason-input {
    background: var(--slate-700);
    border-color: var(--slate-600);
    color: var(--slate-100);
}

body.dark-mode .decline-reason-input:focus {
    border-color: #f87171;
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.15);
}

/* Unavailable Button */
.unavailable-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    background: transparent;
    border: 1px solid var(--slate-300);
    border-radius: var(--radius-md);
    color: var(--slate-400);
    cursor: pointer;
    transition: all 0.15s ease;
}

/* Hover/active state uses red-500 (--review-urgent legacy hex) consistently
   to give the action a slightly punchier red than the canonical busy red-600.
   Kept hardcoded; a future --rc-status-busy-soft would replace it. */
.unavailable-btn:hover {
    background: rgba(239, 68, 68, 0.1);
    border-color: #ef4444;
    color: #ef4444;
}

.unavailable-btn.active {
    background: #ef4444;
    border-color: #ef4444;
    color: white;
}

body.dark-mode .unavailable-btn {
    border-color: var(--slate-500);
    color: var(--slate-500);
}

body.dark-mode .unavailable-btn:hover {
    background: rgba(239, 68, 68, 0.2);
    border-color: #f87171;
    color: #f87171;
}

body.dark-mode .unavailable-btn.active {
    background: #dc2626;
    border-color: #dc2626;
    color: white;
}

/* Proposal Option States */
.proposal-option.rank-selected {
    background: var(--primary-50);
    border-color: var(--primary-300);
}

.proposal-option.rank-unavailable {
    background: rgba(239, 68, 68, 0.05);
    border-color: rgba(239, 68, 68, 0.3);
    opacity: 0.7;
}

body.dark-mode .proposal-option.rank-selected {
    background: rgba(20, 184, 166, 0.1);
    border-color: var(--primary-500);
}

body.dark-mode .proposal-option.rank-unavailable {
    background: rgba(239, 68, 68, 0.1);
    border-color: rgba(239, 68, 68, 0.4);
}

/* Vote Summary */
.proposal-vote-summary {
    padding: 6px 10px;
    background: var(--slate-50);
    border-radius: var(--rc-radius-btn);
    margin-bottom: var(--rc-spacing-section);
}

.vote-summary-text {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--rc-font-secondary);
    font-weight: 500;
    color: var(--primary-600);
}

.vote-summary-text i {
    color: var(--primary-500);
}

.vote-summary-text.vote-summary-empty {
    color: var(--slate-500);
}

.vote-summary-text.vote-summary-empty i {
    display: none;
}

body.dark-mode .proposal-vote-summary {
    background: var(--slate-700);
}

body.dark-mode .vote-summary-text {
    color: var(--primary-400);
}

body.dark-mode .vote-summary-text i {
    color: var(--primary-400);
}

body.dark-mode .vote-summary-text.vote-summary-empty {
    color: var(--slate-400);
}

.option-votes {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 12px;
}

.vote-bar {
    flex: 1;
    height: 8px;
    background: var(--slate-100);
    border-radius: var(--radius-full);
    overflow: hidden;
}

body.dark-mode .vote-bar {
    background: var(--slate-600);
}

.vote-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--primary-400) 0%, var(--primary-500) 100%);
    border-radius: var(--radius-full);
    transition: width var(--transition-slow);
}

.vote-count {
    font-size: 12px;
    font-weight: 600;
    color: var(--slate-500);
    min-width: 40px;
    text-align: right;
}

body.dark-mode .vote-count {
    color: var(--slate-400);
}

/* Collaborative Suggest Time (for collaborative mode polls) */
.proposal-suggest-time {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 0;
    border-top: 1px dashed var(--slate-200);
    margin-top: 8px;
}

body.dark-mode .proposal-suggest-time {
    border-top-color: var(--slate-600);
}

.suggest-time-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 6px 14px;
    border: 1px dashed var(--primary-300);
    border-radius: 6px;
    background: transparent;
    color: var(--primary-600);
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s ease;
    font-family: inherit;
}

.suggest-time-btn:hover {
    background: var(--primary-50);
    border-style: solid;
}

body.dark-mode .suggest-time-btn {
    border-color: var(--primary-600);
    color: var(--primary-400);
}

body.dark-mode .suggest-time-btn:hover {
    background: rgba(20, 184, 166, 0.1);
}

.suggest-time-picker {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.suggest-date-input,
.suggest-time-input {
    padding: 8px 12px;
    border: 1px solid var(--slate-300);
    border-radius: var(--radius-md, 8px);
    font-size: 0.8125rem;
    background: white;
    color: var(--slate-800);
    font-family: inherit;
}

.suggest-date-input:focus,
.suggest-time-input:focus {
    outline: none;
    border-color: var(--primary-400);
}

body.dark-mode .suggest-date-input,
body.dark-mode .suggest-time-input {
    background: var(--slate-800);
    border-color: var(--slate-600);
    color: var(--slate-200);
}

.suggest-add-btn,
.suggest-cancel-btn {
    padding: 8px 12px;
    border: none;
    border-radius: var(--radius-md, 8px);
    font-size: 0.8125rem;
    cursor: pointer;
    transition: all 0.15s ease;
    font-family: inherit;
}

.suggest-add-btn {
    background: var(--primary-500);
    color: white;
}

.suggest-add-btn:hover {
    background: var(--primary-600);
}

.suggest-cancel-btn {
    background: var(--slate-200);
    color: var(--slate-600);
}

.suggest-cancel-btn:hover {
    background: var(--slate-300);
}

body.dark-mode .suggest-cancel-btn {
    background: var(--slate-700);
    color: var(--slate-300);
}

body.dark-mode .suggest-cancel-btn:hover {
    background: var(--slate-600);
}

/* Proposal Actions */
.proposal-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding-top: var(--rc-spacing-section);
    border-top: 1px solid var(--slate-200);
}

body.dark-mode .proposal-actions {
    border-color: var(--slate-600);
}

.cant-attend {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: var(--rc-font-secondary);
    color: #ef4444;
    cursor: pointer;
    transition: color 0.2s ease;
}

.cant-attend:hover {
    color: #dc2626;
}

body.dark-mode .cant-attend {
    color: #f87171;
}

body.dark-mode .cant-attend:hover {
    color: #fca5a5;
}

.cant-attend-checkbox {
    width: 16px;
    height: 16px;
    accent-color: #ef4444;
}

.submit-vote-btn {
    padding: 6px 16px;
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 600;
    color: white;
    background: var(--primary-500);
    border: none;
    border-radius: var(--rc-radius-btn, 6px);
    cursor: pointer;
    transition: all 0.15s ease;
}

.submit-vote-btn:hover {
    background: var(--primary-600);
}

.submit-vote-btn i {
    margin-right: 4px;
    font-size: 11px;
}

.cant-attend i {
    color: #ef4444;
    margin-left: 4px;
}

body.dark-mode .cant-attend i {
    color: #f87171;
}

/* ============================================
   PERMISSION BADGES (Traffic Light Colors)
   ============================================ */
.permission-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: var(--radius-full);
    font-size: 12px;
    font-weight: 600;
}

.permission-badge i {
    font-size: 11px;
}

.permission-teal,
.permission-indigo,
.permission-red {
    background: rgba(20, 184, 166, 0.12);
    color: #0d9488;
    border: 1px solid rgba(20, 184, 166, 0.25);
}

.permission-amber {
    background: rgba(245, 158, 11, 0.12);
    color: #d97706;
    border: 1px solid rgba(245, 158, 11, 0.25);
}

.permission-green {
    background: rgba(34, 197, 94, 0.12);
    color: #16a34a;
    border: 1px solid rgba(34, 197, 94, 0.25);
}

.permission-slate {
    background: rgba(100, 116, 139, 0.12);
    color: #475569;
    border: 1px solid rgba(100, 116, 139, 0.25);
}

/* Dark mode permission badges */
body.dark-mode .permission-teal,
body.dark-mode .permission-indigo,
body.dark-mode .permission-red {
    background: rgba(20, 184, 166, 0.18);
    color: #5eead4;
    border-color: rgba(20, 184, 166, 0.35);
}

body.dark-mode .permission-amber {
    background: rgba(245, 158, 11, 0.18);
    color: #fbbf24;
    border-color: rgba(245, 158, 11, 0.35);
}

body.dark-mode .permission-green {
    background: rgba(34, 197, 94, 0.18);
    color: #4ade80;
    border-color: rgba(34, 197, 94, 0.35);
}

body.dark-mode .permission-slate {
    background: rgba(148, 163, 184, 0.15);
    color: #94a3b8;
    border-color: rgba(148, 163, 184, 0.3);
}

/* ============================================
   MEMBER CHIP — inline person badge with avatar,
   status dot, name, and optional fairness arc
   ============================================ */

.rc-member-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 1px 8px 1px 2px;
    border-radius: 12px;
    background: rgba(100, 116, 139, 0.08);
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-700, #334155);
    line-height: 1;
    vertical-align: middle;
    white-space: nowrap;
    max-width: 220px;
    transition: background 0.15s ease;
}

.rc-member-chip:hover {
    background: rgba(100, 116, 139, 0.14);
}

.rc-member-chip-avatar {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 7px;
    font-weight: 700;
    color: #fff;
    flex-shrink: 0;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
    position: relative;
}

.rc-member-chip-status {
    position: absolute;
    bottom: -1px;
    right: -1px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    border: 1.5px solid var(--bg-secondary, #fff);
}

/* Status dots derive from the canonical status palette where a token
   exists (working/busy/tentative), so they can't drift from the rest of
   the app. sleep keeps its distinct indigo (no rc-status token for it). */
.rc-member-chip-status.status-working   { background: var(--rc-status-available, #22c55e); }
.rc-member-chip-status.status-extended  { background: var(--rc-status-tentative, #fbbf24); }
.rc-member-chip-status.status-off       { background: var(--rc-status-tentative, #fbbf24); }
.rc-member-chip-status.status-sleep     { background: #a78bfa; }
.rc-member-chip-status.status-busy      { background: var(--rc-status-busy, #ef4444); }
.rc-member-chip-status.status-tentative { background: var(--rc-status-tentative, #f59e0b); }

.rc-member-chip-prefix {
    color: var(--slate-400, #94a3b8);
    font-weight: 400;
}

.rc-member-chip-name {
    font-weight: 600;
    color: var(--slate-700, #334155);
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 130px;
}

.rc-member-chip .admin-inline-badge {
    margin-left: 2px;
}

.rc-member-chip-fairness {
    display: inline-flex;
    align-items: center;
    gap: 1px;
    margin-left: 1px;
    flex-shrink: 0;
}

.rc-member-chip-fairness svg {
    flex-shrink: 0;
}

.rc-member-chip-fairness-value {
    font-size: 8px;
    font-weight: 700;
    line-height: 1;
    min-width: 12px;
    text-align: right;
}

/* Dark mode */
body.dark-mode .rc-member-chip {
    background: rgba(148, 163, 184, 0.12);
    color: var(--slate-200, #e2e8f0);
}

body.dark-mode .rc-member-chip:hover {
    background: rgba(148, 163, 184, 0.2);
}

body.dark-mode .rc-member-chip-prefix {
    color: var(--slate-400, #94a3b8);
}

body.dark-mode .rc-member-chip-name {
    color: var(--slate-200, #e2e8f0);
}

body.dark-mode .rc-member-chip-status {
    border-color: var(--bg-secondary, #1e293b);
}

/* Responsive: tighter on small screens */
@media (max-width: 480px) {
    .rc-member-chip {
        max-width: 160px;
        gap: 3px;
        padding: 1px 6px 1px 1px;
    }
    .rc-member-chip-avatar {
        width: 16px;
        height: 16px;
        font-size: 6px;
    }
    .rc-member-chip-name {
        max-width: 90px;
    }
    .rc-member-chip-fairness svg {
        width: 14px;
        height: 14px;
    }
}

/* Danger outline button for Hide action */
.btn-danger-outline {
    color: #dc2626;
    background: transparent;
    border: 1px solid rgba(220, 38, 38, 0.3);
    border-radius: 8px;
    padding: 6px 12px;
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    transition: all 0.15s ease;
}

.btn-danger-outline:hover {
    background: rgba(220, 38, 38, 0.08);
    border-color: rgba(220, 38, 38, 0.5);
}

body.dark-mode .btn-danger-outline {
    color: #f87171;
    border-color: rgba(248, 113, 113, 0.3);
}

body.dark-mode .btn-danger-outline:hover {
    background: rgba(248, 113, 113, 0.12);
    border-color: rgba(248, 113, 113, 0.5);
}

/* ============================================
   OUTGOING/REQUESTED EVENTS TAB
   ============================================ */
.outgoing-events {
    display: flex;
    flex-direction: column;
    gap: 24px;
}

/* All accepted message */
.outgoing-all-accepted {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 24px;
    margin-bottom: 24px;
    background: linear-gradient(135deg, rgba(16, 185, 129, 0.1) 0%, rgba(16, 185, 129, 0.05) 100%);
    border: 1px solid rgba(16, 185, 129, 0.2);
    border-radius: var(--radius-xl);
    text-align: center;
}

.all-accepted-icon {
    font-size: 28px;
    color: #10b981;
    margin-bottom: 8px;
}

.all-accepted-text {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--slate-800);
    margin: 0 0 2px 0;
}

.all-accepted-subtext {
    font-size: 0.75rem;
    color: var(--slate-500);
    margin: 0;
}

body.dark-mode .outgoing-all-accepted {
    background: linear-gradient(135deg, rgba(16, 185, 129, 0.15) 0%, rgba(16, 185, 129, 0.08) 100%);
    border-color: rgba(16, 185, 129, 0.3);
}

body.dark-mode .all-accepted-icon {
    color: #34d399;
}

body.dark-mode .all-accepted-text {
    color: var(--slate-100);
}

body.dark-mode .all-accepted-subtext {
    color: var(--slate-400);
}

/* Outgoing Sections */
.outgoing-section {
    margin-bottom: 24px;
}

.outgoing-section:last-child {
    margin-bottom: 0;
}

.outgoing-section-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    margin-bottom: 16px;
    background: var(--slate-50);
    border-radius: var(--radius-lg);
    border-left: 4px solid var(--review-warning);
}

.outgoing-section-pending .outgoing-section-header {
    border-left-color: var(--review-warning);
    background: linear-gradient(135deg, rgba(245, 158, 11, 0.08) 0%, var(--slate-50) 100%);
}

.outgoing-section-accepted .outgoing-section-header {
    border-left-color: var(--review-success);
    background: linear-gradient(135deg, rgba(16, 185, 129, 0.08) 0%, var(--slate-50) 100%);
}

.outgoing-section-header .section-icon {
    font-size: 14px;
    color: var(--review-warning);
}

.outgoing-section-header .section-icon.accepted {
    color: var(--review-success);
}

.outgoing-section-header .section-count {
    background: var(--review-warning);
}

.outgoing-section-accepted .outgoing-section-header .section-count {
    background: var(--review-success);
}

body.dark-mode .outgoing-section-header {
    background: var(--slate-800);
}

body.dark-mode .outgoing-section-pending .outgoing-section-header {
    background: linear-gradient(135deg, rgba(245, 158, 11, 0.12) 0%, var(--slate-800) 100%);
}

body.dark-mode .outgoing-section-accepted .outgoing-section-header {
    background: linear-gradient(135deg, rgba(16, 185, 129, 0.12) 0%, var(--slate-800) 100%);
}

.outgoing-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Status badges for outgoing events */
.outgoing-status-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 8px;
    font-size: var(--rc-font-tiny);
    font-weight: 600;
    border-radius: var(--rc-radius-pill);
    white-space: nowrap;
}

.outgoing-status-badge i {
    font-size: 9px;
}

.outgoing-status-badge.pending {
    color: var(--review-warning);
    background: var(--review-warning-light);
}

.outgoing-status-badge.accepted {
    color: #10b981;
    background: rgba(16, 185, 129, 0.12);
}

.outgoing-status-badge.declined {
    color: #ef4444;
    background: rgba(239, 68, 68, 0.1);
}

body.dark-mode .outgoing-status-badge.pending {
    color: #fbbf24;
    background: rgba(245, 158, 11, 0.15);
}

body.dark-mode .outgoing-status-badge.accepted {
    color: #34d399;
    background: rgba(16, 185, 129, 0.2);
}

body.dark-mode .outgoing-status-badge.declined {
    color: #f87171;
    background: rgba(239, 68, 68, 0.15);
}

.outgoing-event {
    padding: var(--rc-spacing-card);
    background: var(--review-card-bg);
    border: 1px solid var(--review-card-border);
    border-radius: var(--rc-radius-card);
    box-shadow: var(--review-card-shadow);
    margin-bottom: 6px;
}

.outgoing-event.accepted {
    border-left: 3px solid var(--review-success);
}

.outgoing-event.in-review {
    border-left: 3px solid var(--review-warning);
}

/* outgoing-event-header replaced by rc-card-header + rc-title-row */

.outgoing-event .event-title {
    font-size: var(--rc-font-heading);
    font-weight: 600;
    color: var(--slate-800);
}

body.dark-mode .outgoing-event .event-title {
    color: var(--slate-100);
}

.outgoing-event .status-indicator {
    font-size: 0.75rem;
}

/* Outgoing meta line (dot-separated) */
.outgoing-meta-line {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0;
    font-size: var(--rc-font-secondary);
    color: var(--slate-500);
}

.outgoing-meta-line > span {
    white-space: nowrap;
}

.outgoing-meta-line > span:not(:last-child):not(.outgoing-meta-right)::after {
    content: "\00B7";
    margin: 0 6px;
    color: var(--slate-300);
}

/* Right-aligned zone in outgoing meta line */
.outgoing-meta-right {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
    flex-shrink: 0;
}

body.dark-mode .outgoing-meta-line {
    color: var(--slate-400);
}

body.dark-mode .outgoing-meta-line > span:not(:last-child)::after {
    color: var(--slate-600);
}


.recipient-note {
    margin-top: 6px;
    padding: 6px 10px;
    font-size: var(--rc-font-secondary);
    color: var(--slate-600);
    background: var(--slate-50);
    border-radius: var(--rc-radius-btn);
    border-left: 3px solid var(--primary-400);
}

.recipient-note .note-label {
    font-weight: 600;
    color: var(--slate-700);
}

body.dark-mode .recipient-note {
    color: var(--slate-300);
    background: rgba(255, 255, 255, 0.05);
}

body.dark-mode .recipient-note .note-label {
    color: var(--slate-200);
}

/* ============================================
   RESPONSIVE STYLES
   ============================================ */
@media (max-width: 768px) {
    .review-modal .modal-content {
        max-width: 100%;
        min-height: 100%;
        max-height: 100%;
        border-radius: 0;
        margin: 0;
    }

    .review-dashboard-header {
        padding: 12px 14px 10px;
        gap: 8px;
    }

    .review-dashboard-header .rdh-title {
        font-size: 13px;
    }

    .review-dashboard-header .rdh-title i {
        font-size: 14px;
    }

    .review-dashboard {
        padding: 12px;
    }

    .review-tabs {
        gap: 2px;
        padding: 2px;
    }

    .review-tab {
        padding: 5px 8px;
        font-size: 0.7rem;
    }

    .review-item {
        padding: 12px 14px;
    }

    .review-item-header {
        flex-direction: column;
        align-items: flex-start;
    }

    /* STAY HORIZONTAL ON MOBILE (2026-08-16, user: "space inefficient and
       stacked rather than horizontal"). Stacking three mutually-exclusive
       options into a column costs three rows for one question and breaks the
       segmented track into three loose bars. Private/Busy/Shared are short
       enough to share one row at 390px — verified on the live render. */
    .visibility-options {
        flex-direction: row;
    }

    .visibility-btn {
        justify-content: center;
    }
    /* The confirm button is NOT a segment; it still wants its own full line. */
    .visibility-options .rc-vis-apply-btn {
        width: 100%;
    }

    .auto-accept-config {
        flex-direction: column;
        align-items: flex-start;
        gap: 16px;
    }

    .permission-config {
        flex-direction: column;
        align-items: stretch;
        gap: 12px;
    }

    .permission-level-select {
        width: 100%;
        min-width: auto;
    }

    .revoke-access-btn {
        justify-content: center;
    }

    .action-buttons {
        flex-direction: column;
    }

}

@media (max-width: 480px) {
    /* 2026-07-12 full-modal redesign: the separate .review-dashboard-header row
       is gone — brand + actions now ride inside the single pinned .rc-tabrow.
       On phones the strip's action cluster (sync · ⋯ · close) hugs the right and
       must not be squeezed by the tabs; the brand text collapses to icon-only to
       save the width. No absolute-pinning needed anymore — the flex row + the
       clipped brand keep everything on one line. */
    .rc-tabrow .rdh-actions {
        margin-left: auto;
        flex-shrink: 0;
    }

    /* NO BRAND MARK ON PHONES (2026-07-30, user: "remove the bell").
       The concierge glyph was pure decoration inside a modal the user just
       opened — they know where they are — and it cost a whole row: at 44px it
       could not share the line with the 48px tab pill, so it wrapped and sat
       alone above the tabs with the rest of the row empty. Screen-reader users
       lose nothing: the <h2> is the modal's aria-labelledby target, so it stays
       in the DOM, visually hidden, with its full "Review Center" text intact
       (previously the TEXT was clipped and only the meaningless glyph showed —
       so this is strictly better for a11y as well as for space). */
    .rc-tabrow .rdh-title {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        clip-path: inset(50%);
        white-space: nowrap;
        border: 0;
        min-height: 0;
    }
    /* The text is no longer clipped separately — the whole heading is offscreen
       now, so let it read naturally to assistive tech. */
    .rc-tabrow .rdh-title .rdh-title-text {
        position: static;
        width: auto;
        height: auto;
        margin: 0;
        clip: auto;
        clip-path: none;
    }

    .review-item-title {
        font-size: 12px;
    }

    .review-group-header {
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
    }

    .accept-all-btn {
        width: 100%;
    }

    .proposal-header {
        gap: 3px;
    }

    .proposal-title-row {
        gap: 4px;
    }

    .proposal-meta-line {
        font-size: var(--rc-font-caption);
    }

    /* Compact voting options on mobile: stack time + date */
    .proposal-option {
        flex-wrap: wrap;
        gap: 4px 8px;
    }

    .option-date-sep {
        display: none;
    }

    .option-duration {
        margin-left: 0;
    }

    .proposal-actions {
        flex-wrap: wrap;
        justify-content: flex-end;
        gap: 8px;
    }

    /* Review meta line wraps on mobile */
    .review-meta-line {
        font-size: var(--rc-font-caption);
    }

    /* Decline panel full-width on mobile */
    .decline-panel {
        width: 100%;
        max-width: 100%;
        border-left: none;
        border-top: 4px solid #ef4444;
    }

    .decline-panel-overlay {
        align-items: flex-end;
    }

    /* ---- Scheduled tab ---- */
    /* Lay the action row (Accept / Suggest another time / Decline / ⋮More) out
       as an even 2-up grid instead of ragged right-wrapping. The old
       `.action-buttons{flex-direction:column}` rule targeted a class this row
       doesn't use, so the stack never applied here. Direct-child .btn only, so
       the icon trigger nested in .more-options-dropdown stays compact. */
    .review-actions-row {
        justify-content: stretch;
    }
    .review-actions-row > .btn {
        flex: 1 1 calc(50% - 4px);
        justify-content: center;
    }
    /* The ⋮ More trigger stays a compact square at the end of the row. */
    .review-actions-row > .more-options-dropdown {
        flex: 0 0 auto;
    }
    /* Long titles ellipsize within the card instead of overflowing it. The
       title row is allowed to wrap so the right-zone (date/time) drops under
       the title rather than forcing horizontal overflow. */
    .rc-title-row .event-title,
    .rc-title-row .review-item-title,
    .review-item-title {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        max-width: 100%;
    }
    .rc-title-right {
        white-space: normal;
    }
    .trust-indicator {
        flex-wrap: wrap;
    }

    /* ---- Proposals tab ---- */
    /* The fixed-min-width column header (fairness / who's free / votes) can't
       fit beside its label at 390px and de-aligns once option rows wrap, so
       hide it on mobile; each option row already labels its own stats. */
    .proposal-options-header {
        display: none;
    }

    /* ---- Requested tab ---- */
    .my-proposal-title {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        max-width: 100%;
    }
    /* Stats cluster (vote bar + reachable + fairness + N unavailable) wraps
       instead of overflowing the option row. */
    .time-option-stats {
        flex-wrap: wrap;
    }
    /* Keep the standing badge inside the card edge so it isn't clipped at
       the screen edge (it was poking out at left:-8px). */
    .time-option .rc-standing,
    .my-proposal-time .rc-standing {
        left: 0;
    }
}

/* ============================================
   ACCESSIBILITY
   ============================================ */
@media (prefers-reduced-motion: reduce) {
    .review-btn,
    .review-item,
    .filter-tab,
    .review-tab,
    .visibility-btn,
    .settings-toggle-btn,
    .toggle-slider,
    .toggle-slider::after,
    .action-buttons .btn,
    .accept-all-btn,
    .submit-vote-btn {
        transition: none;
    }

    .review-count-badge.visible,
    .review-count-badge.urgent,
    .review-status-badge.in-review::before,
    .auto-accept-timer.urgent,
    .review-btn.has-items {
        animation: none;
    }
}

/* Focus visible states for keyboard navigation */
.review-btn:focus-visible,
.filter-tab:focus-visible,
.review-tab:focus-visible,
.visibility-btn:focus-visible,
.settings-toggle-btn:focus-visible,
.action-buttons .btn:focus-visible,
.accept-all-btn:focus-visible,
.submit-vote-btn:focus-visible,
/* Previously-unfocusable interactive controls (keyboard users got no ring). */
.review-actions-row .btn:focus-visible,
.conflict-action-btn:focus-visible,
.rank-circle:focus-visible,
.proposal-option:focus-visible,
.dropdown-item:focus-visible,
.sub-tab:focus-visible,
.change-vote-btn:focus-visible,
.schedule-winner-btn:focus-visible,
.view-details-btn:focus-visible,
.cancel-proposal-btn:focus-visible,
.remind-voters-btn:focus-visible,
.undo-accept-btn:focus-visible,
.proposal-description-line:focus-visible,
.timeoff-approve-btn:focus-visible,
.timeoff-reject-btn:focus-visible,
.more-options-btn:focus-visible,
.rc-card-expand-btn:focus-visible,
/* Destructive + sub-flow controls that previously had NO focus ring. */
.revoke-access-btn:focus-visible,
.btn-danger-outline:focus-visible,
.decline-panel-cancel-btn:focus-visible,
.decline-panel-confirm-btn:focus-visible,
.decline-panel-close:focus-visible,
.suggest-time-btn:focus-visible,
.suggest-add-btn:focus-visible,
.suggest-cancel-btn:focus-visible,
.unavailable-btn:focus-visible,
.rc-batch-cb:focus-visible,
.review-retry-btn:focus-visible,
.rc-pd-close:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring-shadow);
}

/* ============================================
   MY PROPOSALS SECTION (Outgoing Tab)
   ============================================ */
.my-proposals-list {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.my-proposal-card {
    background: var(--review-card-bg);
    border: 1px solid var(--review-card-border);
    border-radius: var(--rc-radius-card);
    padding: var(--rc-spacing-card);
    box-shadow: var(--review-card-shadow);
    transition: all 0.15s ease;
}

.my-proposal-card:hover {
    border-color: rgba(16, 185, 129, 0.3);
    box-shadow: 0 2px 12px rgba(16, 185, 129, 0.08);
}

.my-proposal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px;
}

.my-proposal-title-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

.my-proposal-title {
    font-size: var(--rc-font-heading);
    font-weight: 600;
    color: var(--slate-800);
    line-height: 1.3;
}

body.dark-mode .my-proposal-title {
    color: var(--slate-100);
}

/* Proposed Dates - compact */
.proposed-dates {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    font-size: var(--rc-font-caption);
    font-weight: 600;
    color: #0369a1;
    background: rgba(14, 165, 233, 0.1);
    border: 1px solid rgba(14, 165, 233, 0.25);
    border-radius: var(--rc-radius-pill);
}

.proposed-dates i {
    font-size: 9px;
    color: #0ea5e9;
}

body.dark-mode .proposed-dates {
    color: #38bdf8;
    background: rgba(14, 165, 233, 0.15);
    border-color: rgba(14, 165, 233, 0.35);
}

body.dark-mode .proposed-dates i {
    color: #38bdf8;
}

/* Options count badge */
.proposal-options-count {
    display: inline-flex;
    align-items: center;
    padding: 3px 8px;
    font-size: 0.7rem;
    font-weight: 500;
    color: var(--slate-500);
    background: rgba(148, 163, 184, 0.1);
    border-radius: var(--radius-full);
}

body.dark-mode .proposal-options-count {
    color: var(--slate-400);
    background: rgba(148, 163, 184, 0.15);
}

.my-proposal-status {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    font-size: var(--rc-font-tiny);
    font-weight: 600;
    border-radius: var(--rc-radius-pill);
    text-transform: uppercase;
    letter-spacing: 0.3px;
    white-space: nowrap;
}

.my-proposal-status.open {
    background: rgba(16, 185, 129, 0.1);
    color: #059669;
    border: 1px solid rgba(16, 185, 129, 0.25);
}

.my-proposal-status.closed {
    background: rgba(100, 116, 139, 0.1);
    color: #64748b;
    border: 1px solid rgba(100, 116, 139, 0.25);
}

body.dark-mode .my-proposal-status.open {
    background: rgba(16, 185, 129, 0.2);
    color: #34d399;
}

body.dark-mode .my-proposal-status.closed {
    background: rgba(100, 116, 139, 0.2);
    color: #94a3b8;
}

.my-proposal-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    margin-bottom: var(--rc-spacing-section);
}

/* Push voting progress badge to the right */
.my-proposal-meta .voting-progress-badge {
    margin-left: auto;
}

/* Compact Voting Progress Badge */
.voting-progress-badge {
    position: relative;
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--slate-600);
    background: rgba(148, 163, 184, 0.1);
    border: 1px solid rgba(148, 163, 184, 0.2);
    border-radius: var(--radius-full);
    overflow: hidden;
}

.voting-progress-bar {
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    background: linear-gradient(90deg, rgba(16, 185, 129, 0.2) 0%, rgba(20, 184, 166, 0.15) 100%);
    border-radius: var(--radius-full);
    transition: width 0.3s ease;
}

.voting-progress-text {
    position: relative;
    z-index: 1;
}

.voting-progress-badge.complete {
    background: rgba(16, 185, 129, 0.1);
    border-color: rgba(16, 185, 129, 0.3);
    color: #059669;
}

.voting-progress-badge.complete .voting-progress-bar {
    background: linear-gradient(90deg, rgba(16, 185, 129, 0.25) 0%, rgba(16, 185, 129, 0.2) 100%);
}

body.dark-mode .voting-progress-badge {
    color: var(--slate-400);
    background: rgba(148, 163, 184, 0.15);
    border-color: rgba(148, 163, 184, 0.25);
}

body.dark-mode .voting-progress-badge.complete {
    color: #34d399;
    background: rgba(16, 185, 129, 0.15);
    border-color: rgba(16, 185, 129, 0.35);
}

/* Leading Option */
.my-proposal-leading {
    background: rgba(16, 185, 129, 0.06);
    border: 1px solid rgba(16, 185, 129, 0.15);
    border-radius: var(--radius-md);
    padding: 14px;
    margin-bottom: 16px;
}

.leading-label {
    display: block;
    font-size: 0.7rem;
    font-weight: 600;
    color: #059669;
    text-transform: uppercase;
    letter-spacing: 0.3px;
    margin-bottom: 8px;
}

.leading-label i {
    margin-right: 6px;
    color: #f59e0b;
}

body.dark-mode .leading-label {
    color: #34d399;
}

.leading-slot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

.leading-time {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--slate-800);
}

body.dark-mode .leading-time {
    color: var(--slate-100);
}

.leading-votes {
    font-size: 0.75rem;
    color: var(--slate-600);
    padding: 2px 8px;
    background: rgba(148, 163, 184, 0.1);
    border-radius: var(--radius-full);
}

body.dark-mode .leading-votes {
    color: var(--slate-400);
    background: rgba(148, 163, 184, 0.2);
}

/* My Proposal Time Options List */
/* ⭐ ONE BOX, NOT THREE (2026-08-06, user: "this layout could be better").
   The time options were a bordered CONTAINER holding bordered ROWS holding a
   bordered TIME CHIP — three nested boxes to render nine words. On a 430px
   phone "Thu 30 Jul" wrapped to two lines beside "1:30 PM (London, UK)" which
   also wrapped, so a single option cost ~200px of height and read as a form
   rather than a list.
   The container is now a plain grouping with no chrome of its own; the row
   below keeps the single border, and the time chip loses its box entirely. */
.my-proposal-times {
    padding: 0;
    margin-bottom: 16px;
}

.times-label {
    display: block;
    font-size: 0.7rem;
    font-weight: 600;
    color: var(--slate-500);
    text-transform: uppercase;
    letter-spacing: 0.3px;
    margin-bottom: 10px;
}

.times-label i {
    margin-right: 6px;
    color: var(--primary-500);
}

body.dark-mode .times-label {
    color: var(--slate-400);
}

.times-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.time-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px 12px;
    padding: 10px 12px;
    background: white;
    border: 1px solid var(--slate-200);
    border-radius: var(--radius-md);
    position: relative;
    transition: all 0.15s ease;
}

.time-option:hover {
    border-color: var(--slate-300);
}

.time-option.leading {
    background: linear-gradient(135deg, rgba(16, 185, 129, 0.08) 0%, rgba(16, 185, 129, 0.04) 100%);
    border-color: rgba(16, 185, 129, 0.25);
}

body.dark-mode .time-option {
    background: rgba(30, 41, 59, 0.6);
    border-color: var(--slate-600);
}

body.dark-mode .time-option.leading {
    background: linear-gradient(135deg, rgba(16, 185, 129, 0.15) 0%, rgba(16, 185, 129, 0.08) 100%);
    border-color: rgba(16, 185, 129, 0.35);
}

.time-option-datetime {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1;
}

.time-option-date {
    font-size: 13px;
    font-weight: 600;
    color: var(--slate-700);
}

body.dark-mode .time-option-date {
    color: var(--slate-200);
}

/* The time is the most important token on the row, so it earns WEIGHT — not a
   box. The tinted, bordered chip was the third nested border and it forced the
   long "(London, UK)" suffix to wrap inside its own frame. */
.time-option-time {
    font-size: 14px;
    font-weight: 700;
    color: var(--slate-900);
}
/* Keep date · time on ONE line and let it shrink rather than wrap; the row is
   a scannable list item, not a paragraph. */
.time-option-datetime {
    min-width: 0;
    flex-wrap: nowrap;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.time-option-date { white-space: nowrap; }
body.dark-mode .time-option-time { color: var(--slate-100); }

body.dark-mode .time-option-time {
    color: var(--slate-100);
    background: linear-gradient(135deg, rgba(20, 184, 166, 0.15) 0%, rgba(20, 184, 166, 0.08) 100%);
    border-color: rgba(20, 184, 166, 0.3);
}

.time-option-stats {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Per-slot "no" tally for the organiser: how many teammates ruled this time
   out. Calm and neutral (slate) — it informs the scheduling decision without
   shouting; the positive vote bar stays the focal stat. */
.slot-decline-count {
    font-size: 11px;
    color: var(--slate-500);
    padding: 1px 7px;
    border-radius: var(--radius-full);
    background: rgba(148, 163, 184, 0.12);
    white-space: nowrap;
}
body.dark-mode .slot-decline-count {
    color: var(--slate-400);
    background: rgba(148, 163, 184, 0.18);
}

.time-option-votes {
    font-size: 12px;
    color: var(--slate-500);
    padding: 2px 8px;
    background: rgba(148, 163, 184, 0.1);
    border-radius: var(--radius-full);
}

body.dark-mode .time-option-votes {
    color: var(--slate-400);
    background: rgba(148, 163, 184, 0.2);
}

/* The Sent-by-me time rows carry the standing as a POSITIONED BADGE on the row
   edge, not as inline text — the row's stats already fill the line. Inherited
   verbatim from .leading-indicator (2026-08-06), which this replaced: dropping
   the positioning would have left the medal floating in the stats flow and
   re-wrapping the row on a phone.
   The metal tone comes from .rc-standing--* above; only 1st gets the filled
   gradient puck, because a solid gold disc IS the "winning" signal and three
   competing pucks would flatten it back into decoration. */
.time-option .rc-standing,
.my-proposal-time .rc-standing {
    position: absolute;
    left: -8px;
    top: 50%;
    transform: translateY(-50%);
    width: 20px;
    height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-size: 10px;
}
.time-option .rc-standing--gold,
.my-proposal-time .rc-standing--gold {
    /* Amber gradient — gold-medal nod for the leading vote;
       not status, kept as gradient. */
    background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
    color: white;
    box-shadow: 0 2px 6px rgba(245, 158, 11, 0.4);
}
/* Runners-up read as a quiet ring rather than a filled puck. */
.time-option .rc-standing--silver,
.my-proposal-time .rc-standing--silver,
.time-option .rc-standing--bronze,
.my-proposal-time .rc-standing--bronze {
    background: var(--surface-primary, #fff);
    box-shadow: 0 0 0 1px var(--border-color, #e2e8f0);
}
body.dark-mode .time-option .rc-standing--silver,
body.dark-mode .my-proposal-time .rc-standing--silver,
body.dark-mode .time-option .rc-standing--bronze,
body.dark-mode .my-proposal-time .rc-standing--bronze {
    background: var(--slate-800, #1e293b);
    box-shadow: 0 0 0 1px var(--slate-700, #334155);
}

/* My Proposal Actions */
.my-proposal-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 8px;
    padding-top: var(--rc-spacing-section);
    border-top: 1px solid var(--review-card-border);
}

/* .my-proposal-actions .btn sizing now inherits from .review-panel .btn reset */

.schedule-winner-btn {
    background: #10b981;
    color: white;
    border: none;
}

.schedule-winner-btn:hover {
    background: #059669;
}

.view-details-btn {
    background: rgba(148, 163, 184, 0.08);
    color: var(--slate-600);
    border: 1px solid var(--slate-200);
}

.view-details-btn:hover {
    background: rgba(148, 163, 184, 0.15);
    color: var(--slate-700);
}

body.dark-mode .view-details-btn {
    background: rgba(148, 163, 184, 0.1);
    color: var(--slate-300);
    border-color: var(--slate-600);
}

body.dark-mode .view-details-btn:hover {
    background: rgba(148, 163, 184, 0.2);
    color: var(--slate-200);
}

.cancel-proposal-btn {
    background: transparent;
    color: var(--slate-500);
    border: 1px solid transparent;
}

.cancel-proposal-btn:hover {
    background: rgba(239, 68, 68, 0.08);
    color: #dc2626;
    border-color: rgba(239, 68, 68, 0.2);
}

body.dark-mode .cancel-proposal-btn:hover {
    background: rgba(239, 68, 68, 0.15);
    color: #f87171;
}

/* ============================================
   SCHEDULED EVENTS SECTION
   ============================================ */
.scheduled-events-section {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.scheduled-events-group {
    background: var(--review-card-bg);
    backdrop-filter: blur(8px);
    border: 1px solid var(--review-card-border);
    border-radius: var(--radius-lg);
    padding: 16px;
}

.events-group-header {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--slate-600);
    margin-bottom: 12px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--review-card-border);
}

.events-group-header i {
    color: var(--slate-400);
}

body.dark-mode .events-group-header {
    color: var(--slate-400);
}

.group-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    font-size: 0.7rem;
    font-weight: 700;
    color: white;
    background: var(--slate-500);
    border-radius: var(--radius-full);
    margin-left: auto;
}

/* Empty state subtext */
.empty-subtext {
    font-size: 0.8rem;
    color: var(--slate-400);
    margin-top: 4px;
}

/* ============================================
   SCHEDULER INFO MODAL
   "Who is this?" feature
   ============================================ */

.scheduler-info-modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(4px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: var(--z-modal);
    animation: fadeIn 0.2s ease-out;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

.scheduler-info-modal {
    background: var(--review-card-bg, #fff);
    border-radius: var(--radius-xl, 16px);
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
    max-width: 420px;
    width: calc(100% - 32px);
    max-height: calc(100vh - 64px);
    overflow-y: auto;
    animation: slideUp 0.3s ease-out;
}

@keyframes slideUp {
    from {
        opacity: 0;
        transform: translateY(20px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.scheduler-info-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px;
    border-bottom: 1px solid var(--review-card-border, rgba(0,0,0,0.1));
}

.scheduler-info-header h3 {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 600;
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--text-primary, #1e293b);
}

.scheduler-info-header h3 i {
    color: var(--primary-500, #6366f1);
}

.close-scheduler-info {
    background: transparent;
    border: none;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: var(--text-secondary, #64748b);
    transition: background 0.2s, color 0.2s;
}

.close-scheduler-info:hover {
    background: rgba(0, 0, 0, 0.05);
    color: var(--text-primary, #1e293b);
}

.scheduler-info-body {
    padding: 20px;
}

.scheduler-info-section {
    margin-bottom: 20px;
}

.scheduler-info-section:last-child {
    margin-bottom: 0;
}

.scheduler-info-section:first-child {
    display: flex;
    gap: 16px;
    align-items: flex-start;
}

.scheduler-avatar {
    flex-shrink: 0;
}

.scheduler-avatar img {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    object-fit: cover;
    border: 3px solid var(--primary-100, #e0e7ff);
}

.scheduler-avatar-placeholder {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--primary-100, #e0e7ff) 0%, var(--primary-200, #c7d2fe) 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--primary-500, #6366f1);
    font-size: 28px;
}

.scheduler-details {
    flex: 1;
    min-width: 0;
}

.scheduler-name {
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--text-primary, #1e293b);
    margin-bottom: 4px;
}

.scheduler-email,
.scheduler-org {
    font-size: 0.875rem;
    color: var(--text-secondary, #64748b);
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 4px;
}

.scheduler-email i,
.scheduler-org i {
    width: 14px;
    text-align: center;
    color: var(--text-tertiary, #94a3b8);
}

.scheduler-info-section h4 {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-tertiary, #94a3b8);
    margin: 0 0 8px 0;
}

.scheduler-relationship {
    font-size: 0.9375rem;
    color: var(--text-primary, #1e293b);
    padding: 10px 14px;
    background: var(--primary-50, #eef2ff);
    border-radius: var(--radius-md, 8px);
}

.scheduler-history {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
    gap: 12px;
}

.history-stat {
    text-align: center;
    padding: 12px;
    background: rgba(0, 0, 0, 0.02);
    border-radius: var(--radius-md, 8px);
}

.history-value {
    display: block;
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--primary-600, #4f46e5);
    line-height: 1.2;
}

.history-label {
    display: block;
    font-size: 0.75rem;
    color: var(--text-secondary, #64748b);
    margin-top: 4px;
}

.authority-badge {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    background: linear-gradient(135deg, rgba(99, 102, 241, 0.1) 0%, rgba(139, 92, 246, 0.1) 100%);
    border: 1px solid rgba(99, 102, 241, 0.2);
    border-radius: var(--radius-md, 8px);
    font-size: 0.875rem;
    color: var(--primary-700, #4338ca);
}

.authority-badge i {
    font-size: 1.25rem;
}

.warning-section {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 12px 14px;
    background: rgba(245, 158, 11, 0.1);
    border: 1px solid rgba(245, 158, 11, 0.25);
    border-radius: var(--radius-md, 8px);
    font-size: 0.875rem;
    color: #92400e;
}

.warning-section i {
    color: #f59e0b;
    flex-shrink: 0;
    margin-top: 2px;
}

.scheduler-info-actions {
    display: flex;
    gap: 8px;
    padding: 12px 16px;
    border-top: 1px solid var(--review-card-border, rgba(0,0,0,0.1));
    background: rgba(0, 0, 0, 0.02);
}

.scheduler-info-actions .btn {
    flex: 0 0 auto;
    padding: 6px 14px;
    font-size: 12px;
    border-radius: 6px;
}

.scheduler-info-actions #block-scheduler {
    flex: 0 0 auto;
    color: #dc2626;
}

.scheduler-info-actions #block-scheduler:hover {
    background: rgba(220, 38, 38, 0.1);
}

/* Dark mode adjustments */
body.dark-mode .scheduler-info-modal {
    background: var(--review-card-bg, #1e293b);
}

body.dark-mode .scheduler-info-header h3 {
    color: var(--text-primary, #f1f5f9);
}

body.dark-mode .close-scheduler-info {
    color: var(--text-secondary, #94a3b8);
}

body.dark-mode .close-scheduler-info:hover {
    background: rgba(255, 255, 255, 0.1);
    color: var(--text-primary, #f1f5f9);
}

body.dark-mode .scheduler-name {
    color: var(--text-primary, #f1f5f9);
}

body.dark-mode .scheduler-relationship {
    background: rgba(99, 102, 241, 0.15);
    color: var(--text-primary, #f1f5f9);
}

body.dark-mode .history-stat {
    background: rgba(255, 255, 255, 0.05);
}

body.dark-mode .warning-section {
    background: rgba(245, 158, 11, 0.15);
    color: #fcd34d;
}

body.dark-mode .scheduler-info-actions {
    background: rgba(0, 0, 0, 0.2);
}

/* ============================================
   ACTION CONFIRMATION FEEDBACK
   ============================================ */

.review-item.action-complete {
    transition: all 200ms ease-out;
}

.review-item.fade-out {
    opacity: 0;
    max-height: 0;
    margin-bottom: 0;
    padding: 0;
    overflow: hidden;
}

.review-item .action-confirmation {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 10px 14px;
    font-size: 12px;
    font-weight: 500;
    border-radius: 6px;
}

.review-item .action-confirmation i {
    font-size: 12px;
}

.review-item .action-confirmation.accepted {
    background: rgba(34, 197, 94, 0.1);
    color: #166534;
}

.review-item .action-confirmation.declined {
    background: rgba(239, 68, 68, 0.08);
    color: #991b1b;
}

.review-item .action-confirmation.tentative {
    background: rgba(245, 158, 11, 0.1);
    color: #92400e;
}

.review-item .action-confirmation.resolved,
.conflict-pair .action-confirmation.resolved {
    background: rgba(20, 184, 166, 0.1);
    color: #0f766e;
}

/* ============================================
   COMPLETION STATE
   ============================================ */

.review-completion-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 48px 24px;
    text-align: center;
    animation: reviewFadeIn 200ms ease-out;
}

@keyframes reviewFadeIn {
    from {
        opacity: 0;
        transform: translateY(8px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.review-completion-state .completion-icon {
    width: 56px;
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(34, 197, 94, 0.1);
    border-radius: 50%;
    margin-bottom: 16px;
}

.review-completion-state .completion-icon i {
    font-size: 24px;
    color: #22c55e;
}

.review-completion-state .completion-title {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--text-primary, #1e293b);
    margin-bottom: 6px;
}

.review-completion-state .completion-stats {
    font-size: 0.75rem;
    color: var(--text-secondary, #64748b);
    margin-bottom: 14px;
}

.review-completion-state .completion-actions {
    display: flex;
    gap: 10px;
    justify-content: center;
}

/* Done is the ONLY action here now (the "Continue to {tab}" link was removed
   2026-08-19 — tabs do the navigating), so it gets a full-size tap target
   instead of the 12px afterthought it was next to the link. */
.review-completion-state .completion-actions .btn {
    padding: 12px 40px;
    font-size: 15px;
    font-weight: 600;
    border-radius: 8px;
    min-height: 44px; /* comfortable touch target */
}

/* Dark mode */
body.dark-mode .review-item .action-confirmation.accepted {
    background: rgba(34, 197, 94, 0.15);
    color: #86efac;
}

body.dark-mode .review-item .action-confirmation.declined {
    background: rgba(100, 116, 139, 0.2);
    color: #cbd5e1;
}

body.dark-mode .review-item .action-confirmation.tentative {
    background: rgba(245, 158, 11, 0.15);
    color: #fcd34d;
}

body.dark-mode .review-item .action-confirmation.resolved,
body.dark-mode .conflict-pair .action-confirmation.resolved {
    background: rgba(20, 184, 166, 0.15);
    color: #5eead4;
}

body.dark-mode .review-completion-state .completion-icon {
    background: rgba(34, 197, 94, 0.15);
}

body.dark-mode .review-completion-state .completion-title {
    color: var(--text-primary, #f1f5f9);
}

body.dark-mode .review-completion-state .completion-stats {
    color: var(--text-secondary, #94a3b8);
}

/* ============================================
   LOADING SKELETON
   ============================================ */

.review-loading {
    padding: 16px;
}

.review-skeleton-row {
    display: flex;
    gap: 8px;
    margin-bottom: 20px;
}

.review-skeleton-tab {
    flex: 1;
    height: 40px;
    border-radius: var(--radius-md, 8px);
    background: linear-gradient(90deg, rgba(203, 213, 225, 0.3) 25%, rgba(203, 213, 225, 0.5) 50%, rgba(203, 213, 225, 0.3) 75%);
    background-size: 200% 100%;
    animation: reviewShimmer 1.5s ease-in-out infinite;
}

.review-skeleton-card {
    height: 80px;
    border-radius: var(--radius-md, 8px);
    margin-bottom: 12px;
    background: linear-gradient(90deg, rgba(203, 213, 225, 0.2) 25%, rgba(203, 213, 225, 0.4) 50%, rgba(203, 213, 225, 0.2) 75%);
    background-size: 200% 100%;
    animation: reviewShimmer 1.5s ease-in-out infinite;
}

.review-skeleton-card.short {
    height: 56px;
    width: 75%;
}

@keyframes reviewShimmer {
    0% { background-position: -200% 0; }
    100% { background-position: 200% 0; }
}

body.dark-mode .review-skeleton-tab,
body.dark-mode .review-skeleton-card {
    background: linear-gradient(90deg, rgba(71, 85, 105, 0.3) 25%, rgba(71, 85, 105, 0.5) 50%, rgba(71, 85, 105, 0.3) 75%);
    background-size: 200% 100%;
    animation: reviewShimmer 1.5s ease-in-out infinite;
}

/* ============================================
   ENHANCED EMPTY STATES
   ============================================ */

.review-empty .empty-subtext {
    font-size: 12px;
    color: var(--slate-500, #64748b);
    margin-top: 4px;
    line-height: 1.4;
    max-width: 280px;
    margin-left: auto;
    margin-right: auto;
}

body.dark-mode .review-empty .empty-subtext {
    color: var(--slate-400, #94a3b8);
}
/* Dark mode: slate-300 on the dark empty surface clears AA there. */
body.dark-mode .review-empty .empty-hint {
    color: var(--slate-300, #cbd5e1);
}

/* Single source of truth for the empty-state hint. Was defined twice with
   conflicting, both-failing colours: 11px teal @ opacity .8 (~2.8:1) here and
   12px slate-tertiary (~2.6:1) at :9050. Consolidated to slate-600 @ 12px,
   which clears WCAG AA (~7:1 on white) — no opacity (it re-fails contrast). */
.review-empty .empty-hint {
    font-size: 12px;
    color: var(--slate-600, #475569);
    margin-top: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
}

.review-empty .empty-hint i {
    font-size: 12px;
}

/* ============================================
   MOBILE BOTTOM-SHEET BEHAVIOR
   ============================================ */

@media (max-width: 480px) {
    /* 2026-07-21 full-screen redesign: the Review Center was a floating
       bottom-sheet (rounded top, grabber, ~90vh, slide-up over a dimmed
       backdrop). The user's call: make it EDGE-TO-EDGE full-screen like the
       Create-board and Propose modals — one uninterrupted surface, no wasted
       backdrop strip above, no sheet chrome. Match board-modals.css's phone
       rule exactly: fill the viewport, top-aligned, square corners. */
    #review-dashboard-modal {
        align-items: stretch;
        /* Zero the inherited .modal { padding: var(--space-5) } so the surface
           sits flush to all four screen edges. */
        padding: 0;
    }

    #review-dashboard-modal .review-modal-content {
        position: relative;
        width: 100%;
        max-width: 100%;
        /* Full-bleed: fill the viewport height (dvh so the mobile URL bar's
           show/hide doesn't clip the bottom action) rather than a short sheet.
           The ≤768px rule already sets min-height:100% — restate in vh/dvh so
           this beats it and pins the surface to the full screen. */
        min-height: 100vh;
        min-height: 100dvh;
        max-height: 100vh;
        max-height: 100dvh;
        border-radius: 0;
        margin: 0;
        /* Standard modal fade (same as Create/Propose) — no bottom-sheet
           slide-up now that this is a full-screen surface. */
        animation: modalFadeIn 0.2s ease-out;
        padding-bottom: env(safe-area-inset-bottom, 0);
    }

    /* No grabber handle: the ::before pill read as a draggable sheet affordance.
       A full-screen modal has none, so suppress it. */
    #review-dashboard-modal .review-modal-content::before {
        content: none;
    }

    /* Mobile tab row (2026-07-21 wasted-space pass): the old rule stacked
       .rc-tabrow into a COLUMN, so brand / tabs / search+Filters / sync+⋯+×
       each got its own full-width row — five stacked bands of chrome (two of
       them, the right-aligned control + action clusters, wasting the whole
       left half of the screen) before any card showed.

       New layout is a compact TWO-row wrap that fills the width:
         Row 1: [bell]  [ tabs — flex, fill ]  [ sync · ⋯ · × ]
         Row 2: [ 🔍 search ]  [ Filters ▾ ]
       The row-2 controls left-align (their desktop margin-left:auto is dropped
       below) so there's no empty gutter. flex-wrap + `order` do the grouping
       against the fixed DOM order (brand·tabs·triage·controls·actions) without
       any markup change. */
    .rc-tabrow {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        row-gap: 8px;
        column-gap: 8px;
    }
    .rc-tabrow .rdh-title { order: 1; }
    /* flex:1 with basis auto so the tabs eat the whole rest of row 1 — only the
       close (×) shares this row with them (see the display:contents split
       below), which leaves enough width for all three labels IN FULL rather
       than the "Sch… Pro… Pri…" truncation you get when sync+⋯+× all crowd in.
       min-width:0 still lets them ellipsis-shrink as a last resort. */
    /* max-width leaves room for the close button so it can SHARE row 1 rather
       than wrapping below (2026-07-30). With the brand mark removed the tabs had
       the whole row to themselves and their intrinsic width pushed × down onto
       row 2, where it landed first and read as part of the filter cluster. The
       reserved 52px is the 44px button plus the row's 8px column-gap; the tabs
       keep flex:1 so they still fill whatever is left. */
    .review-tabs {
        order: 2;
        flex: 1 1 auto;
        min-width: 0;
        max-width: calc(100% - 52px);
    }

    /* Split the action cluster so ONLY the close button rides row 1 (top-right,
       standard modal spot) while sync + ⋯ drop to row 2 next to the filters.
       display:contents dissolves .rdh-actions as a box so its three children
       become direct flex items of .rc-tabrow and can be ordered individually.
       (.rdh-overflow keeps its own position:relative, so the ⋯ menu still
       anchors correctly.) */
    .rc-tabrow .rdh-actions { display: contents; }
    .rc-tabrow #close-review-modal { order: 3; margin-left: 0; flex-shrink: 0; }

    /* Row 2: search + Filters (left) then sync + ⋯ (right).

       DEAD-GUTTER FIX (2026-07-30). The controls used to size to their content
       while `margin-left:auto` on the sync button shoved the sync/⋯ pair to the
       right edge — which parked a ~60px hole in the MIDDLE of the row (measured
       at 390px: controls ended at x=255.4, sync began at x=263.3, with nothing
       in between). The row read as two clusters adrift rather than one
       deliberate strip.

       Now `.rc-inline-controls` OWNS the slack (flex-grow:1) and distributes it
       INSIDE itself via space-between, so Search sits hard left, Filters trails
       it, and the growth lands as one honest gap that ends exactly where the
       actions begin. Dropping margin-left:auto lets sync/⋯ butt straight up
       against the controls' right edge at the standard 8px column-gap, so the
       whole row is edge-to-edge with no orphan space. */
    .rc-tabrow .rc-inline-controls {
        order: 4;
        flex: 1 1 auto;
        margin-left: 0;                /* kill the desktop right-push gutter */
        justify-content: flex-start;
        /* TWO READABLE GROUPS (2026-07-30, user: "still looks random and
           cluttered … buttons could have more logical placement"). Row 2 was six
           controls in three different shapes with no grouping, so it scanned as
           a random scatter. Now it reads left-to-right as FIND (search +
           Filters, tight 6px so they bind as one unit) then, after the row's
           8px column-gap, ACT (sync + ⋯). Two groups, one gap between them. */
        gap: 6px;
    }
    /* Uniform 36px circular targets for the icon-only controls so the row is one
       consistent shape language instead of circle/pill/bare-glyph mixed. The
       Filters button keeps its wider pill — it carries a text label, so it is
       legitimately a different control, and that difference now reads as
       meaningful rather than accidental. */
    .rc-tabrow #rdh-sync-btn,
    .rc-tabrow .rdh-overflow-btn,
    .rc-tabrow .rc-search-inline .rc-search-toggle {
        width: 36px;
        min-width: 36px;
        height: 36px;
        border-radius: var(--radius-full, 9999px);
        flex-shrink: 0;
    }
    .rc-tabrow #rdh-sync-btn { order: 5; margin-left: 0; flex-shrink: 0; }
    .rc-tabrow .rdh-overflow { order: 6; flex-shrink: 0; }

    /* The Filters button now lives on the LEFT of row 2, so the popover must
       open rightward (left:0) — the desktop right:0 anchor pushed its left edge
       to ~-77px, clipping Work/Personal/Sort off the screen.

       2026-07-30: `left:0` anchors the panel's LEFT edge to the Filters BUTTON,
       and that button sits at the right end of row 2 — so with min-width:220px
       the panel ran straight off the right edge ("Work" clipped to "W", Sort and
       Date Range cut off; user screenshot). max-width could not save it because
       the overflow came from the anchor POSITION, not the width.

       Anchor it to the MODAL instead of the button: pinned to both edges with a
       12px inset, so it is viewport-width by construction and cannot clip on
       either side no matter where the trigger ends up. `position:fixed` would
       escape the modal's transform context, so stay absolute and let the
       stretched inset do the work. */
    #review-dashboard-modal .rc-filters-panel {
        left: 12px;
        right: 12px;
        width: auto;
        min-width: 0;
        max-width: none;
        /* The panel is a child of the small .rc-filters-menu box, so stretch it
           against the sticky bar rather than that box. With the menu made
           static below, `top` now resolves against the BAR — so drop the sheet
           just under the whole header instead of under the button, which is
           where a full-width panel belongs anyway. */
        position: absolute;
        top: calc(100% + 6px);
    }
    /* Give the popover a positioning context that spans the strip, so the
       left/right insets above resolve against the full width. The ≤480px block
       already un-sticks .rc-sticky-bar (position:static) for the anti-vibration
       fix, so relative is safe here — it restores a containing block without
       re-pinning the bar. */
    #review-dashboard-modal .rc-sticky-bar { position: relative; }
    #review-dashboard-modal .rc-tabrow .rc-filters-menu { position: static; }

    /* THE ⋯ MENU NEEDS THE SAME TREATMENT (2026-08-16, user: "The three dot
       menu in review center on mobile hangs off the page").
       It kept the desktop `right:0` + `min-width:200px` anchored to a 36px
       button, while .rdh-actions is dissolved to `display:contents` here and
       the button's final x-position comes from an `order` value — so a 200px
       panel hung off whichever edge the trigger landed near. Same fix the
       Filters panel got above: anchor to the MODAL, not the button, so it is
       viewport-width by construction and cannot clip on either side. */
    #review-dashboard-modal .rc-tabrow .rdh-overflow { position: static; }
    #review-dashboard-modal .rdh-overflow-menu {
        left: 12px;
        right: 12px;
        width: auto;
        min-width: 0;
        max-width: none;
    }

    .review-tabs {
        overflow-x: visible;   /* no scroll needed: 1 labelled + 3 icon tabs fit */
        gap: 4px;
        /* The base rule is `display:inline-flex`, which SHRINK-WRAPS to content.
           The tabs inside are `flex:1 1 0` (equal widths), but equal shares of a
           shrink-wrapped box are not equal shares of the ROW — so the active tab
           (wider: it carries a count badge) claimed more and squeezed its
           neighbour into "Propos…" while Privacy kept visible slack, which read
           as badly aligned tabs (user 2026-07-30). Switching to plain `flex`
           lets the pill fill the width `.rc-tabrow` allots it, so the three tabs
           are genuine thirds and the truncation goes away. */
        display: flex;
        width: 100%;
    }

    /* FOUR tabs on a phone (2026-08-04: Requests became permanent, so the row
       is Events / Proposals / Privacy / Requests). Four labelled tabs do NOT
       fit 390px — the 2026-06-29 lesson — so only the ACTIVE tab shows its
       label; inactive tabs collapse to icon + count. The icons are the same
       glyph+colour as the launcher strip (ReviewTabIdentity), so an icon-only
       tab is still identifiable, and the active tab always names itself. */
    .review-tab {
        flex: 0 1 auto;
        min-width: 0;
        width: auto;
        min-height: 44px;
        padding: 9px 10px;
        gap: 4px;
        justify-content: center;
    }
    .review-tab.active {
        /* The labelled tab takes the slack; icon tabs stay compact. */
        flex: 1 1 auto;
    }

    .review-tab:not(.active) .tab-label {
        display: none;
    }
    .review-tab .tab-icon {
        font-size: 0.85rem;   /* icon is the whole identity when unlabelled */
    }

    .review-tab .tab-label {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 100%;
        font-size: 11.5px;
    }

    /* ⭐2026-08-20 (owner: "Even when selected proposal tabs never read the
       full label. If selected you should see the level. Make the area
       sufficient or remove the icon to give space when clicked").
       The active tab is the ONE tab that must name itself, but it was still
       competing with its own icon for a ~100px box, so "Proposals" ellipsised
       to "Propos…". Take the owner's second option: the SELECTED tab drops
       its icon (its colour + position already identify it, and the icon stays
       on every inactive tab) and gives the whole width to the word, which is
       then explicitly un-truncatable. Inactive tabs are unchanged. */
    .review-tab.active .tab-icon {
        display: none;
    }
    .review-tab.active .tab-label {
        overflow: visible;
        text-overflow: clip;
        max-width: none;
        flex: 0 0 auto;
    }

    /* Sub-tabs touch-friendly */
    .review-sub-tabs .sub-tab {
        min-height: 44px;
        padding: 10px 14px;
    }

    /* Un-stick the tab chrome on mobile (2026-07-06). On a phone the pinned
       .rc-sticky-bar + .review-sub-tabs ate a large slice of the already-short
       bottom-sheet and, stacked with the shrink transition, read as a jittery
       band that fought the content for space. The user's call: let the tab rows
       scroll away with the content ("scrolling up is fine") — they're one short
       swipe from the top anyway. Desktop keeps the pinned behaviour. Also drop
       the scroll-shrink padding/border so the un-pinned bar can't flash chrome
       mid-scroll, and neutralise the sticky bulk-action bar the same way. */
    .rc-sticky-bar,
    .rc-sticky-bar.rc-scrolled,
    .review-sub-tabs,
    .rc-batch-bar-active {
        position: static;
        z-index: auto;
    }
    .rc-sticky-bar.rc-scrolled {
        padding: 10px 18px 0;
        border-bottom-color: transparent;
        box-shadow: none;
    }

    /* ANTI-VIBRATION (2026-07-30). The rule above neutralised the bar's own
       padding/border/shadow, but `.rc-scrolled .rc-tabrow { margin-bottom: 0 }`
       (see ~1542) was left live — and THAT is what still moved the layout. With
       the bar un-stuck to position:static it sits in the scroll flow, so the
       180ms margin-bottom transition changed the content height above the
       viewport on every frame: scrollTop drifted under the finger, re-firing the
       scroll listener, re-testing the threshold, and the top of the screen
       shuddered. Measured live at 390px: bar 120.7px <-> 110.7px, scrollHeight
       1487 <-> 1477.

       Hold the margin at its resting value in BOTH states and drop the
       transition, so the tab row's box is invariant on a phone no matter what
       the scroll handler does. attachScrollShrink() also bails out early at this
       width; this is the belt-and-braces half — it keeps the geometry frozen
       even if the class is applied by some other path (or lingers from a resize
       across the breakpoint). */
    .rc-tabrow,
    .rc-scrolled .rc-tabrow {
        margin-bottom: 10px;
        transition: none;
    }
    /* The tool row (2026-08-04) is a SECOND animated-margin row inside the same
       sticky bar, so it needs the identical freeze — otherwise it reintroduces
       exactly the vibration this block exists to kill, one row lower. Frozen at
       its own phone resting value (8px). */
    .rc-toolrow,
    .rc-scrolled .rc-toolrow {
        margin-bottom: 8px;
        transition: none;
    }
    /* The tool row (2026-08-04) is a SECOND animated-margin row in the same
       sticky bar, so it needs the identical freeze — otherwise it reintroduces
       exactly the vibration this block exists to kill, just one row lower.
       Frozen at its own resting value (8px, set in the phone block below). */
    .rc-toolrow,
    .rc-scrolled .rc-toolrow {
        margin-bottom: 8px;
        transition: none;
    }

    /* Cards: swipe hint. The swipe JS (setupSwipeGestures) toggles these classes
       on the rendered card, which is `.review-item` — the old selectors only
       matched `.review-card`, so swipe-to-accept/decline fired the action with
       ZERO visual feedback (felt broken/unconfirmed). Include `.review-item` so
       the card follows the finger + tints green(right=accept)/red(left=decline). */
    .review-card,
    .review-item {
        transition: transform 0.2s ease, opacity 0.2s ease;
    }

    .review-card.swiping-right,
    .review-item.swiping-right {
        transform: translateX(40px);
        opacity: 0.7;
        background: rgba(34, 197, 94, 0.1);
    }

    .review-card.swiping-left,
    .review-item.swiping-left {
        transform: translateX(-40px);
        opacity: 0.7;
        background: rgba(239, 68, 68, 0.1);
    }

    /* Empty states responsive */
    .review-empty {
        padding: 32px 16px;
    }

    .review-empty .empty-icon {
        font-size: 36px;
    }
}

/* Tablet responsive adjustments (2026-07-21 full-screen redesign).
   The Review Center is now edge-to-edge full-screen across the whole ≤768px
   range — same as the Create-board / Propose modals — instead of the old
   centered 90%/85vh card that floated on a dimmed backdrop. The ≤768px rule
   above already sets max-width:100% + border-radius:0; restate the height in
   vh/dvh here so the surface fills the viewport rather than sitting short. */
@media (min-width: 481px) and (max-width: 768px) {
    #review-dashboard-modal {
        align-items: stretch;
        padding: 0;
    }

    #review-dashboard-modal .review-modal-content {
        width: 100%;                   /* override .review-modal .modal-content's 96% */
        max-width: 100%;
        min-height: 100vh;
        min-height: 100dvh;
        max-height: 100vh;
        max-height: 100dvh;
        border-radius: 0;
        margin: 0;
    }

    /* Compact two-row header (same reflow as the ≤480px block): brand + full
       tab labels + close on row 1; search/Filters + sync/⋯ on row 2. Without
       this the tablet range kept the desktop single-row strip, which at 481-560
       squeezed everything onto one overflowing line. */
    .rc-tabrow {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        row-gap: 8px;
        column-gap: 8px;
    }
    .rc-tabrow .rdh-title { order: 1; }
    .review-tabs { order: 2; flex: 1 1 auto; min-width: 0; }
    .rc-tabrow .rdh-actions { display: contents; }
    .rc-tabrow #close-review-modal { order: 3; margin-left: 0; flex-shrink: 0; }
    .rc-tabrow .rc-inline-controls {
        order: 4;
        flex: 1 1 auto;
        margin-left: 0;
        justify-content: flex-start;
    }
    /* margin-left:0, matching the ≤480px block: `auto` here pushed sync/⋯ to the
       right edge while the controls sized to their content, leaving a dead hole
       in the middle of row 2. The controls own the slack instead. */
    .rc-tabrow #rdh-sync-btn { order: 5; margin-left: 0; flex-shrink: 0; }
    .rc-tabrow .rdh-overflow { order: 6; flex-shrink: 0; }

    /* Filters popover opens rightward from its now-left-positioned button and is
       capped to the viewport so it can't spill off either edge. */
    #review-dashboard-modal .rc-filters-panel {
        left: 0;
        right: auto;
        max-width: calc(100vw - 24px);
    }
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
    .review-skeleton-tab,
    .review-skeleton-card {
        animation: none;
    }

    #review-dashboard-modal .review-modal-content {
        animation: none;
    }

    .review-card {
        transition: none;
    }

    /* Suppress the continuously-looping, attention-grabbing animations and
       the tab-crossfade for users who prefer reduced motion. These are
       exactly the effects that motion-sensitivity guidance targets. */
    .proposal-deadline-badge.urgency-high,
    .rc-timer-amber,
    .rc-timer-critical,
    .rc-tab-enter,
    .rc-tab-exit,
    .highlight-pulse {
        animation: none !important;
    }
}

/* ============================================
   VOTING PROGRESS IN PROPOSAL META
   ============================================ */
.proposal-vote-progress {
    font-weight: 600;
    color: var(--teal-600, #0d9488);
}

/* Prominent deadline badge in proposal meta */
.proposal-deadline-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 4px;
    font-size: var(--rc-font-caption, 11px);
    font-weight: 600;
    background: rgba(245, 158, 11, 0.1);
    /* Darker amber text for legibility — see urgency-tomorrow comment. */
    color: #b45309;
    border: 1px solid rgba(245, 158, 11, 0.2);
}

.proposal-deadline-badge.urgency-high {
    background: rgba(239, 68, 68, 0.1);
    color: var(--rc-status-busy);
    border-color: rgba(239, 68, 68, 0.25);
    animation: deadlinePulse 2s ease-in-out infinite;
}

.proposal-deadline-badge.urgency-medium {
    background: rgba(245, 158, 11, 0.1);
    /* Amber-700 strong variant. */
    color: #d97706;
    border-color: rgba(245, 158, 11, 0.25);
}

.proposal-deadline-badge.urgency-low {
    background: rgba(34, 197, 94, 0.08);
    color: var(--rc-status-working);
    border-color: rgba(34, 197, 94, 0.15);
}

@keyframes deadlinePulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.7; }
}

body.dark-mode .proposal-deadline-badge {
    background: rgba(245, 158, 11, 0.15);
    color: #fcd34d;
    border-color: rgba(245, 158, 11, 0.3);
}

body.dark-mode .proposal-deadline-badge.urgency-high {
    background: rgba(239, 68, 68, 0.15);
    color: #f87171;
    border-color: rgba(239, 68, 68, 0.3);
}

body.dark-mode .proposal-deadline-badge.urgency-low {
    background: rgba(34, 197, 94, 0.12);
    color: #86efac;
    border-color: rgba(34, 197, 94, 0.2);
}

body.dark-mode .proposal-vote-progress {
    color: #5eead4;
}

/* Participant voting status row */
.proposal-voters-row {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    padding: 4px 0;
    font-size: var(--rc-font-caption, 11px);
}

.proposal-voters-row .voter-label {
    color: var(--text-secondary, #64748b);
    font-weight: 500;
}

.voter-chip {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 1px 6px;
    border-radius: 10px;
    font-size: 10px;
    font-weight: 500;
}

.voter-chip.voted {
    background: rgba(34, 197, 94, 0.1);
    color: #16a34a;
}

.voter-chip.not-voted {
    background: rgba(100, 116, 139, 0.1);
    color: #64748b;
}

body.dark-mode .voter-chip.voted {
    background: rgba(34, 197, 94, 0.15);
    color: #86efac;
}

body.dark-mode .voter-chip.not-voted {
    background: rgba(100, 116, 139, 0.15);
    color: #94a3b8;
}

body.dark-mode .proposal-voters-row .voter-label {
    color: #94a3b8;
}

/* ============================================
   SUGGEST TIME INLINE PICKER
   ============================================ */
.suggest-time-inline {
    margin-top: 8px;
    animation: slideDown 0.2s ease-out;
}

.suggest-time-row {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
}

.suggest-time-row input[type="date"],
.suggest-time-row input[type="time"] {
    padding: 5px 8px;
    font-size: 12px;
    border: 1px solid var(--slate-300, #cbd5e1);
    border-radius: 6px;
    background: var(--review-card-bg, #fff);
    color: var(--text-primary, #1e293b);
}

.suggest-time-row .btn {
    padding: 5px 10px;
    font-size: 11px;
}

body.dark-mode .suggest-time-row input[type="date"],
body.dark-mode .suggest-time-row input[type="time"] {
    background: var(--slate-700);
    border-color: var(--slate-600);
    color: var(--slate-100);
}

/* ============================================
   HIGHLIGHT PULSE (View Details navigation)
   ============================================ */
.proposal-item.highlight-pulse {
    animation: highlightPulse 1.5s ease-out;
}

@keyframes highlightPulse {
    0% { box-shadow: 0 0 0 0 rgba(20, 184, 166, 0.4); }
    30% { box-shadow: 0 0 0 6px rgba(20, 184, 166, 0.2); }
    100% { box-shadow: 0 0 0 0 rgba(20, 184, 166, 0); }
}

/* ============================================
   REVIEW CARD DESCRIPTION (collapsible)
   ============================================ */
.review-card-description {
    font-size: var(--rc-font-caption, 11px);
    color: #64748b;
    padding: 4px 0;
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
}

.review-card-description i {
    margin-right: 4px;
    font-size: 10px;
}

body.dark-mode .review-card-description {
    color: #94a3b8;
}

/* P2.2 — "Why this shift was assigned to me" line. Single source of vocabulary
   is QuotaAssignmentService.formatSelectionReason. Visual weight matches the
   description line so it reads as supporting context, not a new section. */
.review-card-assignment-reason {
    font-size: var(--rc-font-caption, 11px);
    color: var(--text-secondary, #64748b);
    padding: 4px 0;
    line-height: 1.4;
    display: flex;
    align-items: center;
    gap: 4px;
}
.review-card-assignment-reason i {
    margin-right: 2px;
    font-size: 10px;
    opacity: 0.75;
}
body.dark-mode .review-card-assignment-reason {
    color: var(--text-secondary, #94a3b8);
}

/* ============================================
   REVIEW CARD LOCATION (inline in meta line)
   ============================================ */
.review-card-location {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    color: #64748b;
    font-size: var(--rc-font-caption, 11px);
}

.review-card-location i {
    color: #ef4444;
    font-size: 10px;
}

body.dark-mode .review-card-location {
    color: #94a3b8;
}

/* ============================================
   AUTO-ACCEPT BADGE
   ============================================ */
.auto-accept-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: var(--rc-font-tiny, 10px);
    font-weight: 600;
    white-space: nowrap;
}

.auto-accept-badge i {
    font-size: 9px;
}

.auto-accept-badge.urgency-high {
    background: rgba(239, 68, 68, 0.12);
    color: #ef4444;
}

.auto-accept-badge.urgency-medium {
    background: rgba(249, 115, 22, 0.12);
    color: #f97316;
}

.auto-accept-badge.urgency-low {
    background: rgba(34, 197, 94, 0.12);
    color: #22c55e;
}

body.dark-mode .auto-accept-badge.urgency-high {
    background: rgba(239, 68, 68, 0.2);
}

body.dark-mode .auto-accept-badge.urgency-medium {
    background: rgba(249, 115, 22, 0.2);
}

body.dark-mode .auto-accept-badge.urgency-low {
    background: rgba(34, 197, 94, 0.2);
}

/* ============================================
   PROPOSAL VOTING CLOSED BADGE
   ============================================ */
.proposal-voting-closed-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: var(--rc-font-tiny, 10px);
    font-weight: 600;
    background: rgba(100, 116, 139, 0.12);
    color: #64748b;
    white-space: nowrap;
}

.proposal-voting-closed-badge i {
    font-size: 9px;
}

body.dark-mode .proposal-voting-closed-badge {
    background: rgba(148, 163, 184, 0.15);
    color: #94a3b8;
}

/* ============================================
   PROPOSAL EXPIRED BADGE & STATE
   ============================================ */
.proposal-expired-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: var(--rc-font-tiny, 10px);
    font-weight: 600;
    background: rgba(239, 68, 68, 0.1);
    color: var(--rc-status-busy);
    white-space: nowrap;
}

.proposal-expired-badge i {
    font-size: 9px;
}

/* ⭐ ONE STATUS CHIP (2026-08-06). The single treatment that says what state a
   proposal is in. Replaces the expired PILL + coloured DEADLINE + dot-and-label
   row, which all fired together and read as three separate problems. */
.rc-status-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: var(--rc-font-tiny, 10px);
    font-weight: 600;
    white-space: nowrap;
}
.rc-status-chip i { font-size: 9px; }
.rc-status-chip--expired {
    background: rgba(239, 68, 68, 0.1);
    color: var(--rc-status-busy);
}
.rc-status-chip--closed {
    background: rgba(100, 116, 139, 0.12);
    color: var(--slate-600);
}
body.dark-mode .rc-status-chip--expired { background: rgba(239, 68, 68, 0.15); color: #f87171; }
body.dark-mode .rc-status-chip--closed  { background: rgba(148, 163, 184, 0.15); color: var(--slate-300); }

/* Once a proposal has ended, the deadline is a DATE, not an alarm. Urgency
   colour is a nudge to act; there is nothing left to act on. */
.proposal-deadline-area.urgency-past,
.proposal-deadline-area.urgency-past .proposal-deadline-value {
    color: var(--slate-500);
    font-weight: 500;
}
body.dark-mode .proposal-deadline-area.urgency-past,
body.dark-mode .proposal-deadline-area.urgency-past .proposal-deadline-value {
    color: var(--slate-400);
}

.proposal-expired {
    position: relative;
}

/* The card was dimmed to 0.65 AND its times to 0.5 — compounding to ~0.33, so
   the one thing a user still needs from an expired proposal (WHEN was it for)
   was the least readable text on screen. The status chip already says it has
   ended; the content should stay legible. Interaction stays disabled. */
.proposal-expired .proposal-options-section,
.proposal-expired .my-proposal-times {
    pointer-events: none;
}

body.dark-mode .proposal-expired-badge {
    background: rgba(239, 68, 68, 0.15);
    color: #f87171;
}

/* ============================================
   PROPOSAL CREATED TIME
   ============================================ */
.proposal-created-time {
    color: #94a3b8;
    font-size: var(--rc-font-caption, 11px);
    font-style: italic;
}

body.dark-mode .proposal-created-time {
    color: #64748b;
}

/* ============================================
   TIME-OFF REQUEST CARDS
   ============================================ */
/* Time-off cards now render as <li class="timeoff-card review-item">, so the
   .review-item chassis (bg / border / radius / padding / hover lift) governs
   the shell uniformly with the other review cards. Only the list spacing is
   timeoff-specific here. */
.timeoff-card {
    margin-bottom: 8px;
}

/* Time-off header row */
.timeoff-header {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.timeoff-type-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 10px;
    border-radius: var(--rc-radius-pill, 12px);
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 600;
    background: color-mix(in srgb, var(--timeoff-color) 12%, transparent);
    color: var(--timeoff-color);
    white-space: nowrap;
}

.timeoff-type-badge i {
    font-size: 11px;
}

body.dark-mode .timeoff-type-badge {
    background: color-mix(in srgb, var(--timeoff-color) 20%, transparent);
}

.timeoff-member-name {
    font-size: var(--rc-font-body, 13px);
    font-weight: 600;
    color: #1e293b;
    flex: 1;
}

body.dark-mode .timeoff-member-name {
    color: #f1f5f9;
}

.timeoff-actions {
    display: flex;
    gap: 6px;
    margin-left: auto;
}

/* .timeoff-actions .btn sizing now inherits from .review-panel .btn reset */

/* Time-off meta line */
.timeoff-meta-line {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 6px;
    font-size: var(--rc-font-caption, 11px);
    color: #64748b;
}

.timeoff-meta-line > span::before {
    content: '·';
    margin-right: 8px;
    color: #cbd5e1;
}

.timeoff-meta-line > span:first-child::before {
    display: none;
}

body.dark-mode .timeoff-meta-line {
    color: #94a3b8;
}

body.dark-mode .timeoff-meta-line > span::before {
    color: #475569;
}

/* Time-off coverage warning */
.timeoff-coverage {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 6px;
    padding: 6px 10px;
    background: rgba(249, 115, 22, 0.08);
    border-radius: 6px;
    font-size: var(--rc-font-caption, 11px);
    color: #f97316;
}

.timeoff-coverage i {
    font-size: 11px;
    flex-shrink: 0;
}

body.dark-mode .timeoff-coverage {
    background: rgba(249, 115, 22, 0.15);
    color: #fb923c;
}

/* Time-off reject reason panel */
.timeoff-reject-reason {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid #e2e8f0;
}

.timeoff-reject-reason .review-note-input {
    flex: 1;
}

.timeoff-reject-reason .btn {
    padding: 4px 12px;
    font-size: var(--rc-font-secondary, 12px);
    white-space: nowrap;
}

body.dark-mode .timeoff-reject-reason {
    border-top-color: #334155;
}

/* ============================================
   OUTGOING AUTHORITY BADGE
   ============================================ */
.outgoing-authority-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: var(--rc-font-tiny, 10px);
    font-weight: 600;
    background: rgba(59, 130, 246, 0.1);
    color: #3b82f6;
    white-space: nowrap;
}

.outgoing-authority-badge i {
    font-size: 9px;
}

body.dark-mode .outgoing-authority-badge {
    background: rgba(59, 130, 246, 0.2);
    color: #60a5fa;
}

/* ============================================
   UX IMPROVEMENTS: TAB DIMMING
   ============================================ */
.review-tab.tab-empty {
    opacity: 0.45;
    filter: grayscale(40%);
    transition: opacity 0.2s ease, filter 0.2s ease;
}
.review-tab.tab-empty:hover {
    opacity: 0.75;
    filter: none;
}

/* ============================================
   SEARCH / FILTER / SORT BAR
   ============================================ */
.rc-search-filter-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
    flex-wrap: wrap;
    /* Animatable collapse for the compact state (see .rc-scrolled rules). */
    overflow: hidden;
    transition: max-height 0.2s ease, opacity 0.15s ease, margin-bottom 0.2s ease;
}

/* ---- Compact-state search toggle (Phase D) -------------------------------
   At the top of the list the full search row is shown and this toggle is
   hidden. Once the sticky bar shrinks (.rc-scrolled) the row collapses and the
   toggle takes its place — a single icon that expands the row inline on click.
   The toggle sits in the sticky bar's top-right, aligned with the tab row. */
.rc-search-toggle {
    display: none;               /* shown only in compact state */
    position: absolute;
    top: 6px;
    right: 16px;
    width: 30px;
    height: 30px;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--slate-200, #e2e8f0);
    border-radius: var(--radius-full, 9999px);
    background: var(--surface-primary, #fff);
    color: var(--slate-500, #64748b);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.rc-search-toggle:hover {
    color: var(--slate-700, #334155);
    border-color: var(--slate-300, #cbd5e1);
}
.rc-search-toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--review-focus-ring, rgba(20, 184, 166, 0.4));
}
.rc-search-toggle .rc-filter-dot {
    position: absolute;
    top: 4px;
    right: 4px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--primary-500, #14b8a6);
    box-shadow: 0 0 0 2px var(--surface-primary, #fff);
}
.rc-search-toggle.rc-filter-on {
    color: var(--primary-600, #0d9488);
    border-color: color-mix(in srgb, var(--primary-500, #14b8a6) 35%, transparent);
}

/* ---- Mobile "Filters" toggle (2026-06-29 de-intimidation) ----------------
   On a phone the Sort + Date dropdowns (power-user controls defaulting to
   Urgency / All dates) tuck behind this toggle so the at-rest surface is just
   search → content. On wider screens the toggle is hidden and the dropdowns
   show inline as before, so this is mobile-only progressive disclosure.
   DESKTOP DEFAULT: toggle hidden, dropdowns always visible. */
.rc-filters-toggle { display: none; }
.rc-filter-dropdowns { display: contents; }   /* dropdowns flow in the bar as before on desktop */

/* COMPACT: collapse the full search row and surface the toggle. */
.rc-scrolled .rc-search-filter-bar {
    max-height: 0;
    opacity: 0;
    margin-bottom: 0;
    pointer-events: none;
}
.rc-scrolled .rc-search-toggle {
    display: inline-flex;
}
/* COMPACT + EXPANDED: user tapped the toggle — reveal the row inline again. */
.rc-scrolled.rc-search-expanded .rc-search-filter-bar {
    max-height: 220px;
    opacity: 1;
    margin-bottom: 10px;
    pointer-events: auto;
}
.rc-scrolled.rc-search-expanded .rc-search-toggle {
    color: var(--primary-600, #0d9488);
    border-color: color-mix(in srgb, var(--primary-500, #14b8a6) 35%, transparent);
    background: color-mix(in srgb, var(--primary-500, #14b8a6) 8%, #fff);
}

body.dark-mode .rc-search-toggle {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
    color: var(--slate-400, #94a3b8);
}
body.dark-mode .rc-search-toggle:hover {
    color: var(--slate-200, #e2e8f0);
    border-color: var(--slate-600, #475569);
}
body.dark-mode .rc-search-toggle .rc-filter-dot {
    box-shadow: 0 0 0 2px var(--slate-800, #1e293b);
}
.rc-search-input-wrap {
    position: relative;
    flex: 1;
    min-width: 160px;
}
.rc-search-icon {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-tertiary, #94a3b8);
    font-size: 12px;
    pointer-events: none;
}
.rc-search-input {
    width: 100%;
    padding: 7px 30px 7px 30px;
    border: 1px solid var(--border-color, #e2e8f0);
    border-radius: 8px;
    background: var(--bg-secondary, #f8fafc);
    font-size: 13px;
    color: var(--text-primary, #1e293b);
    outline: none;
    transition: border-color 0.15s;
}
.rc-search-input:focus {
    border-color: var(--primary-color, #3b82f6);
    box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.15);
}
.rc-search-clear {
    position: absolute;
    right: 6px;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: none;
    color: var(--text-tertiary, #94a3b8);
    cursor: pointer;
    padding: 4px;
    font-size: 12px;
}
.rc-search-clear:hover {
    color: var(--text-primary, #1e293b);
}
/* Custom dropdown that mirrors .boards-dropdown chrome
   (see css/quota-assignment.css:144). Replaces the previous native
   .rc-sort-select / .rc-date-filter <select> elements. */
.rc-dropdown {
    position: relative;
    display: inline-block;
}

.rc-dropdown-trigger {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    border: 1px solid var(--border-color, #e2e8f0);
    border-radius: 8px;
    background: var(--bg-secondary, #f8fafc);
    font-size: 12px;
    color: var(--text-primary, #1e293b);
    cursor: pointer;
    font-family: inherit;
}

.rc-dropdown-trigger:hover {
    border-color: var(--slate-300, #cbd5e1);
}

.rc-dropdown-trigger:focus-visible {
    outline: 2px solid var(--review-accent, var(--primary-500, #14b8a6));
    outline-offset: 2px;
}

.rc-dropdown-trigger[aria-expanded="true"] {
    border-color: var(--review-accent, var(--primary-500, #14b8a6));
}

.rc-dropdown-chevron {
    font-size: 10px;
    color: var(--slate-500, #64748b);
    transition: transform 0.15s ease;
}

.rc-dropdown-trigger[aria-expanded="true"] .rc-dropdown-chevron {
    transform: rotate(180deg);
}

.rc-dropdown-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    min-width: 180px;
    background: var(--surface-primary, #fff);
    border: 1px solid var(--slate-200, #e2e8f0);
    border-radius: 10px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
    z-index: calc(var(--z-dropdown) + 40);
    padding: 4px 0;
    display: flex;
    flex-direction: column;
}

.rc-dropdown-menu[hidden] {
    display: none;
}

.rc-dropdown-option {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px;
    border: none;
    background: none;
    width: 100%;
    text-align: left;
    font-family: inherit;
    font-size: 13px;
    color: var(--slate-700, #334155);
    cursor: pointer;
    transition: background 0.12s ease;
}

.rc-dropdown-option:hover,
.rc-dropdown-option:focus-visible {
    background: var(--slate-50, #f8fafc);
    outline: none;
}

.rc-dropdown-option.active {
    color: var(--primary-700, #0f766e);
    font-weight: 600;
}

.rc-dropdown-tick {
    margin-left: auto;
    font-size: 10px;
    color: var(--review-accent, var(--primary-500, #14b8a6));
}

body.dark-mode .rc-search-input {
    background: var(--dark-bg-secondary, #1e293b);
    border-color: var(--dark-border, #334155);
    color: var(--dark-text, #e2e8f0);
}

body.dark-mode .rc-dropdown-trigger {
    background: var(--dark-bg-secondary, #1e293b);
    border-color: var(--dark-border, #334155);
    color: var(--dark-text, #e2e8f0);
}

body.dark-mode .rc-dropdown-menu {
    background: var(--surface-secondary, #1e293b);
    border-color: var(--slate-700, #334155);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}

body.dark-mode .rc-dropdown-option {
    color: var(--slate-200, #e2e8f0);
}

body.dark-mode .rc-dropdown-option:hover,
body.dark-mode .rc-dropdown-option:focus-visible {
    background: rgba(255, 255, 255, 0.05);
}

/* ============================================================================
   TAB-ROW INLINE CONTROLS (2026-07-11 chrome slim-down)
   Search + all filters moved out of their own full-width band and onto the
   RIGHT of the tab row. A magnifier expands to an inline input; a single
   "Filters ▾" popover holds the calendar filter + sort + date range. This
   reclaims a whole vertical band and consolidates every list filter into one
   affordance. Overrides the old absolute-positioned .rc-search-toggle.
   ============================================================================ */
.rc-inline-controls {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;               /* sit opposite the tabs on the same row */
    flex-shrink: 0;
}
/* When the triage strip is present it already took margin-left:auto; keep the
   controls tight to it rather than pushing them off-row. */
.rc-triage-strip + .rc-inline-controls { margin-left: 8px; }

/* ---- Inline search (collapses to an icon) -------------------------------- */
.rc-search-inline {
    display: inline-flex;
    align-items: center;
    position: relative;
}
/* The magnifier toggle. Reset the legacy absolute positioning that placed it
   in the sticky bar's top-right corner — it's an inline button now. */
.rc-search-toggle {
    display: inline-flex;
    position: static;
    top: auto;
    right: auto;
    width: 32px;
    height: 32px;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid var(--slate-200, #e2e8f0);
    border-radius: var(--radius-full, 9999px);
    background: var(--surface-primary, #fff);
    color: var(--slate-500, #64748b);
    cursor: pointer;
    flex-shrink: 0;
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.rc-search-toggle:hover {
    color: var(--slate-700, #334155);
    border-color: var(--slate-300, #cbd5e1);
}
.rc-search-toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--review-focus-ring, rgba(20, 184, 166, 0.4));
}
.rc-search-toggle .rc-filter-dot {
    position: absolute;
    top: 2px;
    right: 2px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--primary-500, #14b8a6);
    box-shadow: 0 0 0 2px var(--surface-primary, #fff);
}
.rc-search-toggle.rc-filter-on {
    color: var(--primary-600, #0d9488);
    border-color: color-mix(in srgb, var(--primary-500, #14b8a6) 35%, transparent);
}
/* The input is 0-width at rest and animates open when .rc-search-open is set.
 *
 * AN INVISIBLE 160px CLICK-TRAP (2026-08-11 button sweep).
 *
 * An EARLIER `.rc-search-input-wrap` rule (see the toolbar block above) sets
 * `flex: 1; min-width: 160px`. min-width is resolved AFTER max-width in the
 * CSS box algorithm, so it wins outright: the collapsed wrapper measured 160px
 * wide with max-width:0 and opacity:0 still applied. The result was a
 * fully-transparent, 160px-wide, still-hit-testable strip sitting permanently
 * in the toolbar, and a search input that measured 220px while the toggle
 * reported aria-expanded="false".
 *
 * Symptom as reported: the magnifier button "does nothing". It was toggling
 * the class correctly and focusing the input each time — the input simply
 * never hid, so pressing it twice looked identical to pressing it never.
 *
 * Reset min-width and flex here, where the collapse intent lives, rather than
 * editing the toolbar rule (which is load-bearing for the EXPANDED layout and
 * for the mobile override at ~13160). `flex-basis: 0` stops flex:1 re-inflating
 * the box once min-width no longer floors it. */
.rc-search-input-wrap {
    position: relative;
    overflow: hidden;
    max-width: 0;
    min-width: 0;
    flex: 0 1 0;
    opacity: 0;
    margin-left: 0;
    /* Not hit-testable while collapsed: an opacity:0 box still takes clicks. */
    pointer-events: none;
    transition: max-width 0.2s ease, opacity 0.15s ease, margin-left 0.2s ease;
}
.rc-search-inline.rc-search-open .rc-search-input-wrap {
    max-width: 240px;
    min-width: 160px;
    flex: 1 1 auto;
    opacity: 1;
    margin-left: 6px;
    pointer-events: auto;
}
.rc-search-input {
    width: 220px;
    max-width: 46vw;
    padding: 7px 28px 7px 12px;
    border: 1px solid var(--border-color, #e2e8f0);
    border-radius: var(--radius-full, 9999px);
    background: var(--bg-secondary, #f8fafc);
    font-size: 13px;
    color: var(--text-primary, #1e293b);
    outline: none;
    transition: border-color 0.15s;
}
.rc-search-input:focus {
    border-color: var(--primary-color, #3b82f6);
    box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.15);
}

/* ---- "Filters ▾" popover ------------------------------------------------- */
.rc-filters-menu { position: relative; display: inline-block; }
.rc-filters-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    position: relative;
    padding: 6px 10px;
    border: 1px solid var(--slate-200, #e2e8f0);
    border-radius: var(--radius-full, 9999px);
    background: var(--surface-primary, #fff);
    color: var(--slate-600, #475569);
    font-size: 12px;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
    transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.rc-filters-btn:hover { border-color: var(--slate-300, #cbd5e1); color: var(--slate-800, #1e293b); }
.rc-filters-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--review-focus-ring, rgba(20, 184, 166, 0.4));
}
.rc-filters-btn[aria-expanded="true"] { border-color: var(--review-accent, var(--primary-500, #14b8a6)); }
.rc-filters-btn.rc-filter-on { color: var(--primary-600, #0d9488); border-color: color-mix(in srgb, var(--primary-500, #14b8a6) 35%, transparent); }
.rc-filters-btn-chevron { font-size: 10px; transition: transform 0.15s ease; }
.rc-filters-btn[aria-expanded="true"] .rc-filters-btn-chevron { transform: rotate(180deg); }
.rc-filters-btn .rc-filter-dot {
    position: absolute; top: 3px; right: 5px;
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--primary-500, #14b8a6);
    box-shadow: 0 0 0 2px var(--surface-primary, #fff);
}
/* ════════════════════════════════════════════════════════════════════════
   FILTERS POPOVER (rebuilt 2026-08-29, user: "complete the filters ui to be
   high quality and consistent with my ui")
   ────────────────────────────────────────────────────────────────────────
   What was wrong, measured on the real render:
     • The three category icons rendered BLACK. Their colour rules were all
       scoped to `.review-dashboard-header`, a wrapper this renderer stopped
       emitting — so every per-category treatment (work=blue, personal=pink,
       all=teal) was dead CSS the popover never inherited.
     • The active segment came out BLUE against a TEAL button and TEAL count
       badge: two accent families in one control.
     • "Sort: Urgency" sat under a section label reading "SORT".
     • The button promised "2 active" with no way to get back to none.
     • 220px min-width + 12px padding read as a utility menu, not as part of
       the same design language as the rest of the Review Center's surfaces.

   The panel now matches the app's other floating surfaces (.rdh-overflow-menu,
   .rc-dropdown-menu): same radius family, same elevation, same 1px slate
   hairline, and ONE accent — teal — for every "this is chosen" state.
   ════════════════════════════════════════════════════════════════════════ */
.rc-filters-panel {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 30;
    /* Wide enough that "This month" and "Personal" never wrap, which is what
       made the old panel feel cramped at 220px. */
    min-width: 268px;
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    background: var(--surface-primary, #fff);
    border: 1px solid var(--slate-200, #e2e8f0);
    border-radius: 14px;
    box-shadow: 0 12px 32px rgba(15, 23, 42, 0.14);
}
.rc-filters-panel[hidden] { display: none; }

/* Head: what this is, and the way out. */
.rc-filters-panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 8px 8px;
    margin-bottom: 2px;
    border-bottom: 1px solid var(--slate-100, #f1f5f9);
}
.rc-filters-panel-title {
    font-size: 12px;
    font-weight: 700;
    color: var(--text-primary, #0f172a);
    letter-spacing: -0.01em;
}
/* Quiet until wanted: a text button, not a competing filled control. Teal on
   hover so it belongs to the same accent as everything else in here. */
.rc-filters-clear {
    border: none;
    background: none;
    padding: 3px 7px;
    margin: -3px -4px -3px 0;
    border-radius: 6px;
    font: inherit;
    font-size: 11px;
    font-weight: 600;
    color: var(--slate-500, #64748b);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}
.rc-filters-clear:hover {
    background: rgba(20, 184, 166, 0.1);
    color: var(--primary-600, #0d9488);
}
.rc-filters-clear:focus-visible {
    outline: 2px solid var(--primary-500, #14b8a6);
    outline-offset: 1px;
}

.rc-filters-section {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 6px 8px 8px;
}
.rc-filters-section + .rc-filters-section { padding-top: 2px; }
/* CONTRAST, MEASURED (2026-08-29). At --slate-400 on white this label came out
   at 2.56:1 — below 4.5:1, and it is 10px uppercase, i.e. the hardest text in
   the panel to read. It is a real label naming the control beneath it, not
   decoration, so it gets a legible tone. --slate-500 lands at 4.76:1. */
.rc-filters-section-label {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--slate-500, #64748b);
}

/* ── Calendar segmented control ─────────────────────────────────────────
   A real segmented track: one recessed rail, three equal segments, the
   chosen one lifting out as a white card. Same idiom as the visibility
   track on the privacy rows, so "pick one of N" looks the same everywhere. */
.rc-filters-panel .rdh-filters {
    display: flex;
    align-items: center;
    gap: 2px;
    padding: 3px;
    background: var(--slate-100, #f1f5f9);
    border-radius: var(--radius-full, 9999px);
}
.rc-filters-panel .rdh-filters .filter-tab {
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
    gap: 5px;
    padding: 6px 8px;
    font-size: 12px;
    font-weight: 500;
    /* --slate-500 measured 4.34:1 against the slate-100 RAIL (not against the
       panel) — the recessed track darkens the background, so the unselected
       segments need a step darker than they would on white. --slate-600 clears
       4.5:1 on the rail. */
    color: var(--slate-600, #475569);
    background: transparent;
    border: 1px solid transparent;  /* reserve the active ring's 1px */
    border-radius: var(--radius-full, 9999px);
    white-space: nowrap;
}
.rc-filters-panel .rdh-filters .filter-tab i {
    font-size: 10.5px;
    /* Muted at rest so the row reads as one control, not three icons. */
    color: var(--slate-400, #94a3b8);
    transition: color 0.15s ease;
}
.rc-filters-panel .rdh-filters .filter-tab:hover:not(.active) {
    color: var(--slate-700, #334155);
    background: rgba(255, 255, 255, 0.72);
}
.rc-filters-panel .rdh-filters .filter-tab:hover:not(.active) i {
    color: var(--slate-500, #64748b);
}
/* ONE ACCENT. The chosen segment is a lifted white card with teal type — the
   same "selected" vocabulary as the staged visibility chip and the Clear all
   hover. The old per-category blue/pink actives are deliberately NOT revived
   here: three different active colours inside a control whose own button is
   teal is what made this popover feel unfinished. Category identity still
   lives in the ICON, which is the part that means "work" or "personal". */
.rc-filters-panel .rdh-filters .filter-tab.active {
    color: var(--primary-700, #0f766e);
    background: var(--surface-primary, #fff);
    border-color: rgba(20, 184, 166, 0.28);
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
    font-weight: 600;
}
.rc-filters-panel .rdh-filters .filter-tab.active i {
    color: var(--primary-600, #0d9488);
}
.rc-filters-panel .rdh-filters .filter-tab:focus-visible {
    outline: 2px solid var(--primary-500, #14b8a6);
    outline-offset: 1px;
}

/* ── Sort / Date dropdowns ──────────────────────────────────────────────
   Full-width triggers so the two rows align into a column, and the open menu
   covers exactly the trigger it belongs to. */
.rc-filters-panel .rc-dropdown { display: block; }
.rc-filters-panel .rc-dropdown-trigger {
    width: 100%;
    justify-content: space-between;
    padding: 8px 10px;
    border-radius: 9px;
    font-size: 12px;
    font-weight: 500;
    background: var(--surface-primary, #fff);
    border-color: var(--slate-200, #e2e8f0);
}
.rc-filters-panel .rc-dropdown-trigger:hover {
    border-color: var(--primary-300, #5eead4);
    background: rgba(20, 184, 166, 0.04);
}
.rc-filters-panel .rc-dropdown-menu {
    left: 0;
    right: auto;
    width: 100%;
    border-radius: 10px;
}

body.dark-mode .rc-filters-panel {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
}
body.dark-mode .rc-filters-panel-head { border-bottom-color: var(--slate-700, #334155); }
body.dark-mode .rc-filters-panel-title { color: var(--slate-100, #f1f5f9); }
/* MEASURED on the dark panel (#1e293b): --slate-400 gives only 3.07:1 for the
   section labels and Clear all, and --slate-400 on the darkened rail gives a
   badly failing 1.93:1 for the unselected segments. Dark surfaces need LIGHTER
   type than the light-mode mirror, not the same step — stepping to --slate-300
   clears 4.5:1 in all three places. */
body.dark-mode .rc-filters-section-label { color: var(--slate-300, #cbd5e1); }
body.dark-mode .rc-filters-clear { color: var(--slate-300, #cbd5e1); }
body.dark-mode .rc-filters-clear:hover {
    background: rgba(45, 212, 191, 0.16);
    color: var(--primary-300, #5eead4);
}
body.dark-mode .rc-filters-panel .rdh-filters { background: rgba(15, 23, 42, 0.55); }
body.dark-mode .rc-filters-panel .rdh-filters .filter-tab { color: var(--slate-300, #cbd5e1); }
body.dark-mode .rc-filters-panel .rdh-filters .filter-tab i { color: var(--slate-400, #94a3b8); }
body.dark-mode .rc-filters-panel .rdh-filters .filter-tab:hover:not(.active) {
    background: rgba(148, 163, 184, 0.12);
    color: var(--slate-200, #e2e8f0);
}
body.dark-mode .rc-filters-panel .rdh-filters .filter-tab.active {
    background: var(--slate-700, #334155);
    border-color: rgba(45, 212, 191, 0.35);
    color: var(--primary-300, #5eead4);
}
body.dark-mode .rc-filters-panel .rdh-filters .filter-tab.active i { color: var(--primary-300, #5eead4); }
body.dark-mode .rc-filters-panel .rc-dropdown-trigger {
    background: var(--slate-900, #0f172a);
    border-color: var(--slate-600, #475569);
    color: var(--slate-100, #f1f5f9);
}
body.dark-mode .rc-filters-panel .rc-dropdown-trigger:hover {
    border-color: var(--primary-500, #14b8a6);
    background: rgba(20, 184, 166, 0.1);
}

/* TOUCH TARGETS (2026-08-29). Measured at 390px the segments were 27.3px tall
   and the dropdown triggers 31.3px — both well under the 44px this codebase
   uses for coarse pointers elsewhere (see the .incoming-source-split note).
   Gate on the POINTER, not the width: a narrow desktop window still has a
   mouse and does not need the extra height, while a large tablet does. */
@media (pointer: coarse) {
    .rc-filters-panel { min-width: 288px; }
    .rc-filters-panel .rdh-filters .filter-tab {
        min-height: 40px;      /* + the rail's 3px padding top and bottom = 46 */
        font-size: 12.5px;
    }
    .rc-filters-panel .rc-dropdown-trigger {
        min-height: 44px;
        font-size: 13px;
    }
    .rc-filters-panel .rc-dropdown-option { min-height: 44px; }
    /* Clear all is a small text button; give it a real hit box without
       changing how it looks. */
    .rc-filters-clear {
        min-height: 32px;
        padding-left: 10px;
        padding-right: 10px;
    }
}

body.dark-mode .rc-search-toggle,
body.dark-mode .rc-filters-btn {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
    color: var(--slate-400, #94a3b8);
}
body.dark-mode .rc-search-toggle:hover,
body.dark-mode .rc-filters-btn:hover {
    color: var(--slate-200, #e2e8f0);
    border-color: var(--slate-600, #475569);
}
body.dark-mode .rc-filters-panel {
    background: var(--surface-secondary, #1e293b);
    border-color: var(--slate-700, #334155);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
}
body.dark-mode .rc-filters-panel .rdh-filters { background: var(--slate-800, #1e293b); }

/* Narrow screens: cap the expanded search so it never pushes the tabs off-row;
   the tab row already wraps (flex-wrap) so controls drop below the tabs. */
@media (max-width: 560px) {
    .rc-inline-controls { margin-left: auto; }
    .rc-search-inline.rc-search-open .rc-search-input-wrap { max-width: 180px; }
    .rc-filters-panel { right: 0; left: auto; }
}

/* ============================================
   SCHEDULED TAB PROGRESS BAR
   ============================================ */
.rc-scheduled-progress {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 0;
    margin-bottom: 6px;
}
/* Phase D: the whole panel scrolls now (no pinned fixed-height frame), so the
   list no longer "jumps inside a frame" when the bar first appears — it just
   pushes content down like any normal flow insert. So the empty placeholder no
   longer needs to reserve the populated bar's full height; collapse it to zero
   to reclaim ~28px above the first card. The real bar (rendered once the user
   has actioned something) carries its own height. */
.rc-scheduled-progress--empty {
    height: 0;
    margin-bottom: 0;
    padding: 0;
}
.rc-progress-text {
    font-size: 12px;
    color: var(--text-secondary, #64748b);
    white-space: nowrap;
}
.rc-progress-track {
    flex: 1;
    height: 6px;
    background: var(--bg-tertiary, #e2e8f0);
    border-radius: 3px;
    overflow: hidden;
}
.rc-progress-fill {
    height: 100%;
    background: linear-gradient(90deg, #22c55e, #16a34a);
    border-radius: 3px;
    transition: width 0.4s ease;
}

body.dark-mode .rc-progress-track {
    background: #1e293b;
}
body.dark-mode .rc-progress-text {
    color: #94a3b8;
}

/* ============================================
   FIRST-TIME GUIDANCE BANNER
   ============================================ */
/* Collapsed-by-default <details> banner. The summary is a single compact
   line; the body only renders when expanded, so first-visit guidance no
   longer steals ~110px of the card queue. */
.rc-guidance-banner {
    margin-bottom: 10px;
    background: linear-gradient(135deg, rgba(59, 130, 246, 0.08), rgba(139, 92, 246, 0.06));
    border: 1px solid rgba(59, 130, 246, 0.2);
    border-radius: 10px;
    animation: rc-slide-down 0.3s ease;
}
/* The single-line summary (always visible). list-style:none drops the native
   disclosure triangle — we draw our own chevron. */
.rc-guidance-summary {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    cursor: pointer;
    list-style: none;
    user-select: none;
}
.rc-guidance-summary::-webkit-details-marker { display: none; }
.rc-guidance-icon {
    font-size: 15px;
    color: #3b82f6;
    flex-shrink: 0;
}
.rc-guidance-summary-text {
    font-weight: 600;
    font-size: 13px;
    color: var(--text-primary, #1e293b);
}
.rc-guidance-summary-hint {
    font-size: 11px;
    color: var(--text-tertiary, #94a3b8);
}
/* "press ? for shortcuts" is meaningless on touch (no keyboard) and it crowds
   the guidance banner's header on a phone. Hide it on hover-less pointers; the
   full shortcuts list stays reachable inside the expanded banner on desktop. */
@media (hover: none) and (pointer: coarse) {
    .rc-guidance-summary-hint { display: none; }
}
.rc-guidance-summary-hint kbd {
    display: inline-block;
    padding: 0 4px;
    background: var(--bg-tertiary, #e2e8f0);
    border-radius: 4px;
    font-family: monospace;
    font-size: 10px;
    border: 1px solid var(--border-color, #cbd5e1);
}
.rc-guidance-chevron {
    margin-left: auto;
    font-size: 11px;
    color: var(--text-tertiary, #94a3b8);
    transition: transform 0.2s ease;
}
.rc-guidance-banner[open] .rc-guidance-chevron {
    transform: rotate(180deg);
}
.rc-guidance-body {
    padding: 0 12px 12px 34px;
}
.rc-guidance-text {
    font-size: 12px;
    color: var(--text-secondary, #64748b);
    line-height: 1.5;
}
.rc-guidance-text strong {
    color: var(--text-primary, #1e293b);
}
.rc-guidance-shortcuts {
    margin-top: 8px;
    font-size: 11px;
    color: var(--text-tertiary, #94a3b8);
}
.rc-guidance-shortcuts kbd {
    display: inline-block;
    padding: 1px 5px;
    background: var(--bg-tertiary, #e2e8f0);
    border-radius: 4px;
    font-family: monospace;
    font-size: 11px;
    border: 1px solid var(--border-color, #cbd5e1);
}
.rc-guidance-dismiss {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Darker glyph + faint chip so this inline X stays visible on the light
       guidance row (2026-06-17 X-visibility pass; was slate-400 ≈2.7:1, gone on
       white). Kept lighter than the header chips since it's a small inline cue. */
    color: var(--slate-600, #475569);
    background: var(--slate-100, #f1f5f9);
    border: 1px solid var(--slate-200, #e2e8f0);
    cursor: pointer;
    padding: 2px 4px;
    margin-left: 2px;
    font-size: 13px;
    flex-shrink: 0;
    border-radius: 4px;
}
.rc-guidance-dismiss:hover {
    background: var(--slate-200, #e2e8f0);
    border-color: var(--slate-300, #cbd5e1);
    color: var(--slate-700, #334155);
}
body.dark-mode .rc-guidance-dismiss {
    background: var(--slate-700, #334155);
    border-color: var(--slate-600, #475569);
    color: var(--slate-200, #e2e8f0);
}
.rc-guidance-dismiss:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--review-focus-ring, rgba(20, 184, 166, 0.4));
}

@keyframes rc-slide-down {
    from { opacity: 0; transform: translateY(-8px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Reduced-motion: no slide-in, no chevron spin. */
@media (prefers-reduced-motion: reduce) {
    .rc-guidance-banner { animation: none; }
    .rc-guidance-chevron { transition: none; }
}

body.dark-mode .rc-guidance-banner {
    background: linear-gradient(135deg, rgba(59, 130, 246, 0.12), rgba(139, 92, 246, 0.08));
    border-color: rgba(59, 130, 246, 0.25);
}
body.dark-mode .rc-guidance-shortcuts kbd,
body.dark-mode .rc-guidance-summary-hint kbd {
    background: #334155;
    border-color: #475569;
}

/* ============================================
   BATCH SELECT BAR
   ============================================ */
.rc-batch-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    margin-bottom: 8px;
    border-radius: 8px;
    flex-wrap: wrap;
}
.rc-batch-bar-collapsed {
    justify-content: flex-end;
}
.rc-batch-bar-active {
    background: rgba(59, 130, 246, 0.06);
    border: 1px solid rgba(59, 130, 246, 0.2);
    justify-content: space-between;
    /* Stick to the top of the review modal scroll viewport so bulk
       actions stay reachable while scrolling through a long card list. */
    position: sticky;
    top: 0;
    z-index: 5;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}

/* Inline tip surfaced once below the active batch bar. Dismissible. */
.rc-batch-tip {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    margin-bottom: 8px;
    font-size: 12px;
    color: var(--slate-600);
    background: rgba(59, 130, 246, 0.04);
    border: 1px dashed rgba(59, 130, 246, 0.25);
    border-radius: 6px;
}

.rc-batch-tip kbd {
    display: inline-block;
    padding: 0 5px;
    background: var(--slate-100, #f1f5f9);
    border: 1px solid var(--slate-300, #cbd5e1);
    border-bottom-width: 2px;
    border-radius: 3px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 10px;
    line-height: 1.5;
    color: var(--slate-700);
}

.rc-batch-tip-close {
    margin-left: auto;
    background: transparent;
    border: none;
    cursor: pointer;
    color: var(--slate-500);
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
}

.rc-batch-tip-close:hover {
    background: rgba(0, 0, 0, 0.05);
    color: var(--slate-700);
}

body.dark-mode .rc-batch-tip {
    background: rgba(59, 130, 246, 0.08);
    border-color: rgba(59, 130, 246, 0.3);
    color: var(--slate-300);
}

body.dark-mode .rc-batch-tip kbd {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-600, #475569);
    color: var(--slate-200, #e2e8f0);
}

body.dark-mode .rc-batch-tip-close { color: var(--slate-400); }
body.dark-mode .rc-batch-tip-close:hover { background: rgba(255, 255, 255, 0.06); color: var(--slate-200); }
.rc-batch-info {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--text-secondary, #64748b);
}
.rc-batch-info input[type="checkbox"] {
    width: 16px;
    height: 16px;
    accent-color: #3b82f6;
}
.rc-batch-actions {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}
.rc-batch-actions .btn {
    font-size: 12px;
    padding: 5px 10px;
}
.rc-batch-cb {
    width: 16px;
    height: 16px;
    accent-color: #3b82f6;
    margin-right: 6px;
    flex-shrink: 0;
    cursor: pointer;
}
.rc-batch-selected {
    outline: 2px solid rgba(59, 130, 246, 0.4);
    outline-offset: -2px;
    background: rgba(59, 130, 246, 0.03) !important;
}

body.dark-mode .rc-batch-bar-active {
    background: rgba(59, 130, 246, 0.1);
    border-color: rgba(59, 130, 246, 0.3);
}

/* ============================================
   AUTO-ACCEPT TIMER URGENCY ESCALATION
   ============================================ */
.rc-auto-accept-timer {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 12px;
    font-weight: 500;
    padding: 2px 8px;
    border-radius: 12px;
    /* Explicit props (not transition:all) per the visibility-trap guard. */
    transition: background-color 0.3s ease, color 0.3s ease;
}
.rc-timer-calm {
    color: var(--rc-status-working);
    background: rgba(22, 163, 74, 0.08);
}
/* Dark mode: the calm green tint washed out on slate (the green-on-light-green
   fill was tuned for white). Lift the text + tint for contrast. */
body.dark-mode .rc-timer-calm {
    color: #4ade80;
    background: rgba(22, 163, 74, 0.18);
}
.rc-timer-amber {
    /* Amber-700 strong text on amber background — see urgency-tomorrow note. */
    color: #d97706;
    background: rgba(217, 119, 6, 0.1);
    animation: rc-pulse-amber 2s infinite;
}
.rc-timer-critical {
    color: var(--rc-status-busy);
    background: rgba(220, 38, 38, 0.1);
    animation: rc-pulse-critical 1.2s infinite;
    font-weight: 600;
}

@keyframes rc-pulse-amber {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.7; }
}
@keyframes rc-pulse-critical {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.8; transform: scale(1.02); }
}

/* Snooze button */
.rc-snooze-btn {
    font-size: 11px !important;
    padding: 2px 8px !important;
    border-radius: 10px !important;
    background: var(--bg-secondary, #f1f5f9) !important;
    border: 1px solid var(--border-color, #e2e8f0) !important;
    color: var(--text-secondary, #64748b) !important;
    cursor: pointer;
    transition: all 0.15s;
}
.rc-snooze-btn:hover {
    background: var(--bg-tertiary, #e2e8f0) !important;
    color: var(--text-primary, #1e293b) !important;
}

body.dark-mode .rc-snooze-btn {
    background: #1e293b !important;
    border-color: #334155 !important;
    color: #94a3b8 !important;
}

/* ============================================
   PROGRESSIVE DISCLOSURE (CARD EXPAND)
   ============================================ */
.rc-card-details {
    padding: 8px 0 0;
    animation: rc-slide-down 0.2s ease;
}
.rc-card-expand-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    padding: 4px;
    background: none;
    border: none;
    color: var(--text-tertiary, #94a3b8);
    cursor: pointer;
    font-size: 12px;
    transition: color 0.15s;
}
.rc-card-expand-btn:hover {
    color: var(--text-primary, #1e293b);
}

/* ============================================
   STICKY SUB-TABS
   ============================================ */
.review-sub-tabs {
    position: sticky;
    top: 0;
    z-index: 5;
    background: var(--bg-primary, #fff);
    padding-bottom: 4px;
    margin: 0 -18px;
    padding-left: 18px;
    padding-right: 18px;
}
body.dark-mode .review-sub-tabs {
    background: var(--dark-bg, #0f172a);
}

/* ============================================
   TAB TRANSITION ANIMATION
   ============================================ */
/* Crossfade: the outgoing content fades toward 0 (it used to stop at 0.3,
   which read as a hard swap at 30% opacity), then the incoming content
   fades up from 0 via rc-fade-in. The exit is brief because the innerHTML
   swap happens on the next frame; a low target keeps it from looking stuck. */
.rc-tab-exit {
    opacity: 0.05;
    transition: opacity 0.12s ease;
}
.rc-tab-enter {
    animation: rc-fade-in 0.2s ease;
}
@keyframes rc-fade-in {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* ============================================
   KEYBOARD FOCUS HIGHLIGHT
   ============================================ */
.rc-card-focused {
    outline: 2px solid var(--primary-color, #3b82f6) !important;
    outline-offset: -1px;
    box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.12) !important;
}

/* ============================================
   SCREEN READER ONLY
   ============================================ */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ============================================
   OUTGOING TAB: WITHDRAW BUTTON
   ============================================ */
.outgoing-actions {
    padding: 6px 0 2px;
    display: flex;
    gap: 6px;
    /* Right-aligned to match .my-proposal-actions (2026-08-06). Both card types
       render into the SAME scroll column under "Sent by me", and this one was
       left-aligned while its neighbour was right-aligned - so scanning down one
       list, the primary action jumped from one edge to the other. Right is the
       dominant convention across the panel. */
    justify-content: flex-end;
}
.rc-withdraw-btn {
    font-size: 11px !important;
    padding: 4px 10px !important;
    color: var(--text-secondary, #64748b) !important;
}
.rc-withdraw-btn:hover {
    color: var(--review-urgent, #ef4444) !important;
    border-color: var(--review-urgent, #ef4444) !important;
}

/* ============================================
   REVIEW ITEM: WARNING CLASS (amber urgency)
   ============================================ */
.review-item.warning {
    /* Darker amber for the accent border on light backgrounds — see
       urgency-tomorrow comment. */
    border-left: 3px solid #d97706;
}
.review-item.urgent {
    border-left: 3px solid var(--rc-status-busy);
}

body.dark-mode .review-item.warning {
    border-left-color: var(--rc-status-tentative);
}
body.dark-mode .review-item.urgent {
    border-left-color: #ef4444;
}

/* ============================================
   BATCH TOGGLE BUTTON
   ============================================ */
.rc-batch-toggle-btn {
    font-size: 12px;
    padding: 5px 12px;
    border-radius: 8px;
    opacity: 0.7;
    transition: opacity 0.15s;
}
.rc-batch-toggle-btn:hover {
    opacity: 1;
}

/* ============================================
   EMPTY STATES: MEANINGFUL MESSAGES
   ============================================ */
/* (The .empty-hint colour/size live once at :7711 — AA-passing slate-600.
   This block previously re-set them to a failing slate-tertiary; removed.) */
.review-empty .empty-hint i {
    margin-right: 4px;
}

/* ============================================
   (CONFLICT TIMELINE VISUALIZATION removed 2026-08-15.
   The bespoke two-lane chart, .rc-conflict-timeline / .rc-timeline-*,
   was replaced by the conflict mini-board, .rcx-*, defined next to the
   .conflict-item card styles earlier in this file. The mini-board speaks
   the board vocabulary: slate busy spans on an #e2e8f0 empty track, with
   the red overlap column as the only red element.)
   ============================================ */

/* ============================================
   DARK MODE: additional overrides (3rd pass)
   ============================================ */
body.dark-mode .rc-guidance-summary-text { color: #f1f5f9; }
body.dark-mode .rc-guidance-text { color: #94a3b8; }
body.dark-mode .rc-guidance-text strong { color: #f1f5f9; }
body.dark-mode .rc-guidance-icon { color: #60a5fa; }
body.dark-mode .rc-guidance-dismiss { color: #64748b; }
body.dark-mode .rc-guidance-dismiss:hover { color: #e2e8f0; }
body.dark-mode .rc-batch-info { color: #94a3b8; }
body.dark-mode .rc-card-expand-btn { color: #64748b; }
body.dark-mode .rc-card-expand-btn:hover { color: #e2e8f0; }
body.dark-mode .rc-search-clear { color: #64748b; }
body.dark-mode .rc-search-clear:hover { color: #e2e8f0; }
body.dark-mode .rc-scheduled-progress { border-color: #334155; }
body.dark-mode .rc-seen-badge { color: #4ade80; }
body.dark-mode .rc-unseen-badge { color: #64748b; }
body.dark-mode .confidence-pct { color: #94a3b8; }

/* ============================================
   MOBILE: responsive breakpoints (3rd pass)
   ============================================ */
@media (max-width: 640px) {
    /* Search on its own row; the two dropdowns (Sort + date) SHARE the next row
       rather than each taking a full-width row (user 2026-06-21: "more minimal
       with its space"). The bar already flex-wraps, so a full-basis search input
       breaks the line and the two flex:1 dropdowns then split the row below it —
       reclaiming ~50px vs the old flex-direction:column stack. */
    .rc-search-filter-bar { flex-direction: row; flex-wrap: wrap; row-gap: 8px; }
    .rc-search-input-wrap { flex: 1 1 auto; min-width: 0; }
    .rc-dropdown { flex: 1 1 0; min-width: 0; }
    .rc-dropdown-trigger { width: 100%; justify-content: space-between; }
    .rc-dropdown-menu { right: auto; left: 0; width: 100%; }

    /* Mobile: search stays on the row with a compact "Filters" toggle beside it;
       the Sort + Date dropdowns are tucked away until the toggle is tapped. This
       drops the at-rest filter chrome from two strips (search row + dropdown row)
       to one, so the user reaches their items sooner. */
    .rc-filters-toggle {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        position: relative;
        flex: 0 0 auto;
        min-height: 40px;
        padding: 8px 12px;
        border: 1px solid var(--slate-200, #e2e8f0);
        border-radius: var(--radius-md, 8px);
        background: var(--surface-primary, #fff);
        color: var(--slate-600, #475569);
        font-size: 13px;
        font-weight: 500;
        cursor: pointer;
    }
    .rc-filters-toggle.rc-filter-on {
        color: var(--primary-600, #0d9488);
        border-color: color-mix(in srgb, var(--primary-500, #14b8a6) 35%, transparent);
    }
    .rc-filters-toggle .rc-filter-dot {
        width: 7px; height: 7px; border-radius: 50%;
        background: var(--primary-500, #14b8a6);
    }
    /* Dropdowns hidden until the toggle opens them; then they take their own
       full-width row below the search+toggle line. */
    .rc-filter-dropdowns {
        display: none;
        flex: 1 1 100%;
        gap: 8px;
    }
    .rc-search-filter-bar.rc-filters-open .rc-filter-dropdowns {
        display: flex;
    }
    body.dark-mode .rc-filters-toggle {
        background: var(--slate-800, #1e293b);
        border-color: var(--slate-700, #334155);
        color: var(--slate-300, #cbd5e1);
    }
    .rc-guidance-banner { flex-direction: column; gap: 8px; }
    .rc-batch-bar-active { flex-direction: column; align-items: stretch; }
    .rc-batch-actions { justify-content: stretch; }
    .rc-batch-actions .btn { flex: 1; text-align: center; }
}

/* ============================================
   SEEN / UNSEEN badges (outgoing tab)
   ============================================ */
.rc-seen-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    font-weight: 500;
    color: #16a34a;
}
.rc-unseen-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    font-weight: 500;
    color: #94a3b8;
}
.confidence-pct {
    font-size: 11px;
    font-weight: 600;
    color: #64748b;
    margin-left: 4px;
}

/* ============================================
   DETAIL: location inside expandable details
   ============================================ */
.rc-detail-location {
    font-size: 12px;
    color: var(--text-secondary, #64748b);
    padding: 4px 0;
}
.rc-detail-location i {
    margin-right: 4px;
    color: var(--text-tertiary, #94a3b8);
}
body.dark-mode .rc-detail-location {
    color: #94a3b8;
}
body.dark-mode .rc-detail-location i {
    color: #64748b;
}

/* ============================================
   CONFLICT: Keep Both action (shared, in card footer)
   ============================================ */
.conflict-action-btn.keep-both-btn {
    background: transparent;
    color: var(--slate-500);
    border-color: var(--slate-200);
}

.conflict-action-btn.keep-both-btn:hover {
    color: var(--rc-status-working);
    border-color: var(--rc-status-working);
    background: rgba(22, 163, 74, 0.08);
}

body.dark-mode .conflict-action-btn.keep-both-btn {
    background: transparent;
    color: var(--slate-400);
    border-color: var(--slate-700);
}

body.dark-mode .conflict-action-btn.keep-both-btn:hover {
    color: #4ade80;
    border-color: #4ade80;
    background: rgba(74, 222, 128, 0.1);
}

.incoming-empty {
    text-align: center;
    padding: 32px 20px;
}

.incoming-connect-btn {
    margin-top: 14px;
}

body.dark-mode .synced-sweep-bar {
    background: rgba(15, 23, 42, 0.4);
}

body.dark-mode .synced-sweep-btn:hover,
body.dark-mode .synced-vis-btn:hover {
    background: rgba(148, 163, 184, 0.1);
}

/* ============================================================
   Calendar privacy floor — first-connect prompt overlay
   ============================================================ */

/* ⭐2026-08-27 MAKEOVER — this dialog is a hand-rolled overlay (41 other
   surfaces go through Modal.open()), so it never inherited the app's modal
   chrome and drifted off-brand. Measured against the tokens before the
   rewrite:
     radius   12px / 8px literals   vs  --radius-2xl / --radius-md
     width    460px                 vs  560px (.modal-content)
     shadow   ad-hoc 20px 50px      vs  --shadow-xl
     accent   #0284c7 PRE-REBRAND   vs  --primary-500 teal  ⚠️
     focus    2px blue outline      vs  --focus-ring + halo
   The #0284c7 fallback is the same pre-rebrand blue the token comment in
   style.css records as having leaked onto ~93 sites. It only shows when the
   token is missing, but it is exactly how the drift spread — so it goes.

   Dark mode was VERIFIED WORKING before and after (body.dark-mode, not
   data-theme — the tokens carry it, including --border-color -> #334155).
   Nothing here hardcodes a hue that would defeat it. */
.calendar-floor-overlay {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: blur(2px);
    z-index: var(--z-system-top);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
}

.calendar-floor-modal {
    background: var(--surface-primary, var(--bg-primary, #fff));
    border-radius: var(--radius-2xl, 20px);
    padding: 24px;
    max-width: 560px;
    width: 100%;
    box-shadow:
        0 24px 48px rgba(0, 0, 0, 0.2),
        0 0 0 1px rgba(255, 255, 255, 0.1),
        var(--shadow-xl, 0 20px 40px rgba(0, 0, 0, 0.12));
}

/* Beta badge: single definition lives in style.css (.beta-badge, with the
   dark-mode override). The copy that lived here drifted independently. */

.calendar-floor-modal h3 {
    margin: 0 0 8px;
    /* Matches .modal-header's title weight/size rather than a local guess. */
    font-size: 1.25rem;
    font-weight: 650;
    letter-spacing: -0.01em;
    line-height: 1.3;
    color: var(--text-primary, #0f172a);
}

.calendar-floor-modal .floor-subtitle {
    margin: 0 0 20px;
    font-size: 0.875rem;
    color: var(--text-secondary, #64748b);
    line-height: 1.55;
}

/* ⭐2026-08-27 THE CARDS ARE NOW THE SHARED COMPONENT. The choice buttons
   carry `.privacy-scale-option .visibility-option` and render a `.vis-preview`
   strip, exactly like the New Group class picker — so their card chrome,
   selected state, `.recommended-badge` and preview styling all come from
   board-modals.css / privacy-cards.css and are maintained in ONE place.
   Owner: "why not use something closer to this — the group creation example".

   The ~90 lines of bespoke `.floor-choice` card styling that used to live
   here are deliberately GONE. Re-adding local card rules would fork the two
   surfaces again, which is exactly what this change set out to fix. Only the
   list LAYOUT stays local. */
.calendar-floor-modal .floor-choices {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

/* Only the roomier padding is local — `flex-wrap: wrap` already ships with the
   shared component (board-modals.css ~621, so the preview strip drops onto its
   own line), and re-declaring it here would be the start of forking it again. */
.calendar-floor-modal .floor-choice {
    padding: 14px 16px;
}


/* The skip now carries a consequence line like the three choices above it, so
   the row is a LEFT-ALIGNED STACK rather than a right-aligned single button.
   ⚠️`text-align: right` here used to push the (then wordless) button to the
   corner; keeping it would strand the new description away from the control
   it describes. See calendar-sync-ui.js for why the line exists. */
/* Sits below a divider, the way every other modal separates its footer from
   its body. Without it the skip floated against the last choice card and read
   as a fourth option rather than the way out of the set. */
.calendar-floor-modal .floor-skip-row {
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border-color, #e2e8f0);
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 3px;
}

.calendar-floor-modal .floor-skip {
    padding: 2px 0;
    background: transparent;
    border: none;
    color: var(--text-secondary, #64748b);
    cursor: pointer;
    font-size: 0.85rem;
    font-weight: 550;
    text-decoration: underline;
    text-underline-offset: 3px;
    transition: color 0.14s ease;
}

.calendar-floor-modal .floor-skip:hover {
    color: var(--text-primary, #0f172a);
}

.calendar-floor-modal .floor-skip-desc {
    font-size: 0.78rem;
    line-height: 1.45;
    color: var(--text-muted, #94a3b8);
}

.calendar-floor-modal .floor-skip:focus-visible {
    outline: 2px solid var(--accent, #0284c7);
    outline-offset: 2px;
    border-radius: 4px;
}

@media (max-width: 480px) {
    .calendar-floor-modal {
        padding: 18px;
    }
}

body.dark-mode .calendar-floor-modal {
    background: var(--bg-primary, #1e293b);
    color: var(--text-primary, #e2e8f0);
}

body.dark-mode .calendar-floor-modal .floor-choice:hover {
    background: rgba(148, 163, 184, 0.08);
}

/* ============================================================
   Integration card privacy row (settings → integrations modal)
   ============================================================ */

.integration-privacy-row {
    padding-top: 8px;
    border-top: 1px solid var(--border-color, #e2e8f0);
    margin-top: 8px;
}

.integration-privacy-row .privacy-row-title {
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 6px;
    color: var(--text-primary, #0f172a);
}

.integration-privacy-row .floor-selector {
    display: flex;
    gap: 6px;
}

.integration-privacy-row .btn-floor {
    flex: 1;
    padding: 6px 10px;
    border-radius: 6px;
    border: 1px solid var(--border-color, #cbd5e1);
    background: transparent;
    cursor: pointer;
    font-size: 0.8rem;
    color: var(--text-primary, #0f172a);
    transition: background 0.12s ease, border-color 0.12s ease;
}

.integration-privacy-row .btn-floor:hover {
    border-color: var(--accent, #0284c7);
}

.integration-privacy-row .btn-floor:focus-visible,
.integration-privacy-row .btn-rereview:focus-visible {
    outline: 2px solid var(--accent, #0284c7);
    outline-offset: 2px;
}

.integration-privacy-row .btn-floor.active {
    border-color: var(--accent, #0284c7);
    background: var(--accent-bg, rgba(2, 132, 199, 0.08));
    color: var(--accent, #0284c7);
}

.integration-privacy-row .btn-rereview {
    margin-top: 8px;
    padding: 6px 10px;
    border-radius: 6px;
    border: 1px solid var(--border-color, #cbd5e1);
    background: transparent;
    cursor: pointer;
    font-size: 0.8rem;
    width: 100%;
    color: var(--text-primary, #0f172a);
    transition: background 0.12s ease, border-color 0.12s ease;
}

.integration-privacy-row .btn-rereview:hover {
    border-color: var(--accent, #0284c7);
    background: var(--bg-secondary, #f1f5f9);
}

@media (max-width: 480px) {
    .integration-privacy-row .floor-selector {
        flex-direction: column;
    }
}

/* ------------------------------------------------------------
   Per-connection category pills ("This calendar contains:
   Work | Personal | Unset"). These share the .btn-floor class
   with the privacy-row pills but live in a different container
   (.label-category-selector), which previously had NO CSS — so
   the three buttons rendered as browser-default gray. Mirror the
   privacy-row pill exactly. NOTE the selected state keys off
   `.is-selected`: settings-modals.js wireLabelCategorySelector +
   the /api/calendar/status hydration both toggle `is-selected`
   (the privacy-row pills use `.active` — keep the two separate).
   ------------------------------------------------------------ */
.label-category-selector {
    display: flex;
    gap: 6px;
}

.label-category-selector .btn-floor {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 6px 10px;
    border-radius: 6px;
    border: 1px solid var(--border-color, #cbd5e1);
    background: transparent;
    cursor: pointer;
    font-size: 0.8rem;
    color: var(--text-primary, #0f172a);
    transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.label-category-selector .btn-floor:hover {
    border-color: var(--accent, #0284c7);
}

.label-category-selector .btn-floor:focus-visible {
    outline: 2px solid var(--accent, #0284c7);
    outline-offset: 2px;
}

.label-category-selector .btn-floor.is-selected {
    border-color: var(--accent, #0284c7);
    background: var(--accent-bg, rgba(2, 132, 199, 0.08));
    color: var(--accent, #0284c7);
}

/* ============================================
   Shift assignments link-out (Outgoing tab)
   Compact CTA replacing the old inline runs list — detail lives in the
   dedicated Quota & Assignment surface.
   ============================================ */
.rc-shift-link {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 18px;
    padding: 10px 14px;
    border: 1px solid var(--slate-200, #e2e8f0);
    border-radius: 8px;
    background: var(--bg-secondary, #f8fafc);
    flex-wrap: wrap;
}

.rc-shift-link-text {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--slate-600, #475569);
    font-size: 13px;
}

.rc-shift-link-text i {
    color: var(--review-accent, var(--primary-500, #14b8a6));
}

.rc-shift-link-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
    padding: 6px 12px;
    border: 1px solid var(--review-accent, var(--primary-500, #14b8a6));
    border-radius: 6px;
    background: transparent;
    color: var(--review-accent, var(--primary-500, #14b8a6));
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
}

.rc-shift-link-btn:hover {
    background: var(--review-accent-light, rgba(20, 184, 166, 0.1));
}

.rc-shift-link-btn:focus-visible {
    outline: 2px solid var(--review-accent);
    outline-offset: 2px;
}

body.dark-mode .rc-shift-link {
    border-color: var(--slate-700, #334155);
    background: rgba(255, 255, 255, 0.02);
}

body.dark-mode .rc-shift-link-text {
    color: var(--slate-300, #cbd5e1);
}

/* ============================================================
   Privacy tab — Option C unified queue
   ============================================================ */

/* Row wraps the filter-chip group (left) and the policy chip (right). The
   row-level chrome (background + bottom border) lives here now. */
.privacy-chip-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px 6px;
    border-bottom: 1px solid var(--border-color, #e2e8f0);
    background: var(--bg-secondary, #f8fafc);
}
.privacy-filter-chips {
    display: flex; flex-wrap: wrap; gap: 6px;
    flex: 1; min-width: 0;
}

/* Publication-policy chip — deliberately quieter and visually distinct from
   the filter chips (it's a status indicator, not a selectable filter): no
   pill fill, a dotted-ish subtle border, auto-pushed to the right. */
.privacy-policy-chip {
    display: inline-flex; align-items: center; gap: 6px;
    flex-shrink: 0; margin-left: auto;
    padding: 4px 10px; border-radius: 6px;
    border: 1px dashed var(--border-color, #cbd5e1);
    background: transparent;
    color: var(--text-secondary, #64748b);
    font-size: 0.78rem; font-weight: 600;
}
/* Both variants are clickable now: admins jump to settings, read-only opens an
   info popover (2026-07-11 fix — the read-only chip used to be a dead button). */
.privacy-policy-chip.is-admin,
.privacy-policy-chip.is-readonly { cursor: pointer; }
.privacy-policy-chip.is-admin:hover,
.privacy-policy-chip.is-readonly:hover {
    border-color: var(--accent, #0284c7);
    color: var(--text-primary, #0f172a);
    background: var(--bg-primary, #fff);
}
.privacy-policy-chip:focus-visible {
    outline: 2px solid var(--accent, #0284c7); outline-offset: 2px;
}
.privacy-policy-chip .privacy-policy-chip-info {
    font-size: 0.72rem; opacity: 0.6;
}
/* "Policy:" qualifier so the chip self-identifies as the board publication
   policy rather than reading as a sixth queue-filter chip. Muted + lighter
   than the level word it precedes. */
.privacy-policy-chip .privacy-policy-chip-prefix {
    font-weight: 500; opacity: 0.7;
    margin-right: -2px;
}
/* Level tints on the leading icon so Strict reads heavier at a glance. */
.privacy-policy-chip[data-policy-level="strict"]   > i:first-child { color: var(--rc-status-busy, #dc2626); }
.privacy-policy-chip[data-policy-level="standard"] > i:first-child { color: var(--rc-status-tentative, #f59e0b); }
.privacy-policy-chip[data-policy-level="relaxed"]  > i:first-child { color: var(--rc-status-available, #22c55e); }
body.dark-mode .privacy-policy-chip { border-color: var(--slate-600, #475569); color: var(--slate-300, #cbd5e1); }
body.dark-mode .privacy-policy-chip.is-admin:hover,
body.dark-mode .privacy-policy-chip.is-readonly:hover { background: var(--slate-800, #1e293b); color: var(--slate-100, #f1f5f9); }

/* Read-only policy info popover — the on-screen explanation shown when a
   non-admin taps the chip (replaces the invisible-on-touch title tooltip). */
.privacy-policy-chip-wrap { position: relative; display: inline-flex; }
.privacy-policy-popover {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 30;
    width: 240px;
    padding: 12px 14px;
    background: var(--surface-primary, #fff);
    border: 1px solid var(--slate-200, #e2e8f0);
    border-radius: 12px;
    box-shadow: 0 12px 32px rgba(15, 23, 42, 0.16);
    text-align: left;
}
.privacy-policy-popover[hidden] { display: none; }
.privacy-policy-popover-head {
    display: flex; align-items: center; gap: 8px;
    font-size: 0.86rem; font-weight: 700;
    color: var(--text-primary, #0f172a);
    margin-bottom: 6px;
}
.privacy-policy-popover-why {
    margin: 0 0 6px;
    font-size: 0.8rem; line-height: 1.45; font-weight: 400;
    color: var(--text-secondary, #475569);
}
.privacy-policy-popover-admin {
    margin: 0;
    font-size: 0.75rem; font-weight: 500;
    color: var(--slate-400, #94a3b8);
}
body.dark-mode .privacy-policy-popover {
    background: var(--surface-secondary, #1e293b);
    border-color: var(--slate-700, #334155);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
}
body.dark-mode .privacy-policy-popover-head { color: var(--slate-100, #f1f5f9); }
body.dark-mode .privacy-policy-popover-why { color: var(--slate-300, #cbd5e1); }

/* Right-side action group: the quiet "Rules" chip + the policy chip live here
   together, pushed to the row's trailing edge. Grouping them means the policy
   chip no longer needs its own margin-left:auto (that would over-space the two
   inside the group), so neutralise it in this context. */
.privacy-chip-row-actions {
    display: inline-flex; align-items: center; gap: 6px;
    flex-shrink: 0; margin-left: auto;
}
.privacy-chip-row-actions .privacy-policy-chip { margin-left: 0; }

/* Automation-rules chip — the quietest thing in the row: it's a jump-off, not
   a status or a filter. Ghost styling matching the policy chip's weight so the
   two right-side chips read as a set, with a wand icon to signal "automation".
   Opens the AutomationRulesPanel (see click delegation in review-dashboard). */
.privacy-rules-chip {
    display: inline-flex; align-items: center; gap: 6px;
    flex-shrink: 0; cursor: pointer;
    padding: 4px 10px; border-radius: 6px;
    border: 1px dashed var(--border-color, #cbd5e1);
    background: transparent;
    color: var(--text-secondary, #64748b);
    font-size: 0.78rem; font-weight: 600; line-height: 1;
    transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.privacy-rules-chip > i:first-child {
    font-size: 0.75rem;
    color: var(--primary-500, #14b8a6);
}
.privacy-rules-chip:hover {
    border-color: var(--primary-400, #2dd4bf);
    color: var(--text-primary, #0f172a);
    background: var(--bg-primary, #fff);
}
.privacy-rules-chip:focus-visible {
    outline: 2px solid var(--primary-500, #14b8a6); outline-offset: 2px;
}
.privacy-rules-chip .privacy-rules-chip-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 16px; height: 16px; padding: 0 4px;
    border-radius: 9999px; line-height: 1;
    font-size: 0.66rem; font-weight: 700;
    color: #fff;
    background: linear-gradient(135deg, var(--primary-500, #14b8a6) 0%, var(--primary-600, #0d9488) 100%);
}
body.dark-mode .privacy-rules-chip { border-color: var(--slate-600, #475569); color: var(--slate-300, #cbd5e1); }
body.dark-mode .privacy-rules-chip:hover { background: var(--slate-800, #1e293b); color: var(--slate-100, #f1f5f9); }

/* Right-side action group: the quiet "Rules" chip + the policy chip live here
   together, pushed to the row's trailing edge. Grouping them means the policy
   chip no longer needs its own margin-left:auto (that would over-space the two
   inside the group), so neutralise it in this context. */
.privacy-chip-row-actions {
    display: inline-flex; align-items: center; gap: 6px;
    flex-shrink: 0; margin-left: auto;
}
.privacy-chip-row-actions .privacy-policy-chip { margin-left: 0; }

/* Automation-rules chip — the quietest thing in the row: it's a jump-off, not
   a status or a filter. Ghost styling matching the policy chip's weight so the
   two right-side chips read as a set, with a wand icon to signal "automation".
   Opens the AutomationRulesPanel (see click delegation in review-dashboard). */
.privacy-rules-chip {
    display: inline-flex; align-items: center; gap: 6px;
    flex-shrink: 0; cursor: pointer;
    padding: 4px 10px; border-radius: 6px;
    border: 1px dashed var(--border-color, #cbd5e1);
    background: transparent;
    color: var(--text-secondary, #64748b);
    font-size: 0.78rem; font-weight: 600; line-height: 1;
    transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.privacy-rules-chip > i:first-child {
    font-size: 0.75rem;
    color: var(--primary-500, #14b8a6);
}
.privacy-rules-chip:hover {
    border-color: var(--primary-400, #2dd4bf);
    color: var(--text-primary, #0f172a);
    background: var(--bg-primary, #fff);
}
.privacy-rules-chip:focus-visible {
    outline: 2px solid var(--primary-500, #14b8a6); outline-offset: 2px;
}
.privacy-rules-chip .privacy-rules-chip-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 16px; height: 16px; padding: 0 4px;
    border-radius: 9999px; line-height: 1;
    font-size: 0.66rem; font-weight: 700;
    color: #fff;
    background: linear-gradient(135deg, var(--primary-500, #14b8a6) 0%, var(--primary-600, #0d9488) 100%);
}
body.dark-mode .privacy-rules-chip { border-color: var(--slate-600, #475569); color: var(--slate-300, #cbd5e1); }
body.dark-mode .privacy-rules-chip:hover { background: var(--slate-800, #1e293b); color: var(--slate-100, #f1f5f9); }

/* Metrics aligned to .sub-tab (2026-08-06). Privacy is the only tab that
   filters with chips instead of sub-tabs — defensible, since `all` / `needs
   approval` / `done` do not map onto the awaiting/actioned spine the other tabs
   share, and deep links carry these filter values. But the chips also sat at a
   different size and padding from the sub-tabs one tab over, so the SAME job
   (choose which slice of this queue to see) looked like two different controls.
   Type scale, gap and padding now match; the 1px border is deliberately KEPT so
   a filter still reads as a filter rather than impersonating a tab. */
/* MINIMALIST, LIKE THE TABS ABOVE (2026-08-16, user: "Make the all needs
   approval and done minamalistoc like tje above tab design already").
   These carried a permanent 1px outline and an opaque white fill, which the
   .review-tab pills directly above them do not — so two rows of the same kind
   of control read as two different systems, and the heavier row was the less
   important one. Resting state is now bare like a tab; the border and fill
   arrive only on hover/active, where they mean something. */
.privacy-filter-chip {
    display: inline-flex; align-items: center; gap: 4px;
    /* Padding stays locked to .sub-tab (guard: review-empty-loading-pagination)
       — the two rows must measure the same. Only the resting border and fill
       are dropped. */
    padding: 5px 14px; border-radius: var(--radius-full, 9999px);
    border: 1px solid transparent;
    background: transparent;
    color: var(--text-secondary, #64748b);
    font-size: 0.75rem; font-weight: 500; cursor: pointer;
    transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
/* Chips follow the tab's purple identity (2026-08-04) — the old cyan accent
   fill clashed with the purple Privacy tab sitting directly above them. */
.privacy-filter-chip:hover {
    border-color: var(--visibility-private, #8b5cf6);
    color: var(--text-primary, #0f172a);
}
.privacy-filter-chip:focus-visible {
    outline: 2px solid var(--visibility-private, #8b5cf6); outline-offset: 2px;
}
.privacy-filter-chip.active {
    background: var(--visibility-private, #8b5cf6);
    border-color: var(--visibility-private, #8b5cf6);
    color: #fff;
}
/* Count pill matched to .sub-tab .sub-tab-count (2026-08-06): same 16px box,
   same 0.625rem type, so a count reads identically whichever surface shows it.
   Colours stay chip-local (the active chip fills purple and needs a light
   count on it, where an active sub-tab does not). */
.privacy-filter-chip .privacy-chip-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 16px; height: 16px;
    background: rgba(148, 163, 184, 0.22); color: inherit;
    padding: 0 5px; border-radius: 8px;
    font-size: 0.625rem; font-weight: 600;
}
.privacy-filter-chip.active .privacy-chip-count {
    background: rgba(255, 255, 255, 0.25); color: #fff;
}

.synced-sweep-bar {
    display: flex; flex-wrap: wrap; gap: 8px; align-items: center;
    padding: 10px 14px;
    border-bottom: 1px solid var(--border-color, #e2e8f0);
    background: var(--bg-secondary, #f8fafc);
}
.synced-sweep-label {
    font-size: 0.85rem; color: var(--text-secondary, #64748b);
}
/* ONE QUESTION, THREE ANSWERS (2026-08-16, user: "Clicking the options could
   be better designed").
   These were three detached, individually-outlined buttons separated by a gap,
   each carrying its own hue, its own hover fill and — when chosen — a heavy
   saturated fill plus a coloured drop-shadow. Three equal-weight boxes read as
   three independent toggles rather than a single choice, so nothing about the
   resting state said "pick one", and the selected state shouted.

   Make the group a SEGMENTED CONTROL: one bordered track, hairline dividers,
   and the selected segment lifted on a white card. That is the standard idiom
   for a mutually-exclusive choice, and it lets the selection read from shape
   and elevation rather than from decoding a colour. Each level keeps its hue
   as an ICON tint and a text colour, so the privacy grammar survives without
   three competing fills. */
.synced-row-actions,
.synced-sweep-actions {
    /* The track. */
    border: 1px solid var(--border-color, #e2e8f0);
    border-radius: 8px;
    background: var(--slate-100, #f1f5f9);
    padding: 2px;
    gap: 0;
}

.synced-sweep-btn, .synced-vis-btn {
    padding: 5px 12px;
    border-radius: 6px;
    border: 1px solid transparent;
    background: transparent; cursor: pointer;
    font-size: 0.8125rem; line-height: 1.2;
    font-weight: 500;
    color: var(--text-secondary, #64748b);
    /* Explicit props (not transition:all) per the visibility-trap guard. */
    transition: background 0.12s ease, color 0.12s ease, box-shadow 0.12s ease;
}
/* Hairline between segments — dropped on the selected one so the lifted card
   sits clean. */
.synced-vis-btn + .synced-vis-btn,
.synced-sweep-btn + .synced-sweep-btn {
    box-shadow: inset 1px 0 0 var(--slate-200, #e2e8f0);
}
.synced-vis-btn.active + .synced-vis-btn,
.synced-vis-btn:hover + .synced-vis-btn,
.synced-sweep-btn.active + .synced-sweep-btn,
.synced-sweep-btn:hover + .synced-sweep-btn {
    box-shadow: none;
}
.synced-sweep-btn:hover, .synced-vis-btn:hover {
    background: rgba(255, 255, 255, 0.6);
    color: var(--text-primary, #0f172a);
}
.synced-sweep-btn:focus-visible, .synced-vis-btn:focus-visible {
    outline: 2px solid var(--accent, #0284c7); outline-offset: 2px;
}

/* Visibility level colours — same grammar as the canonical .visibility-btn
   in the Scheduled settings panel: Private=purple, Busy=amber, Shared=green
   (the app-wide privacy scale from privacy-visual-config.js; red is never
   a privacy colour in this product). */
.synced-vis-btn i, .synced-sweep-btn i { font-size: 11px; }
.synced-vis-btn[data-visibility="hidden"] i,
.synced-sweep-btn[data-visibility="hidden"] i { color: var(--visibility-private, #8b5cf6); }
.synced-vis-btn[data-visibility="busy"] i,
.synced-sweep-btn[data-visibility="busy"] i { color: var(--rc-status-tentative); }
.synced-vis-btn[data-visibility="full"] i,
.synced-sweep-btn[data-visibility="full"] i { color: var(--rc-status-available); }

.synced-vis-btn[data-visibility="hidden"]:hover,
.synced-sweep-btn[data-visibility="hidden"]:hover {
    color: #7c3aed;
    background: rgba(139, 92, 246, 0.08);
    border-color: rgba(139, 92, 246, 0.3);
}
.synced-vis-btn[data-visibility="busy"]:hover,
.synced-sweep-btn[data-visibility="busy"]:hover {
    color: #d97706;
    background: rgba(245, 158, 11, 0.08);
    border-color: rgba(245, 158, 11, 0.3);
}
.synced-vis-btn[data-visibility="full"]:hover,
.synced-sweep-btn[data-visibility="full"]:hover {
    color: var(--rc-status-working);
    background: rgba(34, 197, 94, 0.08);
    border-color: rgba(34, 197, 94, 0.3);
}

/* SELECTED = A LIFTED WHITE CARD, not a saturated fill. The segment rises out
   of the track; the level's hue stays in the icon and the label, so the choice
   is legible by SHAPE first and colour second. This also stops the row from
   flashing a large block of colour per event on a list of twenty. */
.synced-vis-btn.active {
    background: var(--bg-primary, #fff);
    border-color: var(--border-color, #e2e8f0);
    box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
    font-weight: 600;
}
/* Each level states its own committed background explicitly. It is the same
   raised white card in every case — the hue lives in the text and icon — but
   declaring it per level keeps the "committed owns a solid fill" contract
   legible (and checkable) per level, distinct from the dashed staged chip. */
.synced-vis-btn[data-visibility="hidden"].active {
    color: #7c3aed;
    background: var(--bg-primary, #fff);
}
.synced-vis-btn[data-visibility="busy"].active {
    color: #b45309;
    background: var(--bg-primary, #fff);
}
.synced-vis-btn[data-visibility="full"].active {
    color: var(--rc-status-working);
    background: var(--bg-primary, #fff);
}

/* ── Staged (chosen, not yet confirmed) visibility ──────────────────────────
   2026-08-06. Loosening privacy (→ Busy/Shared) is a one-way door: Undo can
   restore the stored value but cannot un-disclose what a teammate already saw.
   So that choice is TICKED first and committed from the confirm bar below.
   The staged chip reads as a selection — dashed ring, tinted, never the solid
   fill that means "saved" (.active above). Tightening → Private still commits
   on the first click, so it has no staged state. */
/* .visibility-btn is the EVENTS tab's copy of the same three-level control.
   It gained the identical loosening gate on 2026-08-06 (it previously had none
   at all, so one tap disclosed an event), so it must wear the same staged
   grammar — same dashed ring, same tint, same "not saved yet" reading. Listing
   both selectors here keeps the two surfaces from drifting into two looks. */
/* TEAL RING = "THIS IS YOUR SELECTION" (2026-08-29, user: "make the selection
   clearer perhaps a teal outline"). The dashed currentColor ring was the same
   hue as the button's own level (purple on Private, amber on Busy, green on
   Shared), so the ring carried NO information the icon didn't already carry —
   at a glance a staged Busy segment and a resting Busy segment differed only
   by a dash pattern. Selection is a state that belongs to the CONTROL, not to
   the level, so it gets one colour across all three: the app's teal accent,
   which appears nowhere in the privacy scale and therefore can only mean
   "chosen". Solid ring + halo, so it reads at arm's length on a phone.

   Still visibly NOT `.active`: committed keeps the raised white card with a
   soft neutral shadow; staged is flat, tinted teal, and ringed. Two different
   answers to "has this been saved?". */
.synced-vis-btn.pending-choice,
.visibility-btn.pending-choice {
    border-style: solid;
    border-color: var(--primary-500, #14b8a6);
    background: rgba(20, 184, 166, 0.1);
    box-shadow: 0 0 0 2px rgba(20, 184, 166, 0.28);
    font-weight: 700;
    /* Sits above its neighbours so the ring is never clipped by the next
       segment's border in the segmented track (gap:0 — they share edges). */
    position: relative;
    z-index: 1;
}
/* The tick that replaces the level icon when staged. Teal to match the ring,
   so icon and outline say the same thing. */
.synced-vis-btn.pending-choice i,
.visibility-btn.pending-choice i {
    color: var(--primary-600, #0d9488);
}
body.dark-mode .synced-vis-btn.pending-choice,
body.dark-mode .visibility-btn.pending-choice {
    border-color: var(--primary-400, #2dd4bf);
    background: rgba(45, 212, 191, 0.16);
    box-shadow: 0 0 0 2px rgba(45, 212, 191, 0.3);
}
body.dark-mode .synced-vis-btn.pending-choice i,
body.dark-mode .visibility-btn.pending-choice i {
    color: var(--primary-300, #5eead4);
}
.synced-row-confirm {
    /* The row is a flex line; take a full-width line of our own beneath it. */
    flex-basis: 100%;
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    padding: 8px 10px;
    border-radius: 8px;
    background: rgba(139, 92, 246, 0.08);
    border: 1px solid rgba(139, 92, 246, 0.35);
}
.synced-confirm-text {
    flex: 1;
    min-width: 0;
    font-size: 12px;
    line-height: 1.35;
    color: var(--text-primary, #0f172a);
}
.synced-confirm-cancel,
.synced-confirm-apply {
    flex-shrink: 0;
    padding: 5px 10px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    border: 1px solid transparent;
}
.synced-confirm-cancel {
    background: transparent;
    border-color: var(--border-color, #e2e8f0);
    color: var(--text-secondary, #64748b);
}
.synced-confirm-cancel:hover { background: var(--slate-100, #f1f5f9); }
.synced-confirm-apply {
    background: var(--visibility-private, #8b5cf6);
    color: #fff;
}
.synced-confirm-apply:hover { filter: brightness(1.06); }
.synced-confirm-apply:focus-visible,
.synced-confirm-cancel:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--review-focus-ring, rgba(20, 184, 166, 0.4));
}
/* The row must be allowed to wrap for the confirm line to sit under the chips. */
.synced-row { flex-wrap: wrap; }
body.dark-mode .synced-row-confirm {
    background: rgba(139, 92, 246, 0.16);
    border-color: rgba(139, 92, 246, 0.45);
}
body.dark-mode .synced-confirm-text { color: var(--slate-100, #f1f5f9); }
body.dark-mode .synced-confirm-cancel {
    border-color: var(--slate-600, #475569);
    color: var(--slate-300, #cbd5e1);
}
body.dark-mode .synced-confirm-cancel:hover { background: var(--slate-700, #334155); }
/* (The grey dark-mode staged background that used to sit here was removed
   2026-08-29 with the teal selection ring. It came LATER in the file than the
   teal rule and shared its specificity, so it won the cascade and repainted
   the staged segment slate in dark mode — the exact "can't tell what's
   selected" the ring exists to fix. The dark variant now lives beside the
   light one at ~12569.) */
@media (max-width: 480px) {
    /* Stack on a phone so the message isn't squeezed to two words. */
    .synced-row-confirm { flex-wrap: wrap; }
    .synced-confirm-text { flex-basis: 100%; }
}

.synced-tab-content { display: flex; flex-direction: column; }
.synced-list { display: flex; flex-direction: column; }
.synced-row {
    display: flex; align-items: center; gap: 12px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--border-color, #e2e8f0);
}
.synced-row-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.synced-row-title {
    font-weight: 600; color: var(--text-primary, #0f172a);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Meta is a wrapping inline-flex row so its pills (recurring / approval /
   sensitive / suggested) reflow onto a second line on narrow widths instead
   of overflowing or shoving the action buttons off-row. */
.synced-row-meta {
    font-size: 0.8rem; color: var(--text-secondary, #64748b);
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px;
    line-height: 1.5;
}
/* gap:0 — this is a SEGMENTED TRACK, not three loose buttons. A 6px gap here
   was overriding the segmented rule above (this declaration comes later in the
   file and wins), so the segments floated apart inside their own track and the
   divider hairlines had nothing to divide. Verified on the live render at
   390px: real 6px gaps between segments. */
.synced-row-actions { display: flex; gap: 0; flex-shrink: 0; }

/* Suggested (calendar-default) pre-selection for a freshly-synced event.
   A calm amber hint — clearly "recommended, not decided" so the user still
   confirms. Sits in the meta row like the other pills. */
.synced-suggest-pill {
    display: inline-flex; align-items: center; gap: 3px;
    padding: 1px 7px; border-radius: 999px;
    background: rgba(217, 119, 6, 0.14);
    color: #b45309;
    font-size: 0.72rem; font-weight: 600;
}
.synced-suggest-pill i { font-size: 0.7rem; }
body.dark-mode .synced-suggest-pill { background: rgba(217, 119, 6, 0.24); color: #fbbf24; }

/* The vis button matching the suggestion gets a dashed amber ring (distinct
   from the solid-fill `.active` "decided" state) so the recommended tap is
   obvious without looking already-chosen. */
.synced-vis-btn.suggested:not(.active) {
    border-color: #d97706;
    border-style: dashed;
    box-shadow: 0 0 0 1px rgba(217, 119, 6, 0.25) inset;
}
body.dark-mode .synced-vis-btn.suggested:not(.active) {
    border-color: #fbbf24;
    box-shadow: 0 0 0 1px rgba(251, 191, 36, 0.3) inset;
}

.synced-row-newpip {
    display: inline-block; padding: 1px 6px;
    border-radius: 999px; background: var(--accent, #0284c7); color: #fff;
    font-size: 0.65rem; font-weight: 700; vertical-align: middle;
}
.synced-recurring-pill {
    display: inline-flex; align-items: center; gap: 3px;
    padding: 1px 6px; border-radius: 999px;
    background: rgba(148, 163, 184, 0.18);
    color: var(--text-secondary, #475569);
    font-size: 0.72rem; font-weight: 500;
}

.incoming-source-split { display: inline-flex; gap: 6px; align-items: center; }
/* Real filter buttons since 2026-07-27 (were inert <span> decoration that read
   as clickable pills and did nothing). They must LOOK and BEHAVE like controls:
   pointer cursor, hover/active affordance, focus ring, and a 44px touch target
   under coarse pointers. Unselected state is a muted outline so the ACTIVE
   provider is unambiguous — previously both were permanently filled, which is
   why they looked "already selected" and unresponsive. */
.incoming-source-chip {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 2px 8px; border-radius: 999px;
    font-size: 0.75rem; font-weight: 600;
    cursor: pointer;
    border: 1px solid transparent;
    background: rgba(148, 163, 184, 0.18);
    color: var(--text-secondary, #475569);
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.incoming-source-chip:hover { background: rgba(148, 163, 184, 0.3); }
.incoming-source-chip:focus-visible {
    outline: 2px solid var(--accent-color, #0284c7);
    outline-offset: 2px;
}
/* Selected: fill with the provider's brand colour. */
.incoming-source-chip.incoming-source-google.active    { background: #4285f4; color: #fff; border-color: #4285f4; }
.incoming-source-chip.incoming-source-microsoft.active { background: #00a4ef; color: #fff; border-color: #00a4ef; }
/* Unselected: brand-tinted text + border so the provider is still identifiable. */
.incoming-source-chip.incoming-source-google:not(.active)    { color: #1a56c4; border-color: rgba(66, 133, 244, 0.45); }
.incoming-source-chip.incoming-source-microsoft:not(.active) { color: #0369a1; border-color: rgba(0, 164, 239, 0.45); }

@media (hover: none) and (pointer: coarse) {
    .incoming-source-chip { min-height: 44px; padding: 2px 12px; }
}

/* Zero-count filter chip: dimmed but PRESENT and still clickable. "Recent" used
   to be omitted entirely at 0, so its absence read as a missing control rather
   than an empty bucket. Not `disabled` — clicking it should still switch to the
   empty view and explain itself. (2026-07-27) */
.privacy-filter-chip.is-empty:not(.active) { opacity: 0.55; }
.privacy-filter-chip.is-empty:not(.active):hover { opacity: 0.85; }

.incoming-onboard {
    display: flex; align-items: flex-start; gap: 12px;
    padding: 12px 14px;
    background: var(--accent-bg, rgba(2, 132, 199, 0.06));
    border-bottom: 1px solid var(--border-color, #e2e8f0);
    color: var(--text-primary, #0f172a);
}
/* Collapsed-by-default <details> variant (2026-06-29): the privacy explainer
   shows as a one-line summary so it no longer fills the first phone screen.
   The root is a block; the summary carries the flex row. */
details.incoming-onboard-details {
    display: block;
    padding: 0;
}
.incoming-onboard-summary {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 14px;
    cursor: pointer;
    list-style: none;
    font-size: 0.85rem;
}
.incoming-onboard-summary::-webkit-details-marker { display: none; }
.incoming-onboard-summary strong { flex: 1 1 auto; font-weight: 600; }
.incoming-onboard-chev {
    flex-shrink: 0; font-size: 0.7rem; color: var(--text-secondary, #64748b);
    transition: transform 0.2s ease;
}
details.incoming-onboard-details[open] .incoming-onboard-chev { transform: rotate(180deg); }
.incoming-onboard-details .incoming-onboard-body {
    padding: 0 14px 12px 40px;
}

/* The review-first CONSEQUENCE line (2026-08-25): unlike the collapsible
   explainer above it, this is not dismissable — while rows sit pending the
   user's availability reads as open to the group, and that stays true no
   matter how many times they've seen the note. Quiet, one line, no box. */
.incoming-pending-consequence {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 2px 2px 8px;
    font-size: 0.78rem;
    color: var(--text-secondary, #64748b);
}
.incoming-pending-consequence i {
    font-size: 0.7rem;
    color: var(--slate-400, #94a3b8);
    flex-shrink: 0;
}
body.dark-mode .incoming-pending-consequence { color: var(--slate-400, #94a3b8); }
.incoming-onboard-icon {
    flex-shrink: 0; padding-top: 2px;
    color: var(--accent, #0284c7); font-size: 1rem;
}
.incoming-onboard-body {
    flex: 1 1 auto; min-width: 0;
    display: flex; flex-direction: column; gap: 2px;
    font-size: 0.85rem; line-height: 1.4;
}
.incoming-onboard-body strong { font-weight: 600; }
.incoming-onboard-body span { color: var(--text-secondary, #64748b); }
.incoming-onboard-dismiss {
    flex-shrink: 0; padding: 4px;
    background: transparent; border: none; cursor: pointer;
    color: var(--text-secondary, #64748b);
    border-radius: 4px;
}
.incoming-onboard-dismiss:hover {
    background: rgba(148, 163, 184, 0.15);
    color: var(--text-primary, #0f172a);
}
.incoming-onboard-dismiss:focus-visible {
    outline: 2px solid var(--accent, #0284c7); outline-offset: 2px;
}

.incoming-empty { text-align: center; padding: 32px 20px; }
.incoming-empty-locked .empty-icon { color: var(--accent, #0284c7); }
.incoming-connect-btn { margin-top: 14px; }

@media (max-width: 640px) {
    /* Stack the policy chip under the (scrollable) filter chips on narrow
       screens so it isn't squeezed against them. */
    /* ⭐2026-08-20 (owner: "the tabs should fit in the row not stack").
       This block flipped .privacy-chip-row to a COLUMN on the assumption that
       its chips live inside a .privacy-filter-chips wrapper (which the rule
       below then scrolls horizontally). The renderer emits NO such wrapper —
       review-dashboard.js puts .privacy-filter-chip buttons DIRECTLY in
       .privacy-chip-row — so on every phone the three chips stretched to the
       full 279px width and stacked into three rows (measured live: tops 141 /
       179 / 217). Only take the column when the wrapper is actually present;
       otherwise keep one horizontally-scrolling row, matching the wrapper
       treatment. :has() is safe here — the modal already relies on it and the
       no-:has fallback is the pre-existing stacked layout. */
    .privacy-chip-row:has(.privacy-filter-chips) {
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
        padding: 8px 12px 4px;
    }
    .privacy-chip-row:not(:has(.privacy-filter-chips)) {
        flex-direction: row;
        align-items: center;
        gap: 6px;
        padding: 8px 12px 4px;
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
        /* Right-edge fade so it reads as "more chips off-screen", the same
           affordance the wrapper variant gets. */
        -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent);
        mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent);
    }
    .privacy-chip-row:not(:has(.privacy-filter-chips))::-webkit-scrollbar { display: none; }
    /* Chips size to their own label instead of stretching to the row. */
    .privacy-chip-row:not(:has(.privacy-filter-chips)) > .privacy-filter-chip {
        flex: 0 0 auto;
        width: auto;
        align-self: center;
    }
    .privacy-filter-chips {
        flex-wrap: nowrap; overflow-x: auto;
        padding: 0;
        /* Hide the scrollbar but keep a right-edge fade so it's clear there
           are more chips off the right than fit (e.g. All/Sync/Approval/
           Sensitive/Recent on a 390px row). */
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
        -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent);
        mask-image: linear-gradient(to right, #000 calc(100% - 20px), transparent);
    }
    .privacy-filter-chips::-webkit-scrollbar { display: none; }
    .privacy-policy-chip { margin-left: 0; align-self: flex-start; }
    .privacy-filter-chip { flex-shrink: 0; }
    .synced-sweep-bar { flex-direction: column; align-items: stretch; }
    /* TIGHTEN THE STACKED ROW (2026-08-16, user: "Extra row space").
       Flipping to a column turned the 12px row gap into ~24px of vertical
       dead space per row (checkbox band + info band + action band), on top of
       10px padding — so a list of three-line rows scrolled far longer than it
       had content for. The axis flip was the only thing this block changed;
       the spacing that suited a single horizontal row was never revisited. */
    .synced-row {
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
        padding: 8px 12px;
    }
    /* The segmented track spans the stacked row, so the three segments divide
       one full-width control rather than floating as separate buttons. */
    .synced-row-actions { justify-content: stretch; width: 100%; }
    /* Both sweep buttons AND per-row vis buttons stretch full-width in the
       stacked column so the Hidden/Busy/Shared sweep row matches the rows
       below it instead of sitting left-aligned at natural width. */
    .synced-vis-btn,
    .synced-sweep-btn { flex: 1; text-align: center; justify-content: center; }
}

body.dark-mode .privacy-filter-chip { background: var(--bg-primary, #1e293b); }
body.dark-mode .privacy-chip-row,
body.dark-mode .synced-sweep-bar { background: rgba(15, 23, 42, 0.4); }
body.dark-mode .incoming-onboard { background: rgba(2, 132, 199, 0.12); }
body.dark-mode .synced-recurring-pill { background: rgba(148, 163, 184, 0.22); }
body.dark-mode .synced-sweep-btn:hover,
body.dark-mode .synced-vis-btn:hover { background: rgba(148, 163, 184, 0.1); }

/* ============================================================
   Privacy — Reviewed-mode rows (April §2.2 history view)
   ============================================================ */

.synced-row.synced-row-reviewed { opacity: 0.92; }

.synced-row-decided {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 4px 10px; border-radius: 999px;
    font-size: 0.78rem; font-weight: 600;
}
/* Decided pills — Private=purple, Busy=amber, Shared=green (the app-wide
   privacy scale). Hidden was grey, which read as "neutral/unset" and disagreed with the
   active vis buttons; now it matches the rest of the visibility palette. */
.synced-row-decided-hidden { background: rgba(139, 92, 246, 0.16); color: #6d28d9; }
.synced-row-decided-busy   { background: rgba(217, 119, 6, 0.22);   color: #b45309; }
.synced-row-decided-full   { background: rgba(16, 185, 129, 0.22);  color: #047857; }

.synced-rereview-btn {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 5px 10px; border-radius: 6px;
    border: 1px solid var(--border-color, #cbd5e1);
    background: transparent; cursor: pointer;
    font-size: 0.8rem;
    color: var(--text-secondary, #64748b);
    transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}
.synced-rereview-btn:hover {
    background: var(--bg-secondary, #f1f5f9);
    border-color: var(--accent, #0284c7);
    color: var(--accent, #0284c7);
}
.synced-rereview-btn:focus-visible {
    outline: 2px solid var(--accent, #0284c7); outline-offset: 2px;
}

/* April §2.3 — compliance export row */
.incoming-export-row {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 14px;
    border-top: 1px solid var(--border-color, #e2e8f0);
}
.incoming-export-btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px; border-radius: 6px;
    border: 1px solid var(--border-color, #cbd5e1);
    background: transparent; cursor: pointer;
    font-size: 0.85rem;
    color: var(--text-primary, #0f172a);
    transition: background 0.12s ease, border-color 0.12s ease;
}
.incoming-export-btn:hover {
    background: var(--bg-secondary, #f1f5f9);
    border-color: var(--accent, #0284c7);
}
.incoming-export-btn:focus-visible {
    outline: 2px solid var(--accent, #0284c7); outline-offset: 2px;
}
.incoming-export-hint {
    font-size: 0.78rem;
    color: var(--text-secondary, #64748b);
}

body.dark-mode .synced-rereview-btn:hover { background: rgba(148, 163, 184, 0.1); }
body.dark-mode .incoming-export-btn:hover { background: rgba(148, 163, 184, 0.1); }
body.dark-mode .synced-row-decided-hidden { background: rgba(139, 92, 246, 0.24); color: #a78bfa; }
body.dark-mode .synced-row-decided-busy   { background: rgba(217, 119, 6, 0.28);   color: #fbbf24; }
body.dark-mode .synced-row-decided-full   { background: rgba(16, 185, 129, 0.28);  color: #34d399; }

/* ============================================
   KEYBOARD SHORTCUTS OVERLAY
   ============================================ */
.rc-shortcuts-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--z-modal);
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(15, 23, 42, 0.45);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

.rc-shortcuts-panel {
    background: var(--review-card-bg, #fff);
    border: 1px solid var(--review-card-border, rgba(203, 213, 225, 0.5));
    border-radius: var(--rc-radius-card, 8px);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
    padding: 18px 22px;
    min-width: 320px;
    max-width: 420px;
    width: 90%;
}

.rc-shortcuts-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;
}

.rc-shortcuts-header h3 {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    color: var(--slate-800);
}

.rc-shortcuts-close {
    background: var(--slate-100, #f1f5f9);
    color: var(--slate-500, #64748b);
    border: none;
    border-radius: var(--radius-full, 9999px);
    width: 32px;
    height: 32px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
}

.rc-shortcuts-close:hover {
    background: var(--slate-200, #e2e8f0);
    color: var(--slate-700, #334155);
}

.rc-shortcuts-list {
    margin: 0;
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 8px 16px;
    font-size: 13px;
}

.rc-shortcuts-list dt {
    margin: 0;
    text-align: right;
    color: var(--slate-700);
}

.rc-shortcuts-list dd {
    margin: 0;
    color: var(--slate-600);
}

.rc-shortcuts-list kbd {
    display: inline-block;
    padding: 1px 6px;
    background: var(--slate-100, #f1f5f9);
    border: 1px solid var(--slate-300, #cbd5e1);
    border-bottom-width: 2px;
    border-radius: 4px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 11px;
    color: var(--slate-700);
    line-height: 1.4;
}

body.dark-mode .rc-shortcuts-panel {
    background: var(--surface-secondary, #1e293b);
    border-color: var(--slate-700, #334155);
}

body.dark-mode .rc-shortcuts-header h3 { color: var(--slate-100, #f1f5f9); }
body.dark-mode .rc-shortcuts-list dt   { color: var(--slate-200, #e2e8f0); }
body.dark-mode .rc-shortcuts-list dd   { color: var(--slate-300, #cbd5e1); }
body.dark-mode .rc-shortcuts-list kbd {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-600, #475569);
    color: var(--slate-200, #e2e8f0);
}
body.dark-mode .rc-shortcuts-close {
    background: var(--slate-700, #334155);
    color: var(--slate-300, #cbd5e1);
}
body.dark-mode .rc-shortcuts-close:hover {
    background: var(--slate-600, #475569);
    color: var(--slate-100, #f1f5f9);
}

/* ============================================
   PROPOSAL DETAIL OVERLAY (View Details / see full details)
   ============================================ */
.rc-proposal-detail-overlay {
    position: fixed;
    inset: 0;
    z-index: var(--z-modal);
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(15, 23, 42, 0.45);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    padding: 16px;
}
.rc-pd-panel {
    background: var(--review-card-bg, #fff);
    border: 1px solid var(--review-card-border, rgba(203, 213, 225, 0.5));
    border-radius: var(--rc-radius-card, 8px);
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
    width: 92%;
    max-width: 480px;
    max-height: 86vh;
    display: flex;
    flex-direction: column;
}
.rc-pd-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border-color, #e2e8f0);
    flex-shrink: 0;
}
.rc-pd-header h3 {
    margin: 0;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary, #1e293b);
}
.rc-pd-close {
    background: var(--slate-100, #f1f5f9);
    color: var(--slate-500, #64748b);
    border: none;
    border-radius: var(--radius-full, 9999px);
    width: 32px;
    height: 32px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    flex-shrink: 0;
}
.rc-pd-close:hover { background: var(--slate-200, #e2e8f0); color: var(--slate-700, #334155); }
.rc-pd-body {
    padding: 16px 20px 20px;
    overflow-y: auto;
}
.rc-pd-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-bottom: 12px;
}
.rc-pd-status {
    font-size: 12px;
    font-weight: 600;
    padding: 2px 10px;
    border-radius: 9999px;
}
.rc-pd-status-open   { background: rgba(34, 197, 94, 0.16);  color: #15803d; }
.rc-pd-status-closed { background: rgba(148, 163, 184, 0.22); color: #475569; }
.rc-pd-status-expired{ background: rgba(239, 68, 68, 0.16);  color: #b91c1c; }
.rc-pd-deadline {
    font-size: 12px;
    color: var(--text-secondary, #64748b);
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.rc-pd-description {
    margin: 0 0 16px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-primary, #334155);
    white-space: pre-wrap;
}
.rc-pd-section-title {
    margin: 12px 0 8px;
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary, #64748b);
}
.rc-pd-slots { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.rc-pd-slot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 6px 10px;
    padding: 8px 10px;
    border: 1px solid var(--border-color, #e2e8f0);
    border-radius: 8px;
}
.rc-pd-slot.leading { border-color: rgba(34, 197, 94, 0.4); background: rgba(34, 197, 94, 0.05); }
.rc-pd-slot-when { font-size: 13px; font-weight: 500; color: var(--text-primary, #1e293b); display: inline-flex; align-items: center; gap: 6px; }
/* Standings medals (2026-08-06). Replaces the binary trophy: the leading time
   had one, and a close second looked identical to last place. Gold keeps the
   trophy so the winner still reads as the winner at a glance; 2nd/3rd take
   medals. Used on RESULTS rows only — the rank circles stay numbered, because
   they are an input and the number is what teaches "1 is your top choice".
   Metal tones are deliberately literal here; this is the one place in the app
   where gold/silver/bronze IS the meaning, so it does not borrow the status
   palette (green/amber/red never means "second place"). */
.rc-standing {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    flex-shrink: 0;
    line-height: 1;
}
.rc-standing--gold   { color: #d97706; }
.rc-standing--silver { color: #94a3b8; }
.rc-standing--bronze { color: #b45309; }
/* Bronze on a dark surface is nearly invisible at 11px, and silver goes muddy;
   lift both rather than leaving the runners-up unreadable in dark mode. */
body.dark-mode .rc-standing--gold   { color: #fbbf24; }
body.dark-mode .rc-standing--silver { color: #cbd5e1; }
body.dark-mode .rc-standing--bronze { color: #d97706; }
.rc-pd-trophy { color: #d97706; font-size: 11px; }
.rc-pd-slot-stats { display: inline-flex; align-items: center; gap: 10px; flex-shrink: 0; }
.rc-pd-empty { font-size: 13px; color: var(--text-secondary, #64748b); padding: 8px 2px; }
.rc-pd-roster { display: flex; flex-wrap: wrap; gap: 6px; }
.rc-pd-person {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 12px;
    font-weight: 500;
    padding: 3px 10px;
    border-radius: 9999px;
}
.rc-pd-person.voted   { background: rgba(34, 197, 94, 0.14);  color: #15803d; }
.rc-pd-person.pending { background: rgba(148, 163, 184, 0.18); color: #64748b; }
.rc-pd-roster-hint { margin-top: 8px; font-size: 12px; color: var(--text-secondary, #64748b); }

body.dark-mode .rc-pd-panel { background: var(--surface-secondary, #1e293b); border-color: var(--slate-700, #334155); }
body.dark-mode .rc-pd-header { border-color: var(--slate-700, #334155); }
body.dark-mode .rc-pd-header h3 { color: var(--slate-100, #f1f5f9); }
body.dark-mode .rc-pd-description { color: var(--slate-200, #e2e8f0); }
body.dark-mode .rc-pd-slot { border-color: var(--slate-700, #334155); }
body.dark-mode .rc-pd-slot-when { color: var(--slate-100, #f1f5f9); }
body.dark-mode .rc-pd-close { background: var(--slate-700, #334155); color: var(--slate-300, #cbd5e1); }
body.dark-mode .rc-pd-close:hover { background: var(--slate-600, #475569); color: var(--slate-100, #f1f5f9); }


/* Touch target floor for the review tab icons. (The old <=768px "collapse the
   review cluster to icon-only + wrap the toolbar to 2 rows" rules were removed
   2026-06-17: mobile now renders the whole app at a desktop width and scrolls the
   page — see "MOBILE = A DESKTOP-WIDTH APP" in style.css — so the toolbar keeps
   its one-row desktop layout with full labels and the stacked "Review" cluster.
   There's room for it, and it reads clearer than the collapsed/wrapped variants.) */
@media (max-width: 768px) {
  .review-icon-btn {
    min-width: 32px;
    min-height: 32px;
  }
}

/* ============================================
   REQUESTS TAB — pending join requests (admin)
   ============================================ */
.review-requests {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 4px 2px;
}

.review-request-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--border-color, #e2e8f0);
  border-radius: 12px;
  background: var(--card-bg, #fff);
}

.review-request-card .request-avatar {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--amber-100, #fef3c7);
  color: var(--amber-600, #d97706);
  font-size: 16px;
}

.review-request-card .request-body {
  flex: 1;
  min-width: 0;
}

.review-request-card .request-headline {
  margin: 0;
  font-size: 0.875rem;
  color: var(--text-primary, #334155);
  line-height: 1.4;
}

/* Identity lines on a join-request card (2026-08-14). The email IS the
   identity when display_name is null, so it must not read as throwaway
   metadata; and neither-name-nor-email must warn, because approving is an
   access-control decision. */
.review-request-card .request-email {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 3px;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--slate-600, #475569);
  overflow-wrap: anywhere;
}
.review-request-card .request-unidentified {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin-top: 5px;
  padding: 5px 8px;
  border-radius: var(--rc-radius-btn, 6px);
  background: var(--rc-attention-surface, #fff7ed);
  color: var(--rc-attention-ink, #7c2d12);
  font-size: 0.72rem;
  line-height: 1.35;
}
body.dark-mode .review-request-card .request-email { color: var(--slate-300, #cbd5e1); }

.review-request-card .request-when {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: 3px;
  font-size: 0.72rem;
  color: var(--slate-500, #64748b);
}

.review-request-card .request-actions {
  display: flex;
  gap: 8px;
  flex-shrink: 0;
}

.review-request-card .request-actions .btn {
  padding: 6px 12px;
  font-size: 0.8rem;
  white-space: nowrap;
}

body.dark-mode .review-request-card {
  background: var(--slate-800, #1e293b);
  border-color: var(--slate-700, #334155);
}

body.dark-mode .review-request-card .request-headline {
  color: var(--slate-100, #f1f5f9);
}

body.dark-mode .review-request-card .request-avatar {
  background: rgba(217, 119, 6, 0.2);
  color: var(--amber-300, #fcd34d);
}

/* On narrow screens the actions wrap below the headline. */
@media (max-width: 520px) {
  .review-request-card {
    flex-wrap: wrap;
  }
  .review-request-card .request-actions {
    width: 100%;
    justify-content: flex-end;
  }
}

/* ── Live-update banner ──────────────────────────────────────────────────
   Surfaces realtime changes from teammates WITHOUT repainting the list
   underneath a half-made decision. Re-rendering on every incoming event
   moves the row the user is reaching for, so the refresh is offered rather
   than forced. Sits at the top of the tab panel; removed on apply, dismiss,
   or any real re-render. (2026-07-29) */
.rc-live-update-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  margin-bottom: 12px;
  border: 1px solid var(--primary-500, #14b8a6);
  border-radius: var(--radius-md, 8px);
  background: rgba(20, 184, 166, 0.08);
  font-size: 0.875rem;
}

.rc-live-update-text {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
  color: var(--slate-700, #334155);
}

.rc-live-update-banner .btn.rc-live-update-apply {
  flex-shrink: 0;
  padding: 4px 12px;
  font-size: 0.8125rem;
}

.rc-live-update-dismiss {
  flex-shrink: 0;
  background: none;
  border: none;
  cursor: pointer;
  padding: 4px 6px;
  border-radius: var(--radius-sm, 4px);
  color: var(--slate-500, #64748b);
  line-height: 1;
}

.rc-live-update-dismiss:hover { color: var(--slate-700, #334155); }
.rc-live-update-dismiss:focus-visible,
.rc-live-update-banner .btn.rc-live-update-apply:focus-visible {
  outline: 2px solid var(--primary-500, #14b8a6);
  outline-offset: 2px;
}

body.dark-mode .rc-live-update-banner {
  background: rgba(20, 184, 166, 0.12);
  border-color: var(--primary-500, #14b8a6);
}

body.dark-mode .rc-live-update-text { color: var(--slate-100, #f1f5f9); }
body.dark-mode .rc-live-update-dismiss { color: var(--slate-400, #94a3b8); }
body.dark-mode .rc-live-update-dismiss:hover { color: var(--slate-100, #f1f5f9); }

/* Narrow screens: let the text wrap above the actions rather than squashing
   the Refresh button to an unreadable width. */
@media (max-width: 520px) {
  .rc-live-update-banner { flex-wrap: wrap; }
  .rc-live-update-text { width: 100%; }
}

/* ── CONDENSED "My Proposals" CARD (2026-07-30) ─────────────────────────────
   User: "seems visually inconsistent to my typical well laid out minimalist
   vibes. perhaps too many colours and info. consider what can be condensed or
   hidden."

   The card was competing with itself — SIX colours and FOUR overlapping status
   signals that all said the same thing before anyone voted. These rules support
   the markup changes in renderMyProposalCard(): type as a glyph, times
   collapsed until there is something to compare, secondary actions in a ⋯ menu.
   Deliberately NO new colour: everything here is neutral so the turnout bar and
   an urgent deadline stay the only things that can shout. */

/* Event type: a muted glyph, not a coloured chip. */
.rc-type-glyph {
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-400);
    margin-right: 6px;
    flex: 0 0 auto;
}

/* Collapsed time list — one option plus a "+N more" affordance. */
.my-proposal-times.times-collapsed .times-list {
    gap: 4px;
}

.times-more-btn {
    align-self: flex-start;
    background: none;
    border: none;
    padding: 2px 0;
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 600;
    color: var(--slate-500);
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.times-more-btn:hover { color: var(--slate-700); }

/* Single action row: primary on the right, everything else behind ⋯ */
.rc-actions-condensed .my-proposal-actions-right {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
}

.rc-overflow-wrap { position: relative; display: inline-flex; }

.rc-overflow-btn {
    padding: 6px 10px;
    line-height: 1;
    color: var(--slate-500);
}

.rc-overflow-btn:hover { color: var(--slate-700); }

.rc-overflow-menu {
    position: absolute;
    right: 0;
    bottom: calc(100% + 6px);
    min-width: 168px;
    background: #fff;
    border: 1px solid var(--slate-200, #e2e8f0);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
    padding: 4px;
    z-index: 30;
    display: flex;
    flex-direction: column;
}

.rc-overflow-menu[hidden] { display: none; }

.rc-overflow-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 10px;
    background: none;
    border: none;
    border-radius: 7px;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--slate-700);
    text-align: left;
    cursor: pointer;
}

.rc-overflow-item:hover { background: var(--slate-100, #f1f5f9); }

.rc-overflow-item.rc-overflow-danger { color: var(--rc-status-busy, #dc2626); }

body.dark-mode .rc-overflow-menu {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
}

body.dark-mode .rc-overflow-item { color: var(--slate-200, #e2e8f0); }
body.dark-mode .rc-overflow-item:hover { background: var(--slate-700, #334155); }

/* ═══════════════════════════════════════════════════════════════════════
   REVIEW CENTER — DENSITY PASS (2026-08-04)
   User: "redesign review center with a more logical and less space wasting
   layout, space should focus on useful info."

   Measured on a 430px viewport BEFORE this pass: a single proposal card was
   300px tall, of which ~180px carried no signal:
     .proposal-header          109px  (a "Deadline: No deadline" line, mostly)
     .proposal-closed-summary   62px  (one sentence, boxed + padded)
     .proposal-vote-summary     12px  (rendered EMPTY)
     .proposal-options-section   0px  (collapsed, contributing nothing)
   Four cards filled the screen and the user could not scan their queue.

   The rules below are DENSITY ONLY — no colour, no hierarchy, no behaviour
   changes. Every one targets measured dead space, and the strongest cuts are
   scoped to EXPIRED cards, which are pure backlog: they carry no decision, so
   they collapse to a scannable one-liner while live cards keep full detail.
   ═══════════════════════════════════════════════════════════════════════ */

/* 1. Kill the empty vote-summary box. It reserves height even with no content,
      once per card, purely as a spacer. */
.proposal-vote-summary:empty {
    display: none !important;
}

/* 2. "Deadline: No deadline" is an absence of information taking a full line.
      Suppress the label when there is no deadline; a real deadline still shows. */
.proposal-deadline-area:has(.proposal-deadline-label) {
    display: none !important;
}

/* 3. The closed/expired summary is one sentence in a padded, bordered card.
      Keep the sentence, drop the box. */
.proposal-closed-summary {
    padding: 6px 8px !important;
    margin: 4px 0 !important;
    gap: 6px !important;
}
.proposal-closed-summary .proposal-closed-sub,
.proposal-closed-summary p + p {
    font-size: 0.75rem !important;
}

/* 4. EXPIRED cards collapse to a scannable row: title, who, and Dismiss.
      An expired proposal has no decision left, so the explanatory sentence and
      the meta line are noise — the "Expired" tag already says everything. */
.proposal-item.proposal-expired .proposal-closed-summary,
.proposal-item.proposal-expired .proposal-meta-line,
.proposal-item.proposal-expired .proposal-status-line,
.proposal-item.proposal-expired .proposal-vote-summary {
    display: none !important;
}
.proposal-item.proposal-expired {
    padding: 8px 10px !important;
    margin-bottom: 6px !important;
}
.proposal-item.proposal-expired .proposal-header {
    margin-bottom: 0 !important;
    padding-bottom: 0 !important;
}
/* Actions sit inline on the collapsed row rather than owning their own band. */
.proposal-item.proposal-expired .proposal-actions {
    margin-top: 4px !important;
    padding-top: 0 !important;
    border-top: 0 !important;
}

/* 5. Tighten the shared card frame. 300px -> the content's real height. */
.proposal-item {
    padding: 10px 12px;
    margin-bottom: 8px;
}
.proposal-item .proposal-header {
    margin-bottom: 6px;
}
.proposal-item .proposal-title-row {
    gap: 6px;
    margin-bottom: 4px;
}
.proposal-item .proposal-meta-line {
    margin-bottom: 4px;
}

/* 6. The tab strip was 92px on a 430px screen — a quarter of the viewport
      above the first card. Bring it back to a single scannable row. */
.review-tabs,
.rc-tabrow {
    padding-top: 4px !important;
    padding-bottom: 4px !important;
    row-gap: 4px !important;
}

/* 7. The priority badge floated as a 24px square in its own gutter. Keep it
      legible but stop it reserving a column of whitespace. */
.proposal-priority-badge {
    width: 18px !important;
    height: 18px !important;
    font-size: 0.6875rem !important;
}


/* ============================================================
   TWO-ROW STRIP — PHONE (2026-08-04)
   ============================================================
   Appended last so these win over the older per-breakpoint patches without
   having to unpick each one.

   The goal on a phone is that NOTHING IS LOST, only compacted. The previous
   approach hid filters outright below 480px, trading function for width; with
   the two-row split there IS width to spend, so every control survives in a
   smaller form.

   Net at 390px: one 44px nav row + one 36px tool row, versus the old single row
   that wrapped to two or three depending on label lengths.
   ============================================================ */
@media (max-width: 480px) {
    .rc-navrow { gap: 6px; }

    /* Sync is a DESKTOP power action: the Review Center already refreshes on
       its own sync events, so a manual refresh button is redundant chrome on a
       phone. Hidden here and surfaced in the overflow menu instead (see
       #rdh-sync-item), which leaves exactly ONE right-side control on a phone —
       Close — the only one that is always needed. */
    .rc-navrow .rdh-actions #rdh-sync-btn { display: none; }

    /* ⋯ MUST NOT GET A ROW OF ITS OWN (2026-08-29, user: "we have a whole row
       for a 3 dot menu?").
       ------------------------------------------------------------------
       MEASURED at 390px before this rule: the nav row was 100px tall, not the
       44px this two-row design intends, and the overflow button sat at
       top:70px / left:18px — a full line containing nothing but "⋯" and ~340px
       of empty space, while Close stayed on line 1 at top:24px.

       Cause: the legacy single-row patches (~9695 and ~10003) set
       `.rc-tabrow .rdh-actions { display: contents }` to dissolve the action
       cluster so its children could be ORDERED individually across a wrapping
       row. .rc-navrow is also a .rc-tabrow and is `flex-wrap: wrap`, so those
       children became independent flex items that wrap SEPARATELY — the button
       group stopped being a group. Nothing pinned them back together, so the
       first one that did not fit took a new line alone.

       Restore the cluster as ONE unwrappable box on the phone strip. It is a
       button group; it should break as a unit or not at all. This also re-nests
       .rdh-overflow inside a positioned parent, which is where its dropdown
       expects to anchor from. */
    .rc-navrow .rdh-actions {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        flex: 0 0 auto;
        flex-wrap: nowrap;
        margin-left: auto;
    }
    /* The tab strip is the only elastic thing here, so it absorbs the width the
       cluster needs instead of pushing the cluster onto a second line. It
       already scrolls horizontally, so yielding width costs no tabs. */
    .rc-navrow .review-tabs { flex: 1 1 0%; min-width: 0; }

    /* And the row itself does not wrap AT ALL on a phone. The comment block
       above this media query promises "one 44px nav row"; `flex-wrap: wrap`
       (inherited from the legacy single-row patches) made that a hope rather
       than a rule, and any group that did not fit silently bought a new line.
       With the tab strip elastic and scrollable, there is always a valid
       single-line solution, so forbid the wrap and let the tabs absorb the
       pressure. */
    .rc-navrow { flex-wrap: nowrap; }
    /* The brand shrinks before anything else — it is the only purely decorative
       item in the row, and its text already clips to an icon at narrow widths. */
    .rc-navrow .rdh-title { flex: 0 1 auto; min-width: 0; overflow: hidden; }

    /* NEUTRALISE THE LEGACY ORDER LADDER inside the restored cluster.
       ------------------------------------------------------------------
       The single-row design gave each dissolved child its own slot on one
       wrapping line: title 1, tabs 2, close 3, controls 4, overflow 6. Those
       numbers only ever made sense while the children WERE the flex items.
       Now that .rdh-actions is a box again they resolve against its internal
       axis instead, which sorted Close (3) ahead of ⋯ (6) inside the cluster
       and — because the cluster itself carries no order, defaulting to 0 — put
       the whole group BEFORE the tabs. Measured: ⋯ and Close rendered at the
       far LEFT of the strip, ahead of "Events".
       Reset to source order and let `margin-left: auto` (above) do the
       positioning, which is the two-row design's actual intent. */
    .rc-navrow .rdh-actions,
    .rc-navrow .rdh-title,
    .rc-navrow .review-tabs,
    .rc-navrow .rdh-actions > *,
    .rc-navrow #close-review-modal,
    .rc-navrow .rdh-overflow { order: 0; }

    .rc-toolrow { gap: 6px; }

    /* Filters collapses to an ICON + active-count badge. The LABEL is what
       costs width, not the control, so the label goes and the affordance stays
       — and the count badge makes active filters more visible than the old
       single dot, not less. */
    .rc-toolrow .rc-filters-btn-label,
    .rc-toolrow .rc-filters-btn-chevron { display: none; }
    .rc-toolrow .rc-filters-btn {
        min-width: 40px;
        justify-content: center;
        padding-left: 10px;
        padding-right: 10px;
    }

    /* Triage segments keep their COUNTS (the actionable part) and drop their
       word labels, so "3 conflicts" reads as a red 3 beside its icon. The
       accessible name on each segment already carries the full phrase. */
    .rc-toolrow .rc-triage-label { display: none; }
    .rc-toolrow .rc-triage-seg {
        padding-left: 8px;
        padding-right: 8px;
    }
}

/* Very narrow (<=360px): tab labels give way to icons + badges. The tab row
   scrolls rather than wraps (see .rc-navrow .review-tabs), so this is a
   legibility choice, not a rescue — three icon tabs read cleanly at this width
   where three labelled pills do not. Each tab button carries its full name in
   aria-label, so assistive tech loses nothing. */
@media (max-width: 360px) {
    .rc-navrow .review-tab .tab-label { display: none; }
    .rc-navrow .review-tab {
        padding-left: 10px;
        padding-right: 10px;
    }
}

/* ============================================================
   FILTERS ACTIVE-COUNT BADGE (2026-08-04)
   ============================================================
   Replaces the bare `.rc-filter-dot` on the Filters button. The dot could only
   say "something is filtered"; once the button collapses to an icon on a phone
   that was not enough. Derives from the same --primary-* tokens as the dot it
   replaces, so it reads as the established "this control is active" signal
   rather than a new vocabulary.
   ============================================================ */
.rc-filters-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    margin-left: 2px;
    border-radius: var(--radius-full, 9999px);
    background: var(--primary-500, #14b8a6);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    flex-shrink: 0;
}
/* Collapsed (icon-only) state: the badge rides the button's top-right corner
   the way the dot did, so it never widens the 40px touch target. */
@media (max-width: 480px) {
    .rc-toolrow .rc-filters-btn { position: relative; }
    .rc-toolrow .rc-filters-count {
        position: absolute;
        top: -4px;
        right: -4px;
        margin-left: 0;
        box-shadow: 0 0 0 2px var(--surface-primary, #fff);
    }
    body.dark-mode .rc-toolrow .rc-filters-count {
        box-shadow: 0 0 0 2px var(--slate-800, #1e293b);
    }
}

/* ============================================================
   PRIVACY SWEEP — collapsed by default (2026-08-04 redesign)
   ============================================================
   The sweep is now a <details> (review-dashboard.js renderPrivacyTab). It was a
   permanent three-button band sitting between the filter chips and the first
   event, on a tab that already stacked five bands of chrome before any content
   — and it is the most destructive control here, rewriting the visibility of
   the whole queue in one tap. At rest it is a single summary line; the buttons
   appear on demand.

   The base `.synced-sweep-bar` rule sets display:flex, which on a <details>
   element lays the summary and the content out as siblings on one row and
   defeats the collapse entirely. Override back to block and let the summary own
   the row instead.
   ============================================================ */
.synced-sweep-details {
    display: block;
    padding: 0;
}
.synced-sweep-summary {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    cursor: pointer;
    list-style: none;              /* hide the native triangle; we ship a chevron */
    -webkit-tap-highlight-color: transparent;
}
.synced-sweep-summary::-webkit-details-marker { display: none; }
.synced-sweep-summary:hover .synced-sweep-label {
    color: var(--text-primary, #0f172a);
}
.synced-sweep-summary:focus-visible {
    outline: 2px solid var(--focus-ring, #2dd4bf);
    outline-offset: -2px;
}
.synced-sweep-chev {
    margin-left: auto;
    font-size: 11px;
    color: var(--text-secondary, #64748b);
    transition: transform 0.18s ease;
}
.synced-sweep-details[open] .synced-sweep-chev {
    transform: rotate(180deg);
}
/* The buttons only exist while open, so they carry the row padding themselves
   rather than inheriting a band that is visible at rest. */
.synced-sweep-details[open] {
    padding-bottom: 10px;
}
.synced-sweep-details > .synced-sweep-btn,
.synced-sweep-details > .synced-split-hint {
    margin-left: 14px;
    margin-right: 0;
}
@media (prefers-reduced-motion: reduce) {
    .synced-sweep-chev { transition: none; }
}

/* ============================================================
   RULES + POLICY as overflow-menu items (2026-08-04 redesign)
   ============================================================
   Both moved out of the chip row and into the ⋯ menu — they are board SETTINGS,
   not per-decision controls, and that band sat directly above the queue. They
   keep their original classes for behaviour and gain `.rdh-overflow-item` for
   layout, so these rules only need to neutralise the chip-shaped chrome (pill
   border, inline width) that would otherwise look wrong in a menu column.
   ============================================================ */
.rdh-overflow-item.privacy-rules-chip,
.rdh-overflow-item .privacy-policy-chip {
    width: 100%;
    justify-content: flex-start;
    border: none;
    border-radius: 0;
    background: transparent;
}
.rdh-overflow-item.privacy-policy-chip-wrap {
    display: block;
    width: 100%;
    position: relative;
}
/* The policy popover is anchored to its wrapper, which now lives inside the
   menu — pull it clear of the menu's own bounds so it is not clipped. */
.rdh-overflow-item .privacy-policy-popover {
    right: 0;
    left: auto;
    min-width: 240px;
    z-index: 10;
}

/* ============================================================================
   PRIVACY: CHIPS IN THE TOOL ROW  (2026-08-07)
   User: "couldn't the third tab row go in the space where search is then if you
   click search it appears in its place on Mobile".

   The chips used to be a third stacked band inside the tab body, under a
   control row that on Privacy rendered essentially empty (a collapsed search
   icon and the overflow menu). Three chips squeezed into that leftover width
   truncated "Recent" to "Rece". They now ride the control row itself, so the
   band earns its space and the chips get the full row width.

   The body-band chrome (panel background, bottom border, block padding) is
   dropped in this context: it is an inline control group now, not a section.
   ========================================================================== */
.rc-toolrow .privacy-chip-row {
    flex: 0 1 auto;
    min-width: 0;
    padding: 0;
    gap: 6px;
    background: none;
    border-bottom: 0;
    overflow: hidden;
}
.rc-toolrow-chips .rc-inline-controls {
    flex: 0 0 auto;
    margin-left: auto;
}

/* MOBILE: search takes the row, chips step aside.
   The chips are the row's content, so an expanding input has nowhere to go: it
   would either squash them into unreadable slivers or push them off-screen.
   Instead the input claims the full row and the chips collapse out. This is
   phone-only. On desktop there is width for both, and the swap would be motion
   without purpose. */
@media (max-width: 640px) {
    .rc-toolrow-chips {
        position: relative;
        flex-wrap: nowrap;
    }
    .rc-toolrow-chips .privacy-chip-row {
        flex: 1 1 auto;
        transition: opacity 0.15s ease, max-width 0.2s ease;
        max-width: 100%;
        opacity: 1;
        /* ⭐2026-08-20 second pass (owner screenshot: the Done chip half-hidden
           behind the search button). The row shares ONE nowrap line with the
           inline search, so `flex: 1 1 auto` shrinks it to whatever search
           leaves — measured 279px of box for 336px of chips, which CLIPPED
           "Done 18" at the right edge. min-width:0 is what actually lets a
           flex child shrink BELOW its content and hand the overflow to its own
           scroller (without it the box is pinned at content width and the
           excess is simply cut). Paired with the horizontal scroll + edge fade
           declared in the ≤640 block above, so every chip stays reachable by
           swipe instead of disappearing under the search circle. */
        min-width: 0;
        overflow-x: auto;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
    }
    .rc-toolrow-chips .privacy-chip-row::-webkit-scrollbar { display: none; }
    /* The trailing chip needs breathing room so it is not visually tucked
       under the search control the instant it scrolls into view. */
    .rc-toolrow-chips .privacy-chip-row > .privacy-filter-chip:last-child {
        margin-right: 6px;
    }
    /* Collapse the chips only while the search input is actually open. */
    .rc-toolrow-chips:has(.rc-search-inline.rc-search-open) .privacy-chip-row {
        max-width: 0;
        opacity: 0;
        pointer-events: none;
    }
    .rc-toolrow-chips:has(.rc-search-inline.rc-search-open) .rc-inline-controls {
        flex: 1 1 auto;
        margin-left: 0;
    }
    .rc-toolrow-chips:has(.rc-search-inline.rc-search-open) .rc-search-inline {
        flex: 1 1 auto;
        width: 100%;
    }
    .rc-toolrow-chips .rc-search-inline.rc-search-open .rc-search-input-wrap {
        max-width: 100%;
        flex: 1 1 auto;
    }
    .rc-toolrow-chips .rc-search-inline.rc-search-open .rc-search-input {
        width: 100%;
        max-width: none;
    }
    /* :has() fallback: without it the chips simply stay put and the input opens
       to its normal 180px beside them. Degraded, not broken. */
}

/* The active-filter pill shown INSIDE the expanded search field.
   Hiding the chips hides which filter is narrowing the list, which would
   recreate exactly the "list is short and nothing says why" problem the filter
   count badge exists to prevent. So the active non-default filter rides along
   as a dismissible pill. */
.rc-search-active-filter {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex-shrink: 0;
    margin-left: 6px;
    padding: 3px 8px;
    border-radius: var(--radius-full, 9999px);
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--visibility-private, #7c3aed);
    background: rgba(139, 92, 246, 0.12);
    border: 1px solid rgba(139, 92, 246, 0.3);
    cursor: pointer;
}
.rc-search-active-filter:hover { background: rgba(139, 92, 246, 0.2); }
.rc-search-active-filter i { font-size: 9px; }
body.dark-mode .rc-search-active-filter {
    color: #c4b5fd;
    background: rgba(139, 92, 246, 0.22);
    border-color: rgba(139, 92, 246, 0.45);
}

/* ============================================================================
   PRIVACY: BATCH ASSIGN  (2026-08-07)
   Replaces the "Mark all N as:" sweep. Tick, assign, then one confirm.
   ========================================================================== */
.privacy-source-row {
    display: flex; align-items: center; gap: 8px;
    padding: 8px 14px 0;
}
/* The bulk controls, now the FIRST band of the bottom confirmation step
   (2026-08-27). Was .privacy-batch-bar, a non-sticky strip above the list:
   on mobile it scrolled out of reach as soon as you began deciding rows, so
   the batch had controls you could not get back to and a commit you could not
   see. The step below the list owns them now — see .privacy-final-confirm. */
.privacy-final-controls {
    display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
    padding-bottom: 12px;
    margin-bottom: 12px;
    border-bottom: 1px solid var(--border-color, #e2e8f0);
}
.privacy-batch-select {
    display: flex; align-items: center; gap: 10px;
    flex: 1 1 auto; min-width: 0;
}
.privacy-batch-selectall {
    display: inline-flex; align-items: center; gap: 7px;
    font-size: 0.85rem; color: var(--text-secondary, #64748b);
    cursor: pointer; white-space: nowrap;
}
.privacy-batch-selectall input[type="checkbox"] {
    width: 16px; height: 16px; cursor: pointer;
    accent-color: var(--visibility-private, #8b5cf6);
}
.privacy-batch-selectall-matching {
    background: none; border: 0; padding: 0;
    font-size: 0.8rem; font-weight: 600;
    color: var(--accent, #0284c7);
    cursor: pointer; text-decoration: underline;
    white-space: nowrap;
}
/* THE BATCH TRIPLET MUST NOT READ AS A FOURTH ROW (2026-08-11).
 *
 * The bar already has its own tint and border, but its Private/Busy/Shared
 * buttons are the same size, border and type scale as the three per-row
 * buttons directly beneath them — so the column reads as FOUR identical
 * triplets, one of which silently acts on every ticked row. Measured: batch
 * stamp 85x30 with a 0.667px slate border and 13.6px text; per-row button
 * 85x30 with the same border and the same 13.6px text.
 *
 * For a control whose mistake is irreversible (loosening visibility cannot be
 * un-seen), "looks like the thing next to it" is the wrong default. Label the
 * group and bind it visually to the bar rather than to the rows: a leading
 * caption states the scope in words, and a hairline rule closes the group so
 * the eye reads it as one control, not three loose buttons in a column. */
.privacy-batch-actions {
    display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
    padding-left: 10px;
    border-left: 2px solid var(--visibility-private, #8b5cf6);
}
.privacy-batch-actions-label {
    font-size: 0.72rem; font-weight: 700; letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--text-secondary, #64748b);
    white-space: nowrap; margin-right: 2px;
}
/* When nothing is ticked the whole group is inert; say so once, on the group,
   instead of relying on three separately-dimmed buttons. */
.privacy-batch-actions[data-armed="false"] { border-left-color: var(--border-color, #cbd5e1); }
.privacy-batch-actions[data-armed="false"] .privacy-batch-actions-label { opacity: 0.6; }
.privacy-batch-stamp {
    padding: 6px 12px; border-radius: 6px;
    border: 1px solid var(--border-color, #cbd5e1);
    background: var(--bg-primary, #fff); cursor: pointer;
    font-size: 0.85rem; line-height: 1.2;
    color: var(--text-primary, #0f172a);
    transition: background 0.12s ease, border-color 0.12s ease, opacity 0.12s ease;
}
.privacy-batch-stamp i { font-size: 11px; }
.privacy-batch-stamp[data-batch-stamp="hidden"] i { color: var(--visibility-private, #8b5cf6); }
.privacy-batch-stamp[data-batch-stamp="busy"] i   { color: var(--rc-status-tentative); }
.privacy-batch-stamp[data-batch-stamp="full"] i   { color: var(--rc-status-available); }
.privacy-batch-stamp:hover:not(:disabled) {
    background: var(--bg-secondary, #f1f5f9);
    border-color: var(--accent, #0284c7);
}
.privacy-batch-stamp:disabled { opacity: 0.45; cursor: not-allowed; }
.privacy-batch-stamp:focus-visible {
    outline: 2px solid var(--accent, #0284c7); outline-offset: 2px;
}
/* (.privacy-batch-commit / -staged / -tally / -review / -discard were REMOVED
   2026-08-27 with the top bar. The per-level tally they styled is superseded
   by the grouped readback in the confirm card, which names the events as well
   as counting them; the commit itself is .privacy-final-apply below.) */

/* Row tick + staged verdict. The verdict shows ON the row because a mixed
   batch is unreadable if the only record of what you assigned is a total. */
.synced-row-check { display: inline-flex; align-items: center; flex-shrink: 0; }
.synced-row-check input[type="checkbox"] {
    width: 16px; height: 16px; cursor: pointer;
    accent-color: var(--visibility-private, #8b5cf6);
}
.synced-row-ticked { background: rgba(139, 92, 246, 0.05); }
.synced-row-has-staged { border-left: 3px solid var(--visibility-private, #8b5cf6); }
.synced-row-staged {
    display: inline-flex; align-items: center; gap: 4px;
    margin-left: 8px; padding: 2px 8px;
    border-radius: var(--radius-full, 9999px);
    font-size: 0.72rem; font-weight: 600;
    vertical-align: middle;
}
.synced-row-staged i { font-size: 9px; }
.synced-row-staged-hidden {
    color: #7c3aed; background: rgba(139, 92, 246, 0.12);
}
.synced-row-staged-busy {
    color: #b45309; background: rgba(245, 158, 11, 0.14);
}
.synced-row-staged-full {
    color: #047857; background: rgba(16, 185, 129, 0.14);
}

/* The commit confirm card. Same three-section structure as the send-proposal
   summary (.propose-confirm-summary) because it answers the same question. */
.privacy-confirm-summary { text-align: left; }
.privacy-confirm-scope {
    font-size: 0.9rem; color: var(--text-secondary, #64748b);
    margin-bottom: 10px;
}
/* SCROLL THE READBACK, NOT THE PAGE (2026-08-29, user: "Review selections
   perhaps needs a scroll for large selections").
   Each group is ~92px and all three can be populated at once, so a mixed batch
   pushed the Discard/Apply pair below the fold — the readback grew until the
   controls it exists to introduce were off-screen, and the user had to scroll
   past the summary to reach the commit. Cap the list and let IT scroll, so the
   card's own height is bounded and the actions stay put. 46vh keeps at least
   two groups fully visible on a phone before scrolling starts. */
.privacy-confirm-groups {
    list-style: none; margin: 0; padding: 0;
    max-height: 46vh;
    overflow-y: auto;
    /* A hairline of padding so a group's focus ring / border is not shaved by
       the scroll container's edge. */
    padding-right: 2px;
    overscroll-behavior: contain;
}
/* Only decorate the track when it is actually scrollable, so short batches
   (the common case) show no scrollbar chrome at all. */
.privacy-confirm-groups { scrollbar-width: thin; }
.privacy-confirm-groups::-webkit-scrollbar { width: 8px; }
.privacy-confirm-groups::-webkit-scrollbar-thumb {
    background: rgba(148, 163, 184, 0.5);
    border-radius: 999px;
}
.privacy-confirm-groups::-webkit-scrollbar-track { background: transparent; }
body.dark-mode .privacy-confirm-groups::-webkit-scrollbar-thumb {
    background: rgba(148, 163, 184, 0.35);
}
.privacy-confirm-group {
    padding: 10px 12px; border-radius: 8px;
    border: 1px solid var(--border-color, #e2e8f0);
    margin-bottom: 8px;
    background: var(--bg-secondary, #f8fafc);
}
/* Shared is the section that needs reading, so it carries the most weight:
   loosest first, and visibly so. */
.privacy-confirm-group-full {
    border-color: rgba(16, 185, 129, 0.4);
    background: rgba(16, 185, 129, 0.07);
}
.privacy-confirm-group-busy { border-color: rgba(245, 158, 11, 0.35); }
/* ONE REAL ICON COLUMN (2026-08-29, user: "Alignment of the visibility summary
   needs perfecting").
   The heading was a flex row (icon + gap:7px + label) while the two lines under
   it faked the same indent with a hardcoded `margin-left: 22px`. Those are two
   different measurements of the same column and they never agreed: the icons
   are Font Awesome glyphs of DIFFERENT natural widths (fa-eye is wider than
   fa-clock, which is wider than fa-eye-slash), so the heading text started at a
   different x per group while the description and names all started at a fixed
   22px. Result: in a three-group summary nothing shared a left edge, and within
   a group the title sat proud of its own body text.

   Replace both with a single grid whose first track is a FIXED icon column, so
   the icon is centred in it and every text line — heading, description, names —
   starts on the exact same edge in every group regardless of glyph. */
.privacy-confirm-group {
    display: grid;
    grid-template-columns: 15px 1fr;
    column-gap: 7px;
    align-items: start;
}
.privacy-confirm-group-head {
    display: contents;
}
.privacy-confirm-group-head i {
    grid-column: 1;
    /* Centre each glyph inside the fixed track and pin it to the cap-height of
       the label beside it, so wide and narrow icons sit identically. */
    justify-self: center;
    line-height: 1.35;
    font-size: 0.85rem;
}
.privacy-confirm-group-head strong {
    grid-column: 2;
    font-size: 0.9rem; color: var(--text-primary, #0f172a);
    line-height: 1.35;
}
.privacy-confirm-group-full .privacy-confirm-group-head i { color: var(--rc-status-available); }
.privacy-confirm-group-busy .privacy-confirm-group-head i { color: var(--rc-status-tentative); }
.privacy-confirm-group-hidden .privacy-confirm-group-head i { color: var(--visibility-private, #8b5cf6); }
/* Both body lines occupy the TEXT column, so the 22px guess is gone and the
   indent is whatever the grid says it is — one source of truth. */
.privacy-confirm-group-desc {
    grid-column: 2;
    font-size: 0.78rem; color: var(--text-secondary, #64748b);
    margin: 2px 0 6px;
}
.privacy-confirm-group-names {
    grid-column: 2;
    font-size: 0.82rem; color: var(--text-primary, #0f172a);
    line-height: 1.5;
    /* Long titles wrap inside the column instead of pushing it wider. */
    min-width: 0;
    overflow-wrap: anywhere;
}
.privacy-confirm-rec, .privacy-confirm-more {
    font-size: 0.72rem; font-weight: 600;
    color: var(--text-secondary, #64748b);
}
.privacy-confirm-rec {
    padding: 1px 6px; border-radius: var(--radius-full, 9999px);
    background: rgba(100, 116, 139, 0.14);
}
.privacy-confirm-next {
    display: flex; align-items: flex-start; gap: 8px;
    padding-top: 10px; margin-top: 4px;
    border-top: 1px solid var(--border-color, #e2e8f0);
    font-size: 0.82rem; color: var(--text-secondary, #64748b);
}
.privacy-confirm-warn { color: #b45309; }
.privacy-confirm-warn i { color: var(--rc-status-tentative); margin-top: 2px; }

body.dark-mode .privacy-final-controls { border-bottom-color: var(--slate-700, #334155); }
body.dark-mode .privacy-batch-stamp {
    background: var(--slate-900, #0f172a);
    border-color: var(--slate-600, #475569);
    color: var(--slate-100, #f1f5f9);
}
body.dark-mode .privacy-batch-stamp:hover:not(:disabled) { background: var(--slate-700, #334155); }
body.dark-mode .synced-row-ticked { background: rgba(139, 92, 246, 0.12); }
body.dark-mode .privacy-confirm-group {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
}
body.dark-mode .privacy-confirm-group-full {
    background: rgba(16, 185, 129, 0.12);
    border-color: rgba(16, 185, 129, 0.45);
}
body.dark-mode .privacy-confirm-group-names { color: var(--slate-100, #f1f5f9); }
body.dark-mode .privacy-confirm-next { border-top-color: var(--slate-700, #334155); }
body.dark-mode .privacy-confirm-warn { color: #fbbf24; }

/* PHONE: ONE LEFT EDGE (2026-08-25, user: "the alignment on mobile is wrong").
 *
 * The bar stayed `flex-wrap: wrap` and faked rows with `flex: 1 1 100%`, so the
 * stamp group kept the desktop grouping chrome that binds the triplet
 * HORIZONTALLY: a 2px left rule plus 10px padding-left. Stacked, that is a 12px
 * indent on the middle row only. Measured at 390px: the checkbox and the Review
 * button start at x=14.7, the "SET SELECTED TO" caption at x=26.7 - three rows
 * on two different left edges. The rule itself, which closes the group when the
 * buttons sit beside it, degrades to a 2px orphan tick in the margin once the
 * group is full width.
 *
 * Column + stretch is the idiom the Events batch bar already uses
 * (.rc-batch-bar-active at <=768px), so batch mode reads the same across tabs.
 *
 * The scope caption STAYS - it is load-bearing (see the .privacy-batch-actions
 * note: without it the triplet reads as a fourth per-row triplet while acting
 * on every ticked event) - but moves to its own line so the three buttons split
 * the full width evenly instead of sharing a row with a 99px caption. */
@media (max-width: 640px) {
    .privacy-final-controls {
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
    }
    .privacy-batch-select { flex: 0 0 auto; }
    /* Full-width group: the left rule would now be a stray tick, so the accent
       moves to the top edge where it still closes the group. */
    .privacy-batch-actions {
        flex: 0 0 auto;
        flex-wrap: wrap;
        gap: 6px;
        padding-left: 0;
        padding-top: 8px;
        border-left: 0;
        border-top: 2px solid var(--visibility-private, #8b5cf6);
    }
    .privacy-batch-actions[data-armed="false"] {
        border-left-color: transparent;
        border-top-color: var(--border-color, #cbd5e1);
    }
    .privacy-batch-actions-label { flex: 1 0 100%; margin-right: 0; }
    .privacy-batch-actions .privacy-batch-stamp { flex: 1; text-align: center; }
    .synced-row-staged { margin-left: 0; margin-top: 3px; }

    /* PRIVACY ROW = TWO BANDS, NOT THREE (2026-08-25, user: "there is spare
       space on mobile privacy can we bring it down to two rows so we dont have
       one row with just dots").
     *
     * The stacked row (~12826, "Extra row space") is a COLUMN: checkbox band,
     * info band, then the full-width segmented control. That segmented track is
     * ratified and stays. What earns its own band and should not is the
     * CHECKBOX: a 16px tick sitting alone on a line with ~340px of empty space
     * beside it, which is the row that reads as spare. Float it up beside the
     * title instead - same line, no extra height - so the row is:
     *
     *     [x] Title                     <- band 1
     *         source · date · time      <- (inside band 1's column)
     *     [ Private | Busy | Shared ]   <- band 2
     *
     * Measured at 390px: 144.2px -> see the tally below the rules. */
    .synced-row {
        display: grid;
        grid-template-columns: auto 1fr;
        grid-template-areas: "check info" "actions actions";
        align-items: start;
        column-gap: 10px;
        row-gap: 6px;
    }
    .synced-row-check { grid-area: check; align-self: center; }
    .synced-row-info  { grid-area: info; min-width: 0; }
    .synced-row-actions { grid-area: actions; }
}

/* Meta segments: the separator travels WITH the segment it precedes, so a "·"
   is never left to start a wrapped line. `nowrap` keeps each "· <segment>" pair
   atomic; the row still wraps BETWEEN segments, which is the only place a break
   reads correctly. */
.synced-meta-seg { display: inline-flex; align-items: center; white-space: nowrap; }
.synced-meta-sep { margin: 0 5px 0 0; }

/* ── Conflicts entry row (Events tab) ─────────────────────────────────────
   2026-08-16, user: "the ui to manage conflicts is missing, unlike before"
   and "conflicts manager could be a sub section of events".

   The panel was never removed — its entry points were. A count-gated triage
   strip vanishes on a quiet day, and the Scheduled-tab dot is display:none in
   every state by deliberate design (no coloured dots on that row). That left
   the manager reachable only by accident. This row is the standing route.

   It names its count in WORDS rather than leaning on a hue, and it renders at
   zero too: an empty state that says "nothing double-booked" teaches that the
   manager exists and is working, which a hidden control never can. */
.rc-conflicts-entry {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    margin: 0 0 10px;
    padding: 10px 12px;
    text-align: left;
    cursor: pointer;
    border: 1px solid var(--border-color, #e2e8f0);
    border-radius: var(--radius-md, 10px);
    background: var(--bg-primary, #fff);
    /* Explicit props (not transition:all) per the visibility-trap guard. */
    transition: background-color 0.15s ease, border-color 0.15s ease;
}
.rc-conflicts-entry:hover {
    background: var(--bg-secondary, #f8fafc);
    border-color: var(--slate-300, #cbd5e1);
}
.rc-conflicts-entry__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-sm, 6px);
    /* Slate at rest: "no overlaps" is not a warning. */
    color: var(--slate-500, #64748b);
    background: var(--slate-100, #f1f5f9);
}
.rc-conflicts-entry__text {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
    flex: 1 1 auto;
}
.rc-conflicts-entry__label {
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 600;
    color: var(--text-primary, #0f172a);
}
.rc-conflicts-entry__hint {
    font-size: 11px;
    color: var(--text-secondary, #64748b);
}
.rc-conflicts-entry__chev {
    flex: 0 0 auto;
    font-size: 11px;
    color: var(--slate-400, #94a3b8);
}
/* Only an ACTUAL double-booking earns the danger hue — this is the one place
   red is correct (conflicts/danger), per the busy-is-slate split. */
.rc-conflicts-entry.has-conflicts {
    border-color: rgba(220, 38, 38, 0.35);
    background: rgba(220, 38, 38, 0.04);
}
.rc-conflicts-entry.has-conflicts .rc-conflicts-entry__icon {
    color: #dc2626;
    background: rgba(220, 38, 38, 0.1);
}

body.dark-mode .rc-conflicts-entry {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
}
body.dark-mode .rc-conflicts-entry:hover {
    background: var(--slate-700, #334155);
}
body.dark-mode .rc-conflicts-entry__icon {
    color: var(--slate-300, #cbd5e1);
    background: var(--slate-700, #334155);
}
body.dark-mode .rc-conflicts-entry__label { color: var(--slate-100, #f1f5f9); }
body.dark-mode .rc-conflicts-entry__hint { color: var(--slate-400, #94a3b8); }
body.dark-mode .rc-conflicts-entry.has-conflicts {
    border-color: rgba(248, 113, 113, 0.45);
    background: rgba(248, 113, 113, 0.1);
}
body.dark-mode .rc-conflicts-entry.has-conflicts .rc-conflicts-entry__icon {
    color: #f87171;
    background: rgba(248, 113, 113, 0.16);
}

/* Dark mode for the segmented visibility track (2026-08-16). The track must
   read as a recessed groove and the selected segment as a raised card in both
   themes — in dark mode that means the track goes DARKER than the surface and
   the selection LIGHTER, the inverse of the light-mode relationship. */
body.dark-mode .synced-row-actions,
body.dark-mode .synced-sweep-actions {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
}
body.dark-mode .synced-vis-btn,
body.dark-mode .synced-sweep-btn {
    color: var(--slate-400, #94a3b8);
}
body.dark-mode .synced-vis-btn + .synced-vis-btn,
body.dark-mode .synced-sweep-btn + .synced-sweep-btn {
    box-shadow: inset 1px 0 0 var(--slate-700, #334155);
}
body.dark-mode .synced-vis-btn.active {
    background: var(--slate-700, #334155);
    border-color: var(--slate-600, #475569);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
body.dark-mode .synced-vis-btn[data-visibility="hidden"].active { color: #c4b5fd; }
body.dark-mode .synced-vis-btn[data-visibility="busy"].active { color: #fcd34d; }
body.dark-mode .synced-vis-btn[data-visibility="full"].active { color: #86efac; }
body.dark-mode .synced-vis-btn.active i { color: inherit; }

/* ── Final confirmation, at the end of the privacy list ───────────────────
   2026-08-16, user: "Then scroll for for a final confirmation button. This
   should show a summary of events grouped into their visibility selections
   then confirm."

   The grouped summary already existed but lived only inside a modal — and
   that modal is skipped whenever nothing loosens, so a tightening-only batch
   committed with no summary at all. This puts the same card in the page, at
   the bottom of the list, so scrolling to it is the natural last step and the
   review happens on the same surface as the choosing.

   Renders only while something is staged. */
.privacy-final-confirm {
    margin: 12px 0 4px;
    padding: 14px;
    border: 1px solid var(--border-color, #e2e8f0);
    border-radius: 12px;
    background: var(--bg-secondary, #f8fafc);
}
/* Armed = something is staged and committable. Carries the weight the old top
   bar's -armed state did, on the element that now owns the commit. */
.privacy-final-confirm-armed {
    background: rgba(139, 92, 246, 0.06);
    border-color: rgba(139, 92, 246, 0.3);
}
.privacy-final-confirm-title {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 0 0 10px;
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 600;
    color: var(--text-primary, #0f172a);
}
/* Idle copy. The step is always present, so it has to say what it is waiting
   for rather than render as an empty card. */
.privacy-final-idle {
    margin: 0;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--text-secondary, #64748b);
}
/* The one-line readback that used to BE the button label ("Share 1, hide 2").
   2026-08-30: the button is now just "Apply", so this line carries the detail —
   and, when something loosens, it is the last statement of what gets shared
   before the commit. Right-aligned to sit directly over the button it describes. */
.privacy-final-cta-detail {
    margin: 12px 0 0;
    padding-top: 12px;
    border-top: 1px solid var(--border-color, #e2e8f0);
    text-align: right;
    font-size: var(--rc-font-secondary, 12px);
    color: var(--text-secondary, #64748b);
}
.privacy-final-confirm-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border-color, #e2e8f0);
}
/* When the detail line is present it owns the divider — two stacked rules
   would draw two hairlines 12px apart. */
.privacy-final-cta-detail + .privacy-final-confirm-actions {
    margin-top: 8px;
    padding-top: 0;
    border-top: 0;
}
.privacy-final-discard {
    padding: 8px 14px;
    border: 1px solid var(--border-color, #cbd5e1);
    border-radius: 8px;
    background: transparent;
    color: var(--text-secondary, #64748b);
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 500;
    cursor: pointer;
    /* Explicit props (not transition:all) per the visibility-trap guard. */
    transition: background-color 0.12s ease, border-color 0.12s ease;
}
.privacy-final-discard:hover {
    background: var(--bg-primary, #fff);
    border-color: var(--slate-300, #cbd5e1);
}
/* The commit. Purple = the Privacy tab's identity colour, so the button that
   applies a visibility change is coloured by the thing it changes. */
.privacy-final-apply {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 16px;
    border: 1px solid transparent;
    border-radius: 8px;
    background: var(--visibility-private, #8b5cf6);
    color: #fff;
    font-size: var(--rc-font-secondary, 12px);
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.12s ease, box-shadow 0.12s ease;
}
.privacy-final-apply:hover {
    background: #7c3aed;
    box-shadow: 0 2px 8px rgba(139, 92, 246, 0.3);
}
.privacy-final-apply:focus-visible,
.privacy-final-discard:focus-visible {
    outline: 2px solid var(--visibility-private, #8b5cf6);
    outline-offset: 2px;
}

body.dark-mode .privacy-final-confirm {
    background: var(--slate-800, #1e293b);
    border-color: var(--slate-700, #334155);
}
body.dark-mode .privacy-final-confirm-armed {
    background: rgba(139, 92, 246, 0.14);
    border-color: rgba(139, 92, 246, 0.45);
}
body.dark-mode .privacy-final-idle { color: var(--slate-400, #94a3b8); }
body.dark-mode .privacy-final-confirm-title { color: var(--slate-100, #f1f5f9); }
body.dark-mode .privacy-final-confirm-actions { border-top-color: var(--slate-700, #334155); }
body.dark-mode .privacy-final-discard {
    border-color: var(--slate-600, #475569);
    color: var(--slate-300, #cbd5e1);
}
body.dark-mode .privacy-final-discard:hover { background: var(--slate-700, #334155); }

@media (max-width: 640px) {
    /* Stack the actions so the commit is a full-width target, and put it
       FIRST in reading order under the summary it applies. */
    .privacy-final-confirm-actions { flex-direction: column-reverse; align-items: stretch; }
    .privacy-final-apply,
    .privacy-final-discard { width: 100%; justify-content: center; }
}

/* ============================================
   CONFLICTS — "Ignored" disclosure (2026-08-11)
   ============================================
   The record of overlaps the user accepted via "Keep both". It is the UNDO
   for a dismissal that now persists, so it must always be reachable — the
   conflicts panel deliberately stays mounted when the live queue empties
   rather than bouncing to the Scheduled list, or this section would become
   unreachable exactly when it is the only thing left to show.

   Collapsed by default and styled DOWN (muted ink, no card chrome): it is a
   record, not a queue, and must never compete with live conflicts above it. */
.rc-conflict-ignored {
    margin-top: 10px;
    border-top: 1px solid var(--slate-200, #e2e8f0);
    padding-top: 8px;
}

.rc-conflict-ignored-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    padding: 4px 2px;
    background: none;
    border: none;
    cursor: pointer;
    font-size: 12px;
    font-weight: 600;
    color: var(--slate-500, #64748b);
    text-align: left;
}
.rc-conflict-ignored-toggle:hover {
    color: var(--slate-700, #334155);
}
.rc-conflict-ignored-toggle i {
    font-size: 10px;
    transition: transform 0.15s ease;
}
.rc-conflict-ignored-toggle[aria-expanded="true"] i {
    transform: rotate(90deg);
}

.rc-conflict-ignored-body {
    list-style: none;
    margin: 4px 0 0;
    padding: 0;
}

.rc-conflict-ignored-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 6px 2px;
    border-top: 1px solid var(--slate-100, #f1f5f9);
}
.rc-conflict-ignored-row:first-child {
    border-top: none;
}

.rc-conflict-ignored-pair {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}
.rc-conflict-ignored-titles {
    font-size: 12px;
    color: var(--slate-600, #475569);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.rc-conflict-ignored-amp {
    color: var(--slate-400, #94a3b8);
}
.rc-conflict-ignored-date {
    font-size: 10.5px;
    color: var(--slate-400, #94a3b8);
    font-variant-numeric: tabular-nums;
}

body.dark-mode .rc-conflict-ignored {
    border-top-color: var(--slate-700);
}
body.dark-mode .rc-conflict-ignored-row {
    border-top-color: var(--slate-800);
}
body.dark-mode .rc-conflict-ignored-toggle {
    color: var(--slate-400, #94a3b8);
}
body.dark-mode .rc-conflict-ignored-toggle:hover {
    color: var(--slate-200, #e2e8f0);
}
body.dark-mode .rc-conflict-ignored-titles {
    color: var(--slate-300, #cbd5e1);
}
