/* ============================================================================
   KOSIS — assets/css/kosis-dashboard.css
   ----------------------------------------------------------------------------
   v2.0 · Full rewrite · 20 May 2026

   WHAT CHANGED (vs v1.x)
   ----------------------------------------------------------------------------
   · Removed every legacy "Sarra" variable (--accent, --page, --kosis-sidebar-bg,
     --kosis-text, etc.). All colours now reference brand-book tokens
     (--ks-navy, --ks-cream, --ks-sage, --ks-gold, --ks-muted, --ks-border).
     [Brand Book v2.1 §05 — Colour tokens]

   · Body background changed from #eef5f9 (pale blue) to --ks-cream (#FDFAF1).
     [§05 — "Cream · Page background"]

   · Primary button colour changed from #3d5a80 (Sarra blue) to --ks-sage
     (#4A6F5C). [§07 — "Use sage for primary actions, gold only for highlights"]

   · Sidebar width: single source of truth — 260px desktop, 88px tablet,
     drawer on mobile. Old 300/210 conflict eliminated.

   · Sidebar brand block: 36px mark + Cinzel wordmark (3px tracking) + gold
     italic tagline, sized so "Choir · Management" never wraps. [§03, §06]

   · Profile pills: `.pill-tab-label` now `display: none` by default — fixes
     the overlap bug where "Choir director / stuff random" rendered on top
     of the tablet-mode short label at borderline viewport widths.

   · Nav icons: 18px per brand book §04 ("Render at 18 px in the sidebar"),
     stroke="currentColor" so colour inherits from the link state.

   · Active nav state: 3px gold left-bar + navy-lift background + cream text
     + gold icon (was: 4px white border + 20% white overlay).

   · PWA: env(safe-area-inset-*) on sidebar top + mobile bottom-nav for iOS
     home-screen installs; will-change on drawer transform for jank-free open.

   · Font stack: Inter for UI body (was DM Sans). Cinzel reserved for brand
     wordmark, section headings, scripture only. [§06]

   LOAD ORDER (head-dashboard.php)
     1. kosis-brand.css            ← design tokens (CSS variables)
     2. kosis-dashboard.css        ← this file (layout + chrome)
     3. kosis-brand-extensions.css ← page-level components

   kosis-sarra-theme.css is no longer loaded by dashboard pages.
   ========================================================================= */


/* ── 1. Reset ────────────────────────────────────────────────────────────── */
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html,
body {
    margin: 0;
    padding: 0;
}

html {
    -webkit-text-size-adjust: 100%;
}

body.kosis-dashboard {
    background: var(--ks-cream);
    color: var(--ks-navy);
    font-family: var(--ks-font-sans);
    font-size: 14px;
    line-height: 1.5;
    min-height: 100vh;
    min-height: 100dvh;            /* PWA: handles mobile browser chrome */
    display: flex;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}


/* ── 2. Layout tokens ────────────────────────────────────────────────────── */
:root {
    --kosis-sidebar-width: 260px;  /* SINGLE source of truth. Tablet override
                                       lives in the tablet media query only. */
}


/* ── 3. Sidebar — root container ─────────────────────────────────────────── */
.sidebar,
aside.sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--kosis-sidebar-width);
    min-width: var(--kosis-sidebar-width);
    max-width: var(--kosis-sidebar-width);
    height: 100vh;
    height: 100dvh;
    background: var(--ks-navy);
    color: var(--ks-cream);
    overflow-x: hidden;
    overflow-y: auto;
    z-index: 20;
    display: flex;
    flex-direction: column;
    padding-top: env(safe-area-inset-top, 0);   /* PWA */
    box-shadow: 1px 0 0 rgba(212, 169, 85, 0.08);
}


/* ── 4. Sidebar brand lockup ─────────────────────────────────────────────── */
.sidebar .brand {
    flex-shrink: 0;
    padding: 24px 20px 16px;
    display: flex;
    align-items: center;
    gap: 12px;
    border: 0;
    background: transparent;
    /* No bottom border — divider lives in .ks-brand-divider */
}

/* v2.1 — Logo bumped from 36px (brand-book sidebar floor) to 52px so the
   three-angels mark reads at a glance instead of getting lost above the
   pills. Brand book §03 lists 36px as the SIZE FLOOR, not the target —
   anything larger is still on-brand provided we keep the gold-ring clear-
   space margin. Applies to desktop, tablet (88px sidebar), and mobile
   drawer through a single rule. */
.sidebar .brand .ks-brand__mark,
.sidebar .brand img {
    width: 52px;
    height: 52px;
    flex: 0 0 52px;
    display: block;
}

/* Cinzel wordmark — never wraps. min-width: 0 lets the parent flex
   container shrink the text wrapper if needed instead of overflowing. */
.sidebar .brand > div {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    line-height: 1;
}

.sidebar .brand .ks-brand__wordmark {
    font-family: var(--ks-font-serif);
    font-size: 16px;
    font-weight: 500;
    letter-spacing: 3px;
    color: var(--ks-cream);
    text-transform: uppercase;
    white-space: nowrap;
    line-height: 1;
    margin: 0;
}

.sidebar .brand .ks-brand__tagline {
    font-family: var(--ks-font-serif);
    font-size: 8px;
    font-style: italic;
    font-weight: 400;
    letter-spacing: 1.5px;
    color: var(--ks-gold);
    white-space: nowrap;
    line-height: 1.4;
    margin: 0;
}

/* Defensive override — kills the legacy `.sidebar .brand span` rule
   that used to force every span to 1.42rem / weight 800. */
.sidebar .brand span {
    font-size: inherit;
    font-weight: inherit;
}


/* ── 5. Dashed gold divider (under brand) ────────────────────────────────── */
.ks-brand-divider {
    flex-shrink: 0;
    height: 1px;
    margin: 0 20px 12px;
    background-image: linear-gradient(
        to right,
        rgba(212, 169, 85, 0.35) 0,
        rgba(212, 169, 85, 0.35) 6px,
        transparent 6px,
        transparent 12px
    );
    background-size: 12px 1px;
    background-repeat: repeat-x;
    position: relative;
}

.ks-brand-divider::after {
    content: "";
    position: absolute;
    top: -1.5px;
    left: 50%;
    transform: translateX(-50%);
    width: 4px;
    height: 4px;
    background: var(--ks-gold);
    border-radius: 50%;
    opacity: 0.7;
}


/* ── 6. Profile pills (director + group) ─────────────────────────────────── */
.sidebar .admin-pill,
.sidebar .group-pill {
    flex-shrink: 0;
    margin: 0 12px 8px;
    padding: 10px 12px;
    display: flex;
    align-items: center;
    gap: 12px;
    border-radius: var(--ks-radius-sm);
    min-height: 56px;
    box-sizing: border-box;
    position: relative;
}

.sidebar .admin-pill {
    background: var(--ks-navy-lift);
}

.sidebar .group-pill {
    background: transparent;
    border: 0.5px solid rgba(212, 169, 85, 0.18);
}

/* Avatars / photo */
.sidebar .admin-avatar,
.sidebar .group-photo {
    width: 32px;
    height: 32px;
    flex: 0 0 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    box-sizing: border-box;
}

.sidebar .admin-avatar {
    border-radius: 50%;
    background: var(--ks-gold);
    color: var(--ks-navy);
    font-family: var(--ks-font-sans);
    font-weight: 600;
    font-size: 13px;
    text-transform: uppercase;
}

.sidebar .group-photo {
    border-radius: var(--ks-radius-sm);
    background: rgba(212, 169, 85, 0.12);
    color: var(--ks-gold);
}

.sidebar .group-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: var(--ks-radius-sm);
}

.sidebar .group-photo svg {
    width: 18px;
    height: 18px;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* Initials fallback shown when a choir has no photo (or the file is missing).
   Centered by the .group-photo flex container above; this just sizes the text. */
.sidebar .group-initials {
    font-family: var(--ks-font-sans);
    font-weight: 600;
    font-size: 12px;
    line-height: 1;
    letter-spacing: 0.2px;
    text-transform: uppercase;
    color: var(--ks-gold);
}

/* Pill text columns */
.sidebar .pill-desktop-info {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
    flex: 1;
}

.sidebar .profile-label {
    font-family: var(--ks-font-sans);
    font-size: 9px;
    font-weight: 500;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--ks-muted);
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar .admin-name,
.sidebar .group-name {
    font-family: var(--ks-font-sans);
    font-size: 12px;
    font-weight: 600;
    color: var(--ks-cream);
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar .group-sub {
    font-family: var(--ks-font-sans);
    font-size: 10px;
    color: var(--ks-muted);
    line-height: 1.3;
    margin-top: 1px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Chevron — desktop only */
.sidebar .kosis-pill-chevron {
    flex-shrink: 0;
    opacity: 0.5;
    color: var(--ks-cream);
}

/* CRITICAL FIX — default hide tablet label. Without this default,
   the tablet-mode short label rendered on top of the desktop info
   at any viewport that fell outside the explicit media queries. */
.sidebar .pill-tab-label {
    display: none;
}

.sidebar .pill-tab-name,
.sidebar .pill-tab-role {
    font-family: var(--ks-font-sans);
}

/* Profile pill hover (clickable trigger) */
.sidebar .kosis-profile-trigger {
    cursor: pointer;
    transition: background 150ms ease;
}

.sidebar .kosis-profile-trigger:hover {
    background: #324478;          /* Slightly lighter than navy-lift */
}


/* ── 7. Navigation ───────────────────────────────────────────────────────── */
.sidebar nav {
    flex: 1 1 auto;
    padding: 16px 0 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-height: 0;
    /* Scroll the nav list internally when the window is short, so the brand
       stays pinned at the top and the footer scripture stays pinned at the
       bottom instead of the links overflowing onto the verse. */
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-width: thin;
    overscroll-behavior: contain;
}

/* Sidebar scrollbars: the navy sidebar made the default (dark) scrollbar
   nearly invisible — especially on short/small viewports where the nav must
   scroll. Give the thumb a visible gold tint over a faint track so it is
   obvious there is more to scroll. Applies to the whole sidebar column and
   the inner nav list. */
.sidebar,
aside.sidebar,
.sidebar nav {
    scrollbar-width: thin;
    scrollbar-color: rgba(212, 169, 85, 0.80) rgba(253, 250, 241, 0.10);
}
.sidebar::-webkit-scrollbar,
.sidebar nav::-webkit-scrollbar {
    width: 8px;
}
.sidebar::-webkit-scrollbar-track,
.sidebar nav::-webkit-scrollbar-track {
    background: rgba(253, 250, 241, 0.08);
    border-radius: 999px;
}
.sidebar::-webkit-scrollbar-thumb,
.sidebar nav::-webkit-scrollbar-thumb {
    background: rgba(212, 169, 85, 0.80);
    border-radius: 999px;
    border: 2px solid transparent;
    background-clip: padding-box;
}
.sidebar::-webkit-scrollbar-thumb:hover,
.sidebar nav::-webkit-scrollbar-thumb:hover {
    background: var(--ks-gold);
    background-clip: padding-box;
    border: 2px solid transparent;
}

.sidebar .nav-link {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 0 12px;
    padding: 10px 14px;
    min-height: 44px;             /* Touch target */
    border-radius: var(--ks-radius-sm);
    border-left: 3px solid transparent;
    color: var(--ks-muted);
    background: transparent;
    text-decoration: none;
    font-family: var(--ks-font-sans);
    font-size: 13px;
    font-weight: 500;
    line-height: 1.3;
    transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
    position: relative;
}

.sidebar .nav-link:focus-visible {
    outline: 2px solid rgba(212, 169, 85, 0.6);
    outline-offset: 2px;
}

/* Default icon state — muted, inherits link colour via stroke="currentColor" */
.sidebar .nav-link svg {
    width: 18px;                  /* §04 brand book */
    height: 18px;
    flex: 0 0 18px;
    stroke: currentColor;
    color: currentColor;
    fill: none;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
    transition: color 120ms ease;
}

/* Force any inline width/height on nested SVG nodes to match */
.sidebar .nav-link svg *[stroke="currentColor"] {
    stroke: currentColor;
}

/* Hover */
.sidebar .nav-link:hover {
    background: rgba(212, 169, 85, 0.06);
    color: var(--ks-cream);
}

/* Active — gold left bar + lift background + cream text + gold icon */
.sidebar .nav-link.active {
    background: var(--ks-navy-lift);
    color: var(--ks-cream);
    border-left-color: var(--ks-gold);
    font-weight: 600;
}

.sidebar .nav-link.active svg {
    color: var(--ks-gold);
}

/* Hide tablet-mode short label by default — same rationale as
   .pill-tab-label above. */
.sidebar .nav-link .nav-label-short {
    display: none;
}

.sidebar .nav-link .nav-label-full {
    display: inline-block;
    flex: 1;
    min-width: 0;
}


/* ── 8. Sidebar footer scripture ─────────────────────────────────────────── */
.ks-sidebar-footer {
    flex-shrink: 0;
    margin: 16px 20px 24px;
    padding-top: 16px;
    border-top: 0.5px solid rgba(212, 169, 85, 0.18);
    text-align: center;
    padding-bottom: env(safe-area-inset-bottom, 0);   /* PWA */
}

.ks-sidebar-footer__quote {
    display: block;
    font-family: var(--ks-font-serif);
    font-style: italic;
    font-size: 9px;
    color: var(--ks-muted);
    margin-bottom: 4px;
    line-height: 1.4;
}

.ks-sidebar-footer__ref {
    display: block;
    font-family: var(--ks-font-serif);
    font-size: 8px;
    letter-spacing: 1.5px;
    color: var(--ks-gold);
    text-transform: uppercase;
}


/* ── 9. Drawer footer (mobile only — hidden by default) ──────────────────── */
.drawer-footer {
    display: none;
}


/* ── 10. Sidebar overlay (mobile drawer) ─────────────────────────────────── */
.sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(31, 41, 82, 0.45);
    z-index: 19;
}


/* ── 11. Mobile bottom nav (hidden on desktop) ───────────────────────────── */
.mobile-nav {
    display: none;
}

/* ── 11b. Mobile "More" overflow button + sheet (base; shown at <=639px) ──── */
.ks-more-btn   { display: none; }
.ks-more-sheet { display: none; }
.ks-more-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(31, 41, 82, 0.45);
    z-index: 160;
}


/* ── 12. Main content area ───────────────────────────────────────────────── */
main.main,
.main {
    margin-left: var(--kosis-sidebar-width);
    width: calc(100% - var(--kosis-sidebar-width));
    min-height: 100vh;
    min-height: 100dvh;
    background: var(--ks-cream);
    padding: var(--ks-space-xl) var(--ks-space-xl) calc(var(--ks-space-xl) * 1.5 + env(safe-area-inset-bottom, 0));
    box-sizing: border-box;
}

/* Uniform content width across ALL dashboard pages.
   Every direct child of .main is capped at 1280px and CENTRED inside the
   content area, so content sits in a balanced column and the topbar lines up
   with it. We use margin-inline:auto (not the 4-value shorthand) so a stray
   left/right value can never re-bias it, and !important so per-page wrappers
   (.kosis-page-content, .ks-page-narrow, .members-layout, section, etc.) that
   carry their own margins can't override the centring. A max-width can only
   narrow, never widen, so narrower wrappers stay put. */
.main > * {
    max-width: 1280px;
    margin-inline: auto !important;
}


/* ── 13. Topbar (breadcrumb + sign-out) ──────────────────────────────────── */
.topbar {
    max-width: 1280px;
    margin: 0 auto var(--ks-space-md);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ks-space-md);
}

/* Topbar left/right groups: the right group holds the notification bell + Sign
   out button. Without an explicit flex context the bell (a block-level div) and
   the Sign out link stacked vertically on narrow screens; this keeps them on
   one row, and lets the title ellipsis instead of shoving the actions. */
.topbar__left {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    flex: 1 1 auto;
}
.topbar__left h1 {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
.topbar__right {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
}

.topbar h1 {
    font-family: var(--ks-font-sans);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--ks-slate);
    margin: 0;
}

.signout {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--ks-navy);
    text-decoration: none;
    font-family: var(--ks-font-sans);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: .02em;
    padding: 7px 16px;
    border: 1px solid var(--ks-border);
    border-radius: 999px;
    background: #fff;
    box-shadow: 0 1px 2px rgba(31,41,82,.05);
    transition: color .15s, border-color .15s, background .15s, box-shadow .15s;
}

.signout:hover,
.signout:focus-visible {
    color: #fff;
    background: #B85450;
    border-color: #B85450;
    text-decoration: none;
    box-shadow: 0 2px 6px rgba(184,84,80,.28);
    outline: none;
}


/* ── 14. Buttons — brand-correct ─────────────────────────────────────────── */
/*  THE CANONICAL ACTION-BUTTON SYSTEM — single source of truth (Session 53).

    Every action button in Kosis is `.btn` + exactly ONE variant below. The PHP
    helper ks_action_button() (includes/helpers.php) emits this markup from a
    SEMANTIC ACTION name, so the look can never drift again and destructive
    actions always get a confirm. The mapping — also documented in the helper,
    and to be added to the Kosis Brand Book — is:

      ACTION    VARIANT               APPEARANCE      MEANING
      save      .btn-primary          sage solid      primary commit (Save/Create)
      add       .btn--gold            gold solid      add a thing to a list
      edit      .btn--secondary       navy outline    edit / configure
      cancel    .btn--secondary       navy outline    cancel / close / back
      remove    .btn--danger-ghost    brick outline   remove/delete trigger (confirms)
      delete    .btn--danger          brick solid     final delete commit (confirms)
      neutral   .btn--navy-outline    navy outline    misc secondary action

    Modifiers: .btn--sm (compact, rows/cards), .full (100% width).
    Brand book §07: sage = primary; gold = highlight/add; #B85450 brick =
    destructive. Destructive buttons ALWAYS pair with a confirm — kosis.js §27
    reads data-ks-confirm on the surrounding <form>.

    MIGRATION NOTE (Session 53): older pages used ad-hoc strays
    (.ks-btn-danger, .ks-btn-compact, a CONFLICTING .ks-btn--sm, .ks-btn-muted).
    As each page moves to ks_action_button() those classes leave the markup and
    the leftover stray CSS in kosis-pages.css is removed page-by-page. Do NOT
    add new button classes — extend THIS system instead. */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 10px 20px;
    border: 0;
    border-radius: var(--ks-radius-input);
    background: transparent;
    color: var(--ks-navy);
    font-family: var(--ks-font-sans);
    font-size: 13px;
    font-weight: 500;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    transition: filter 120ms ease, background 120ms ease, border-color 120ms ease;
    min-height: 40px;
    box-sizing: border-box;
}

.btn:hover {
    filter: brightness(0.96);
    text-decoration: none;
}

/* Primary — sage. Brand book §07: "Use sage for primary actions". */
.btn.btn-primary,
.btn-primary {
    background: var(--ks-sage);
    color: var(--ks-cream);
}

/* Gold variants — accept both BEM (.btn--gold) and legacy (.btn-gold) */
.btn--gold,
.btn-gold {
    background: var(--ks-gold);
    color: var(--ks-navy);
}

.btn--gold-outline,
.btn-gold-outline {
    background: transparent;
    color: var(--ks-gold);
    border: 0.8px solid var(--ks-gold);
}

/* Navy variants */
.btn--navy {
    background: var(--ks-navy);
    color: var(--ks-cream);
}

.btn--navy-outline {
    background: transparent;
    color: var(--ks-navy);
    border: 0.8px solid var(--ks-navy);
}

/* Secondary (transparent + navy border) */
.btn.secondary,
.btn--secondary {
    background: transparent;
    color: var(--ks-navy);
    border: 0.8px solid var(--ks-navy);
}

.btn.full {
    width: 100%;
}

/* Danger — destructive actions (delete poll, remove, etc.).
   #B85450 is the sanctioned brick red used across Kosis for destructive
   intent (account deletion, error flashes). Promoted here from the
   profile-modal-scoped .ks-btn--danger* into the shared .btn system so every
   destructive control reads the same. Two weights, mirroring the brand's
   trigger-vs-commit pattern:
     · --danger-ghost : calm trigger on a management surface (brick outline,
                         fills brick on hover). Use on cards/rows.
     · --danger       : solid commit, for the FINAL confirm in a delete flow. */
.btn--danger-ghost {
    background: transparent;
    color: #B85450;
    border: 0.8px solid #B85450;
}
.btn--danger-ghost:hover {
    background: #B85450;
    color: var(--ks-cream);
    filter: none;
}
.btn--danger {
    background: #B85450;
    color: var(--ks-cream);
}

/* Small button — compact secondary/danger affordances inside cards & rows. */
.btn--sm {
    padding: 6px 12px;
    min-height: 32px;
    font-size: 12px;
}
.btn--sm svg { width: 14px; height: 14px; }


/* ── 15. Form controls ───────────────────────────────────────────────────── */
.ks-input,
.ks-textarea,
input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
input[type="search"],
textarea,
select {
    width: 100%;
    padding: 10px 14px;
    background: var(--ks-cream);
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-input);
    font-family: var(--ks-font-sans);
    font-size: 13px;
    color: var(--ks-navy);
    outline: none;
    transition: border-color 120ms ease, box-shadow 120ms ease;
    box-sizing: border-box;
}

/* ── 15a. Select control: custom arrow + shrinkable in flex rows ──────────── */
/*  Without appearance:none the native arrow eats width and the label clips on
    narrow screens; without min-width:0 a <select> refuses to shrink inside a
    flex row (this caused "Add a song from reper…" to be cut off on mobile). */
select {
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    min-width: 0;
    max-width: 100%;
    padding-right: 36px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23667085' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 16px;
    text-overflow: ellipsis;
}

.ks-input::placeholder,
.ks-textarea::placeholder,
input::placeholder,
textarea::placeholder {
    color: var(--ks-muted);
}

.ks-input:focus,
.ks-textarea:focus,
input:focus,
textarea:focus,
select:focus {
    border-color: var(--ks-sage);
    box-shadow: 0 0 0 3px rgba(74, 111, 92, 0.12);
}

textarea {
    min-height: 96px;
    resize: vertical;
}

.ks-label {
    display: block;
    font-family: var(--ks-font-sans);
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    color: var(--ks-slate);
    margin-bottom: 6px;
}

.form-grid {
    display: grid;
    gap: var(--ks-space-sm);
}

/* ── 15b. Search field: stop the icon/clear-control overlapping the text ──── */
/*  Removes the native WebKit search decoration + cancel button that rendered
    on top of the placeholder ("Search" word overlap), and guarantees the
    left padding clears the magnifier icon. */
input[type="search"] {
    -webkit-appearance: none;
    appearance: none;
}
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration {
    -webkit-appearance: none;
    display: none;
}
.search-form { position: relative; }
.search-form svg {
    position: absolute;
    left: 14px; top: 50%;
    transform: translateY(-50%);
    color: var(--ks-slate);
    pointer-events: none;
}
.search-form .search-input,
.search-form input[type="search"] {
    padding-left: 42px;
}


/* ── 16. Flash messages ──────────────────────────────────────────────────── */
.kosis-flash {
    padding: 10px 16px;
    border-radius: var(--ks-radius-sm);
    font-size: 13px;
    max-width: 1280px;
    margin: 0 auto var(--ks-space-md);
}

.kosis-flash--success,
.kosis-flash-success {
    background: #ecfdf3;
    border: 0.5px solid #b7e4c7;
    color: #1f6b3a;
}

.kosis-flash--error,
.kosis-flash-error {
    background: #fef2f2;
    border: 0.5px solid #fecaca;
    color: #b91c1c;
}

.kosis-flash--info,
.kosis-flash-info {
    background: var(--ks-parchment);
    border: 0.5px solid var(--ks-border);
    color: var(--ks-navy);
}


/* ── 17. Hamburger (mobile only — hidden on desktop) ─────────────────────── */
.hamburger-btn {
    display: none;
}


/* ╔══════════════════════════════════════════════════════════════════════════╗
   ║  RESPONSIVE                                                              ║
   ║  Desktop ≥ 1101px — full sidebar (260px)                                 ║
   ║  Tablet  640–1100px — compact icon-only sidebar (88px)                   ║
   ║  Mobile  < 640px — sidebar hidden, slide-in drawer + bottom nav          ║
   ╚══════════════════════════════════════════════════════════════════════════╝ */


/* ── 18. (DISABLED) old icon-rail tier ───────────────────────────────────────
   The intermediate icon-rail looked cramped when zooming, so it's disabled: we
   now go straight from the full desktop sidebar (>=1024px) to the clean mobile
   bottom-bar layout (<=1023px, see §19). This media query is intentionally
   impossible so the rules below never apply. */
@media (max-width: 767px) and (min-width: 768px) {
    :root { --kosis-sidebar-width: 88px; }

    .sidebar { overflow: visible; overflow-y: auto; }

    /* Hide text labels */
    .sidebar .brand .ks-brand__wordmark,
    .sidebar .brand .ks-brand__tagline,
    .sidebar .pill-desktop-info,
    .sidebar .kosis-pill-chevron,
    .sidebar .ks-sidebar-footer { display: none; }

    /* Center brand mark */
    .sidebar .brand {
        justify-content: center;
        padding: 20px 8px 12px;
    }

    /* Compact pills — avatar/photo on TOP, short label BELOW.
       v2.1 — Previously the pills showed only an avatar with no text, so on
       iPad-class viewports a user couldn't tell the director pill from the
       group pill at a glance. Now they mirror the nav-link pattern: icon
       stacked above a centred short label. The .pill-tab-name and
       .pill-tab-role spans are already rendered by sidebar.php — they were
       hidden by the default rule and never enabled at this breakpoint. */
    .sidebar .admin-pill,
    .sidebar .group-pill {
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 4px;
        margin: 0 8px 8px;
        padding: 8px 4px;
        min-height: 72px;
    }

    .sidebar .pill-tab-label {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 1px;
        max-width: 72px;
    }

    .sidebar .pill-tab-name {
        font-family: var(--ks-font-sans);
        font-size: 10px;
        font-weight: 600;
        color: var(--ks-cream);
        line-height: 1.2;
        text-align: center;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 72px;
    }

    .sidebar .pill-tab-role {
        font-family: var(--ks-font-sans);
        font-size: 8px;
        font-weight: 500;
        letter-spacing: 0.6px;
        text-transform: uppercase;
        color: var(--ks-muted);
        line-height: 1.2;
        text-align: center;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 72px;
    }

    /* Compact nav — icon stacked above short label */
    .sidebar .nav-link {
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 4px;
        margin: 0 8px;
        padding: 8px 4px;
        min-height: 56px;
        border-left: none;
        border-bottom: 3px solid transparent;
    }

    .sidebar .nav-link.active {
        border-left: none;
        border-bottom-color: var(--ks-gold);
    }

    .sidebar .nav-link .nav-label-full  { display: none; }
    .sidebar .nav-link .nav-label-short {
        display: block;
        font-size: 10px;
        font-weight: 500;
        line-height: 1.2;
        text-align: center;
        white-space: nowrap;
        max-width: 72px;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* Brand divider narrower */
    .ks-brand-divider { margin: 0 12px 12px; }

    /* Content reflow */
    main.main,
    .main { padding: var(--ks-space-lg) var(--ks-space-lg); }
}


/* ── 19. Mobile — drawer + bottom nav ────────────────────────────────────── */
/* Mobile / narrow layout — sidebar becomes a bottom nav bar + hamburger drawer.
   Applies to everything below the desktop `lg` breakpoint (<=1023px): the full
   sidebar shows at >=1024px, and anything narrower (a smaller window OR zooming
   in on a big monitor) switches straight to this clean mobile bottom-bar layout,
   like a proper PWA — no cramped icon-rail in between. */
@media (max-width: 1023px) {
    /* ── Mobile form containment (Session 10 fix) ───────────────────────── */
    /*  Keep every form control inside the viewport — no horizontal scroll.
        The New Event form and the per-event "add song" rows overflowed because
        long <select> option text (e.g. full IANA timezone names) pushed past
        the screen edge. */
    .kosis-page-content,
    .ks-card,
    .form-grid { max-width: 100%; min-width: 0; }

    /* Reserve space for the fixed bottom bar so page content never hides
       behind it (the bar is ~56px + the device safe-area inset). */
    .kosis-page-content,
    main.main,
    .main { padding-bottom: calc(72px + env(safe-area-inset-bottom, 0)); }

    .ks-card { overflow-x: hidden; }

    .form-grid,
    .form-grid > * { min-width: 0; max-width: 100%; box-sizing: border-box; }

    /* Two-column start/end grids collapse to one column on phones. */
    .form-grid div[style*="grid-template-columns:1fr 1fr"],
    .form-grid div[style*="grid-template-columns: 1fr 1fr"] {
        grid-template-columns: 1fr !important;
    }

    /* Inline flex rows (add-song row, export row, filters) wrap instead of
       overflowing. We let FORMS' children shrink (selects/inputs), but do NOT
       force min-width:0 on every flex div (that squeezed the event cards). */
    form[style*="display:flex"],
    div[style*="display:flex"] { flex-wrap: wrap; }
    form[style*="display:flex"] > * { min-width: 0; }

    /* A bare <select> in a flex row takes the full row width on mobile so its
       label is never clipped. */
    select { width: 100%; }

    /* Inputs that were given inline width:auto should still not overflow. */
    input[style*="width:auto"],
    select[style*="width:auto"] { max-width: 100%; }

    /* Event-card top row: let it WRAP so the Edit/Delete buttons drop below
       the title block instead of squeezing the text into a narrow strip.
       (We deliberately do NOT zero the title column's min-width — that caused
       awkward wrapping like "CHOIR / PRACTICE".) */
    .ks-card > div[style*="justify-content:space-between"] { flex-wrap: wrap; }
    /* The 240px title column may relax a little on very narrow screens, but
       not collapse — keep it readable. */
    .ks-card [style*="min-width:240px"],
    .ks-card [style*="min-width: 240px"] { min-width: 200px !important; flex: 1 1 100% !important; }

    :root { --kosis-sidebar-width: 0px; }

    /* Sidebar → slide-in drawer */
    .sidebar,
    aside.sidebar {
        position: fixed;
        top: 0; left: 0; bottom: 0;
        width: 280px;
        min-width: 280px;
        max-width: 280px;
        transform: translateX(-100%);
        transition: transform 250ms ease-out;
        will-change: transform;
        z-index: 200;
        overflow-y: auto;
        box-shadow: 0 0 32px rgba(0, 0, 0, 0.25);
    }

    body.sidebar-open .sidebar { transform: translateX(0); }
    body.sidebar-open { overflow: hidden; }

    /* Overlay */
    .sidebar-overlay { display: block; opacity: 0; pointer-events: none;
                       transition: opacity 200ms ease; z-index: 199; }
    body.sidebar-open .sidebar-overlay { opacity: 1; pointer-events: auto; }

    /* Hide the main nav inside the drawer on mobile — the bottom-nav + More
       sheet handle navigation (matches live sidebar.php). The hamburger drawer
       is then just the brand + profile/choir pills + drawer-footer (Switch
       choir / Sign out), so it stays clean and focused rather than cluttered. */
    .sidebar > nav,
    .ks-sidebar-footer { display: none; }

    /* Show drawer-footer (Join another choir / Sign out) */
    .drawer-footer {
        display: flex;
        flex-direction: column;
        gap: 6px;
        padding: 16px;
        margin-top: auto;
        border-top: 0.5px solid rgba(212, 169, 85, 0.18);
        padding-bottom: calc(16px + env(safe-area-inset-bottom, 0));
    }

    .drawer-action {
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 12px 14px;
        border-radius: var(--ks-radius-sm);
        color: var(--ks-cream);
        font-family: var(--ks-font-sans);
        font-size: 13px;
        font-weight: 500;
        text-decoration: none;
        transition: background 150ms ease;
    }

    .drawer-action:hover { background: rgba(212, 169, 85, 0.08); text-decoration: none; }
    .drawer-action svg { width: 18px; height: 18px; stroke: currentColor; fill: none;
                          stroke-width: 1.8; flex-shrink: 0; }

    .drawer-action--danger { color: #fca5a5; }
    .drawer-action--danger:hover { background: rgba(239, 68, 68, 0.12); color: #fca5a5; }

    /* Main content — top padding reserves space for the FIXED header below so
       page content never starts underneath it. (88px bottom = bottom-nav.) */
    main.main,
    .main {
        margin-left: 0;
        width: 100%;
        padding: calc(68px + env(safe-area-inset-top, 0)) var(--ks-space-md) 88px;
    }

    /* Mobile topbar — FIXED so the hamburger + Sign out stay pinned to the top
       while the page scrolls, matching live Kosis. (We use fixed rather than
       sticky because the SPA mounts under #app{display:contents}, which can stop
       position:sticky from actually sticking; fixed is unaffected and gives the
       same behaviour.) */
    .topbar {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        width: 100%;
        background: var(--ks-cream);
        border-bottom: 0.5px solid var(--ks-border);
        padding: 12px var(--ks-space-md);
        padding-top: calc(12px + env(safe-area-inset-top, 0));
        z-index: 100;
        margin: 0;
        max-width: none;
        box-sizing: border-box;
    }

    /* Match live's mobile header: hamburger + page title + Sign out only.
       The notification bell is a v2-only desktop enhancement; hide it in the
       mobile topbar so the header behaves exactly like live Kosis (which has
       no bell). Notifications still arrive via push/email on mobile. */
    .topbar__right .ks-bell { display: none; }

    .hamburger-btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 36px;
        height: 36px;
        border: none;
        background: transparent;
        color: var(--ks-navy);
        cursor: pointer;
        border-radius: var(--ks-radius-sm);
        flex-shrink: 0;
    }
    .hamburger-btn:hover { background: rgba(31, 41, 82, 0.06); }
    .hamburger-btn svg { width: 22px; height: 22px; stroke: currentColor; fill: none;
                         stroke-width: 2; }

    /* Bottom navigation */
    .mobile-nav {
        display: flex;
        position: fixed;
        bottom: 0; left: 0; right: 0;
        background: var(--ks-navy);
        border-top: 0.5px solid rgba(212, 169, 85, 0.18);
        /* Above page content + topbar (100), below the "More" sheet (160/161)
           and the open drawer (200). Opaque + isolated so scrolling content can
           never bleed through and make the bar look faded or partly hidden. */
        z-index: 155;
        isolation: isolate;
        box-shadow: 0 -4px 16px rgba(31, 41, 82, 0.18);
        padding-bottom: env(safe-area-inset-bottom, 0);
    }

    .mobile-nav a {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        padding: 8px 4px;
        min-height: 56px;
        color: var(--ks-muted);
        font-family: var(--ks-font-sans);
        font-size: 9px;
        font-weight: 500;
        text-decoration: none;
        transition: color 120ms ease;
    }

    .mobile-nav a svg {
        width: 20px;
        height: 20px;
        stroke: currentColor;
        fill: none;
        stroke-width: 1.8;
        flex-shrink: 0;
    }

    .mobile-nav a.active,
    .mobile-nav a:hover { color: var(--ks-gold); }
    .mobile-nav a.active svg { color: var(--ks-gold); }

    /* "More" button — sits in the bottom bar, styled like a .mobile-nav item */
    .ks-more-btn {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 3px;
        padding: 8px 4px;
        min-height: 56px;
        background: none;
        border: none;
        cursor: pointer;
        color: var(--ks-muted);
        font-family: var(--ks-font-sans);
        font-size: 9px;
        font-weight: 500;
        transition: color 120ms ease;
    }
    .ks-more-btn svg {
        width: 20px;
        height: 20px;
        stroke: currentColor;
        fill: none;
        stroke-width: 1.8;
        flex-shrink: 0;
    }
    .ks-more-btn.active,
    .ks-more-btn:hover { color: var(--ks-gold); }

    /* "More" overlay + slide-up sheet */
    body.more-open .ks-more-overlay { display: block; }

    .ks-more-sheet {
        position: fixed;
        left: 0; right: 0; bottom: 0;
        z-index: 161;
        background: var(--ks-navy);
        border-top-left-radius: 18px;
        border-top-right-radius: 18px;
        padding: 8px 16px calc(16px + env(safe-area-inset-bottom, 0));
        transform: translateY(100%);
        transition: transform 220ms cubic-bezier(.22, .61, .36, 1);
        box-shadow: 0 -8px 30px rgba(0, 0, 0, 0.3);
        /* Cap the sheet so a long overflow list can never grow past the screen
           (which would hide the grip/close area and push the first items off the
           top). It stays a proper bottom sheet and scrolls its own list. */
        max-height: 80vh;
        max-height: 80dvh;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }
    body.more-open .ks-more-sheet {
        display: block;
        transform: translateY(0);
    }

    .ks-more-grip {
        width: 40px; height: 4px;
        border-radius: 999px;
        background: rgba(212, 169, 85, 0.35);
        margin: 6px auto 10px;
    }
    .ks-more-title {
        font-family: var(--ks-font-sans);
        font-size: 10px;
        letter-spacing: 1.5px;
        text-transform: uppercase;
        color: var(--ks-muted);
        padding: 0 4px 8px;
    }
    .ks-more-item {
        display: flex;
        align-items: center;
        gap: 14px;
        padding: 14px 8px;
        color: var(--ks-cream);
        text-decoration: none;
        border-top: 0.5px solid rgba(212, 169, 85, 0.14);
        font-family: var(--ks-font-sans);
        font-size: 15px;
    }
    .ks-more-item:first-of-type { border-top: none; }
    .ks-more-item__icon {
        display: inline-flex;
        width: 22px; height: 22px;
        color: var(--ks-muted);
    }
    .ks-more-item__icon svg {
        width: 22px; height: 22px;
        stroke: currentColor;
        fill: none;
        stroke-width: 1.8;
    }
    .ks-more-item__label { flex: 1; }
    .ks-more-item__chev { color: var(--ks-muted); font-size: 20px; }
    .ks-more-item.active { color: var(--ks-gold); }
    .ks-more-item.active .ks-more-item__icon { color: var(--ks-gold); }

    /* Account-action buttons in the More sheet (Edit profile / Switch choir /
       Sign out): strip native button chrome so they read like the nav links. */
    button.ks-more-item {
        width: 100%;
        background: none;
        border: none;
        border-top: 0.5px solid rgba(212, 169, 85, 0.14);
        cursor: pointer;
        text-align: left;
    }
    .ks-more-actions { margin-top: 4px; }
    .ks-more-item--danger { color: #e0908f; }
}


/* ── 20. Touch device tap targets ────────────────────────────────────────── */
@media (hover: none) and (pointer: coarse) {
    .btn,
    .nav-link,
    button:not(.toggle) { min-height: 44px; }
}


/* ── 21. Reduced motion ──────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
    }
}


/* ── 20. Calendar month-grid (Session 11) ────────────────────────────────── */
/*  Used on pages/events.php when ?view=calendar. All colour comes from brand
    tokens; event-type chip colours are set inline from kosisEventTypeColor(). */

/* View toggle (List / Calendar) */
.ks-viewtoggle {
    display: inline-flex;
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-sm);
    overflow: hidden;
}
.ks-viewtoggle__btn {
    padding: 8px 14px;
    font-family: var(--ks-font-sans);
    font-size: 12px;
    color: var(--ks-slate);
    background: var(--ks-cream);
    border: none;
    cursor: pointer;
    transition: background 120ms ease, color 120ms ease;
}
.ks-viewtoggle__btn + .ks-viewtoggle__btn { border-left: 0.5px solid var(--ks-border); }
.ks-viewtoggle__btn:hover { background: rgba(31, 41, 82, 0.05); }
.ks-viewtoggle__btn.is-active { background: var(--ks-navy); color: var(--ks-gold); }

/* Calendar card header bar */
.ks-cal__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--ks-space-sm);
    margin-bottom: var(--ks-space-md);
}
.ks-cal__nav { display: flex; align-items: center; gap: var(--ks-space-sm); }
.ks-cal__navbtn {
    width: 32px; height: 32px;
    display: inline-flex; align-items: center; justify-content: center;
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-sm);
    color: var(--ks-navy);
    font-size: 20px; line-height: 1;
    background: var(--ks-cream);
}
.ks-cal__navbtn:hover { background: rgba(31, 41, 82, 0.05); }
.ks-cal__month {
    font-family: var(--ks-font-serif);
    font-size: 18px;
    color: var(--ks-navy);
    min-width: 150px;
    text-align: center;
}
.ks-cal__today {
    margin-left: var(--ks-space-sm);
    padding: 6px 12px;
    font-family: var(--ks-font-sans);
    font-size: 12px;
    color: var(--ks-sage);
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-sm);
}
.ks-cal__today:hover { background: rgba(74, 111, 92, 0.08); }

/* Calendar options menu (3-dots) */
.ks-cal__menu { position: relative; }
.ks-cal__menubtn {
    width: 32px; height: 32px;
    display: inline-flex; align-items: center; justify-content: center;
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-sm);
    background: var(--ks-cream);
    color: var(--ks-slate);
    cursor: pointer;
}
.ks-cal__menubtn:hover { background: rgba(31, 41, 82, 0.05); color: var(--ks-navy); }
.ks-cal__menupop {
    position: absolute;
    right: 0; top: calc(100% + 6px);
    min-width: 190px;
    background: #fff;
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-md);
    box-shadow: 0 8px 28px rgba(31, 41, 82, 0.16);
    padding: 6px;
    z-index: 60;
}
.ks-cal__menuhead {
    font-family: var(--ks-font-sans);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .6px;
    text-transform: uppercase;
    color: var(--ks-slate);
    padding: 6px 10px 4px;
}
.ks-cal__menuitem {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 10px;
    font-family: var(--ks-font-sans);
    font-size: 13px;
    color: var(--ks-navy);
    border-radius: var(--ks-radius-sm);
}
.ks-cal__menuitem:hover { background: rgba(31, 41, 82, 0.05); }
.ks-cal__menuitem.is-active { color: var(--ks-sage); font-weight: 600; }
.ks-cal__menucheck { width: 14px; display: inline-block; color: var(--ks-sage); }

/* The 7-column grid */
.ks-cal__grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 4px;
}
.ks-cal__weekdays { margin-bottom: 4px; }
.ks-cal__wd {
    text-align: center;
    font-family: var(--ks-font-sans);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .5px;
    text-transform: uppercase;
    color: var(--ks-slate);
    padding: 4px 0;
}
.ks-cal__week { margin-bottom: 4px; }

.ks-cal__day {
    min-height: 96px;
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-sm);
    background: #fff;
    padding: 4px;
    display: flex;
    flex-direction: column;
    gap: 3px;
    overflow: hidden;
}
.ks-cal__day.is-out { background: var(--ks-cream); opacity: 0.55; }
.ks-cal__day.is-today { border: 1px solid var(--ks-gold); box-shadow: 0 0 0 2px rgba(212, 169, 85, 0.18); }
.ks-cal__daynum {
    font-family: var(--ks-font-sans);
    font-size: 12px;
    font-weight: 600;
    color: var(--ks-navy);
    align-self: flex-end;
    padding: 0 2px;
}
.ks-cal__day.is-today .ks-cal__daynum {
    background: var(--ks-gold);
    color: var(--ks-navy);
    border-radius: 50%;
    width: 20px; height: 20px;
    display: flex; align-items: center; justify-content: center;
}

/* Event chips */
.ks-cal__chip {
    display: block;
    border: 1px solid;
    border-radius: 5px;
    padding: 3px 6px;
    font-family: var(--ks-font-sans);
    line-height: 1.2;
    overflow: hidden;
    box-shadow: 0 1px 2px rgba(31, 41, 82, 0.12);
}
.ks-cal__chip-time { font-size: 9px; font-weight: 700; display: block; opacity: .92; letter-spacing: .2px; }
.ks-cal__chip-title {
    font-size: 11px;
    font-weight: 600;
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.ks-cal__chip:hover { filter: brightness(1.08); transform: translateY(-1px); transition: filter 100ms ease, transform 100ms ease; }
.ks-cal__more {
    font-family: var(--ks-font-sans);
    font-size: 10px;
    color: var(--ks-sage);
    padding: 1px 4px;
}

/* Legend */
.ks-cal__legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ks-space-md);
    margin-top: var(--ks-space-md);
    padding-top: var(--ks-space-md);
    border-top: 0.5px solid var(--ks-border);
}
.ks-cal__legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--ks-font-sans);
    font-size: 11px;
    color: var(--ks-slate);
}
.ks-cal__legend-dot {
    width: 12px; height: 12px;
    border-radius: 3px;
    border: 1px solid;
    display: inline-block;
}

/* Mobile: tighten the grid so 7 columns still fit a phone screen. */
@media (max-width: 639px) {
    .ks-cal__day { min-height: 64px; padding: 2px; }
    .ks-cal__grid { gap: 2px; }
    .ks-cal__chip-time { display: none; }            /* save space; keep titles */
    .ks-cal__chip-title { font-size: 9px; }
    .ks-cal__daynum { font-size: 10px; }
    .ks-cal__month { font-size: 15px; min-width: 110px; }
    .ks-cal__bar { gap: 6px; }
}


/* ── 21. Event priority badge (Session 11 priority) ──────────────────────── */
/*  The coloured priority pill shown beside the type pill on event cards
    (list view). Colour comes inline from KOSIS_EVENT_PRIORITIES. */
.ks-prio-badge {
    display: inline-block;
    font-family: var(--ks-font-sans);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .5px;
    text-transform: uppercase;
    padding: 3px 8px;
    border-radius: 999px;
    border: 1px solid;
    line-height: 1.4;
    vertical-align: middle;
}


/* ── 22. Info indicator + tooltip (ⓘ) ────────────────────────────────────── */
/*  A small circled-i that reveals an explanatory popover on hover OR keyboard
    focus (accessible). Used to explain the priority colour ramp on the
    calendar legend and beside the Priority form field. */
.ks-info {
    position: relative;
    display: inline-flex;
    align-items: center;
    cursor: help;
    outline: none;
}
.ks-info__mark {
    font-size: 13px;
    color: var(--ks-shared);
    line-height: 1;
}
.ks-info:hover .ks-info__mark,
.ks-info:focus .ks-info__mark { color: var(--ks-navy); }

.ks-info__pop {
    position: absolute;
    left: 50%;
    bottom: calc(100% + 8px);
    transform: translateX(-50%);
    min-width: 240px;
    max-width: 300px;
    background: #fff;
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-md);
    box-shadow: 0 8px 28px rgba(31, 41, 82, 0.18);
    padding: 12px 14px;
    z-index: 70;
    opacity: 0;
    visibility: hidden;
    transition: opacity 120ms ease, visibility 120ms ease;
    text-align: left;
    white-space: normal;
}
.ks-info:hover .ks-info__pop,
.ks-info:focus .ks-info__pop,
.ks-info:focus-within .ks-info__pop {
    opacity: 1;
    visibility: visible;
}
/* Little arrow under the popover */
.ks-info__pop::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 6px solid transparent;
    border-top-color: #fff;
}
.ks-info__title {
    display: block;
    font-family: var(--ks-font-sans);
    font-size: 12px;
    color: var(--ks-navy);
    margin-bottom: 8px;
}
.ks-info__row {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin: 5px 0;
}
.ks-info__dot {
    flex-shrink: 0;
    width: 12px; height: 12px;
    border-radius: 3px;
    border: 1px solid;
    margin-top: 2px;
}
.ks-info__txt {
    font-family: var(--ks-font-sans);
    font-size: 12px;
    line-height: 1.4;
    color: var(--ks-slate);
}
.ks-info__txt strong { color: var(--ks-navy); }

/* Legend heading that carries the info icon */
.ks-cal__legend-heading {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--ks-font-sans);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .5px;
    text-transform: uppercase;
    color: var(--ks-navy);
    margin-right: var(--ks-space-sm);
}

/* On small screens, keep the popover within the viewport. */
@media (max-width: 639px) {
    .ks-info__pop { min-width: 200px; max-width: 240px; }
}


/* ── 23. Priority select (colour-filled) + tooltip hex chip ──────────────── */
/*  The Priority <select> paints itself in the selected tier's colour (set
    inline by JS). With a dark fill the default dark dropdown arrow vanishes,
    so when coloured we swap to a white arrow. */
.ks-prio-select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23FFFFFF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") !important;
    /* Pin EVERY background sub-property with !important so the single arrow can
       NEVER tile into a column of "v" icons — no inline style, cascade, or JS
       backgroundColor write can override these. This is the definitive fix for
       the repeating-arrow bug. */
    background-repeat: no-repeat !important;
    background-position: right 12px center !important;
    background-size: 16px 16px !important;
    background-origin: padding-box !important;
    background-clip: padding-box !important;
    -webkit-appearance: none !important;
    -moz-appearance: none !important;
    appearance: none !important;
    transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
/* Each <option> stays readable in the native list (coloured bg + white text
   set inline); some browsers ignore option colours — that's a harmless
   no-op, the closed box still shows the selected colour. */

/* Hex code chip inside the info tooltip rows */
.ks-info__hex {
    font-family: var(--ks-font-mono, ui-monospace, monospace);
    font-size: 10px;
    color: var(--ks-slate);
    background: var(--ks-cream);
    border: 0.5px solid var(--ks-border);
    border-radius: 3px;
    padding: 0 4px;
}
.ks-info__row .ks-info__txt { line-height: 1.45; }


/* ── 24. Calendar Week / Day / Year views (Session 11b) ──────────────────── */

/* Right cluster of the header: view tabs + 3-dots menu. */
.ks-cal__bar-right { display: flex; align-items: center; gap: var(--ks-space-sm); flex-wrap: wrap; }

/* View tabs: Month / Week / Day / Year — a segmented control. */
.ks-cal__tabs {
    display: inline-flex;
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-sm);
    overflow: hidden;
    background: var(--ks-cream);
}
.ks-cal__tab {
    font-family: var(--ks-font-sans);
    font-size: 12px;
    font-weight: 500;
    color: var(--ks-slate);
    padding: 6px 12px;
    border-right: 0.5px solid var(--ks-border);
    white-space: nowrap;
}
.ks-cal__tab:last-child { border-right: none; }
.ks-cal__tab:hover { background: rgba(31, 41, 82, 0.05); color: var(--ks-navy); }
.ks-cal__tab.is-active { background: var(--ks-navy); color: var(--ks-cream); font-weight: 600; }

/* Month day-number is now a link (opens Day view) — keep it looking like text. */
.ks-cal__daynum { text-decoration: none; display: inline-block; }
.ks-cal__daynum:hover { color: var(--ks-gold); }

/* ── WEEK: seven day-columns ─────────────────────────────────────────────── */
.ks-cal__weekcols {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 6px;
}
.ks-cal__weekcol {
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-sm);
    background: #fff;
    min-height: 160px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.ks-cal__weekcol.is-today { border: 1px solid var(--ks-gold); box-shadow: 0 0 0 2px rgba(212, 169, 85, 0.18); }
.ks-cal__weekcol-head {
    display: block;
    text-align: center;
    padding: 6px 4px;
    border-bottom: 0.5px solid var(--ks-border);
    background: var(--ks-cream);
    text-decoration: none;
}
.ks-cal__weekcol-head:hover { background: rgba(31, 41, 82, 0.05); }
.ks-cal__weekcol-dow {
    display: block;
    font-family: var(--ks-font-sans);
    font-size: 10px; font-weight: 700; letter-spacing: .5px; text-transform: uppercase;
    color: var(--ks-slate);
}
.ks-cal__weekcol-date { display: block; font-size: 13px; font-weight: 600; color: var(--ks-navy); }
.ks-cal__weekcol-body { padding: 6px; display: flex; flex-direction: column; gap: 5px; }
.ks-cal__weekcol-empty { color: var(--ks-muted); text-align: center; margin: 8px 0; font-size: 14px; }
.ks-cal__wchip {
    display: block;
    border: 1px solid;
    border-radius: 5px;
    padding: 4px 6px;
    text-decoration: none;
    box-shadow: 0 1px 2px rgba(31, 41, 82, 0.10);
}
.ks-cal__wchip-time { font-size: 9px; font-weight: 700; display: block; opacity: .92; }
.ks-cal__wchip-title { font-size: 11px; font-weight: 600; display: block; line-height: 1.25; }

/* ── DAY: time-ordered agenda ────────────────────────────────────────────── */
.ks-cal__day-agenda { display: flex; flex-direction: column; gap: 8px; }
.ks-cal__day-empty {
    border: 0.5px dashed var(--ks-border);
    border-radius: var(--ks-radius-md);
    background: var(--ks-cream);
    padding: var(--ks-space-lg);
    text-align: center;
}
.ks-cal__day-empty strong { color: var(--ks-navy); display: block; }
.ks-cal__day-empty p { color: var(--ks-slate); font-size: 12px; margin: 6px 0 0; }
.ks-cal__agenda-row {
    display: flex;
    align-items: stretch;
    gap: 12px;
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-md);
    background: #fff;
    padding: 10px 12px;
    text-decoration: none;
}
.ks-cal__agenda-row:hover { background: rgba(31, 41, 82, 0.03); }
.ks-cal__agenda-time {
    flex-shrink: 0;
    width: 72px;
    font-family: var(--ks-font-sans);
    font-size: 12px; font-weight: 700;
    color: var(--ks-navy);
    align-self: center;
}
.ks-cal__agenda-bar { flex-shrink: 0; width: 4px; border-radius: 2px; }
.ks-cal__agenda-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ks-cal__agenda-title { font-family: var(--ks-font-serif); font-size: 15px; color: var(--ks-navy); }
.ks-cal__agenda-meta { font-size: 11px; color: var(--ks-slate); }

/* ── YEAR: twelve mini-months ────────────────────────────────────────────── */
.ks-cal__year {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--ks-space-md);
}
.ks-cal__mini {
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-sm);
    background: #fff;
    padding: 10px;
}
.ks-cal__mini-title {
    display: block;
    text-align: center;
    font-family: var(--ks-font-serif);
    font-size: 13px;
    color: var(--ks-navy);
    margin-bottom: 6px;
    text-decoration: none;
}
.ks-cal__mini-title:hover { color: var(--ks-gold); }
.ks-cal__mini-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; }
.ks-cal__mini-cell {
    aspect-ratio: 1 / 1;
    display: flex; align-items: center; justify-content: center;
    font-size: 10px;
    color: var(--ks-navy);
    text-decoration: none;
    border-radius: 3px;
}
.ks-cal__mini-cell.is-out { color: transparent; }
.ks-cal__mini-cell.has-events { background: var(--ks-navy); color: var(--ks-cream); font-weight: 700; }
.ks-cal__mini-cell.is-today { outline: 1px solid var(--ks-gold); }
.ks-cal__mini-cell.has-events.is-today { outline: 1px solid var(--ks-gold); }
.ks-cal__mini-wdcell { color: var(--ks-muted); font-weight: 700; font-size: 9px; }
.ks-cal__mini-wd { margin-bottom: 2px; }

/* ── Responsive: stack week columns + shrink year grid on small screens ──── */
@media (max-width: 860px) {
    .ks-cal__year { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 639px) {
    .ks-cal__weekcols { grid-template-columns: 1fr; }
    .ks-cal__weekcol { min-height: 0; }
    .ks-cal__weekcol-head { display: flex; align-items: baseline; justify-content: center; gap: 6px; }
    .ks-cal__year { grid-template-columns: repeat(2, 1fr); }
    .ks-cal__tab { padding: 6px 9px; font-size: 11px; }
}



/* ── 4b. Sidebar brand lockup — HERO mark variant (Session 25 brand pass) ───
   When the sidebar brand block carries .ks-brand-sidebar--hero, it shows the
   full kosis-hero.svg (three angels + rays + kinnor medallion + shepherd's
   staff) instead of the compact kosis-sidebar.svg. The hero art is a TALL
   portrait (200×240) — forcing it into the square 52×52 mark box would shrink
   the medallion to a dot — so this variant gives the mark its own taller box
   and STACKS the lockup (mark centered on top, wordmark + tagline beneath).
   Scoped entirely to the --hero modifier so the default lockup is untouched. */
.sidebar .brand.ks-brand-sidebar--hero {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 8px;
    padding: 20px 16px 14px;
}

/* Taller, auto-width mark so the staff + rays read clearly. Overrides the
   shared 52×52 square sizing for the hero art only. */
.sidebar .brand.ks-brand-sidebar--hero .ks-brand__mark,
.sidebar .brand.ks-brand-sidebar--hero img {
    width: auto;
    height: 64px;
    flex: 0 0 auto;
    display: block;
    margin: 0 auto;
}

/* Center the stacked wordmark/tagline under the mark. */
.sidebar .brand.ks-brand-sidebar--hero > div {
    align-items: center;
    text-align: center;
}

/* Tablet (88px icon sidebar): the wordmark/tagline are already hidden by the
   existing tablet rule; just keep the hero mark centered and a touch smaller
   so it fits the narrow rail without crowding. */
@media (max-width: 767px) and (min-width: 768px) {
    .sidebar .brand.ks-brand-sidebar--hero {
        padding: 16px 6px 10px;
    }
    .sidebar .brand.ks-brand-sidebar--hero .ks-brand__mark,
    .sidebar .brand.ks-brand-sidebar--hero img {
        height: 48px;
    }
}

/* ── Rehearsal schedule editor (create + edit-choir) ─────────────────────── */
.ks-reh-days { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 10px; }
.ks-reh-day input { position: absolute; opacity: 0; width: 0; height: 0; }
.ks-reh-day span {
    display: inline-block; padding: 6px 12px; border: 1px solid var(--ks-border);
    border-radius: 999px; font-size: 12px; cursor: pointer; color: var(--ks-navy);
    background: #fff; user-select: none; transition: background .12s, border-color .12s;
}
.ks-reh-day input:checked + span { background: var(--ks-sage); color: #fff; border-color: var(--ks-sage); }
.ks-reh-day input:focus-visible + span { outline: 2px solid var(--ks-gold); outline-offset: 2px; }
.ks-reh-row { display: flex; flex-wrap: wrap; gap: 10px; }
.ks-reh-field { display: flex; flex-direction: column; gap: 4px; flex: 1 1 120px; }
.ks-reh-field label { font-size: 12px; color: var(--ks-slate); }
.ks-reh-field input, .ks-reh-field select {
    padding: 8px 10px; border: 1px solid var(--ks-border); border-radius: 8px;
    font-size: 13px; background: #fff; color: var(--ks-navy);
}
/* ==========================================================================
   SIDEBAR FIT — zoom-safe full height + single scroll region  (2026-08-18)
   DESKTOP sidebar only (min-width:769px); the mobile drawer is left as-is.
   Bug fixed: on some displays the nav was cut off (scroll dead-ended around
   "Policy & rules"). Two causes, both handled:
     1) The fixed sidebar height was 100dvh; under CSS `zoom` (large screens)
        and mobile browser-chrome, dvh mis-measures across browsers, so the
        column ran off the viewport and clipped the nav. Fix: derive height
        from top:0 + bottom:0 — exact at any zoom / device, no vh/dvh.
     2) The sidebar ROOT and its <nav> both scrolled, so neither reliably
        reached the bottom items. Fix: root never scrolls; <nav> owns the one
        scroll region. Brand, profile pills and scripture footer stay pinned.
   ========================================================================== */
@media (min-width: 769px) {
    .sidebar,
    aside.sidebar {
        top: 0;
        bottom: 0;
        height: auto;             /* height = viewport via top/bottom (zoom-safe) */
        overflow: hidden;         /* root never scrolls */
    }
    .sidebar nav {
        flex: 1 1 auto;           /* nav takes all remaining height … */
        min-height: 0;            /* … and may shrink so it can scroll */
        overflow-y: auto;         /* the ONE scroll region */
        overflow-x: hidden;
        overscroll-behavior: contain;
    }
    /* Genuinely short windows (small laptops, half-height splits): give the menu
       every pixel — the decorative scripture yields rather than pushing links
       off screen. Taller windows keep the verse pinned at the bottom. */
    @media (max-height: 640px) {
        .sidebar .ks-sidebar-footer { display: none; }
    }
}

/* ==========================================================================
   MOBILE "MORE" SHEET — polish  (2026-08-18)
   v2 already caps the sheet at 80dvh and scrolls; add the scroll-chaining
   guard and lock the page behind the sheet while it's open, to match live and
   standard mobile bottom-sheet behaviour.
   ========================================================================== */
@media (max-width: 1023px) {
    .ks-more-sheet { overscroll-behavior: contain; }
    body.more-open { overflow: hidden; }
}
