/* ──────────────────────────────────────────────────────────────────
   WSM ServiceManager — Public-chrome styles (Bundle M)

   Shared theme tokens, persistent navbar, theme toggle, footer.
   LIGHT is the default; DARK activates via [data-theme="dark"] on <html>.

   Each public-facing page links this file in <head> AFTER the FOUC-
   prevention boot script (renderPublicThemeBoot in config.php) and then
   adds its own page-specific styles in an inline <style> block.

   Don't put page-specific selectors here. This file is *chrome only*.
   ────────────────────────────────────────────────────────────────── */

/* ─── Theme tokens ─────────────────────────────────────────────── */

:root {
    /* LIGHT theme — default */
    --bg:            #fafafa;
    --surface-1:     #ffffff;
    --surface-2:     #f3f3f3;
    --surface-3:     #e8e8e8;
    --border-1:      rgba(0,0,0,.08);
    --border-2:      rgba(0,0,0,.14);
    --text:          #1a1a1a;
    --text-soft:     #555555;
    --muted:         #888888;
    --accent:        #2a8c7a;                /* slightly deeper teal for contrast on white */
    --accent-hover:  #1f7264;
    --accent-glow:   rgba(42,140,122,.10);
    --accent-text:   #ffffff;                /* text on accent-bg buttons — dark teal needs light text */
    --spotify:       #1db954;                /* always Spotify green on the CTA / play buttons */

    /* Backdrop overlay base colour, used in linear-gradients on the
       series/playlist/student-guide hero panes. Light mode fades the
       imagery into white; dark mode into black. Title text + shadow
       flip with the theme so they remain legible against whichever
       way the overlay is fading. */
    --backdrop-overlay-rgb: 255, 255, 255;
    --backdrop-text:        #1a1a1a;
    --backdrop-text-shadow: 0 1px 3px rgba(255,255,255,.7);
    --backdrop-text-soft:   #444444;

    /* Glass-card "bubble" behind title text that overlays the backdrop.
       Strong opacity + heavy backdrop-blur on the wrapping element keeps
       title text legible no matter how busy the mosaic / hero image is. */
    --bubble-bg:            rgba(255,255,255,.78);
    --bubble-border:        rgba(255,255,255,.6);
    --bubble-shadow:        0 6px 20px rgba(0,0,0,.10);

    /* ─── Canonical glass tokens (Bundle KK) ────────────────────────
       Single source of truth for the glass card chrome used across
       the public site (worship / lessons / series / playlists). Every
       glassed surface — head cards, content rows, empty states, tabs
       rows — reads these so theme switching is one place to change.
       Previously the rgba values were inlined per-page and every
       page got its own light-mode override via [data-theme="light"]
       — but light is the DEFAULT (no attribute set), so those
       overrides never fired and light mode rendered the dark values.
       Now: `:root` defines the light values (default), and
       `[data-theme="dark"]` overrides for dark mode. The cascade
       works as designed. */
    --glass-surface:        rgba(255, 255, 255, 0.88);
    --glass-surface-hover:  rgba(255, 255, 255, 0.94);
    --glass-border:         rgba(255, 255, 255, 0.70);
    --glass-border-hover:   rgba(0, 0, 0, 0.10);
    --glass-shadow:         0 8px 24px rgba(0, 0, 0, 0.14);
    --glass-shadow-sm:      0 6px 18px rgba(0, 0, 0, 0.10);
    --glass-blur:           blur(20px) saturate(140%);
    --glass-blur-head:      blur(24px) saturate(140%);
}

[data-theme="dark"] {
    --bg:            #0a0a0a;
    --surface-1:     #111111;
    --surface-2:     #181818;
    --surface-3:     #232323;
    --border-1:      rgba(255,255,255,.06);
    --border-2:      rgba(255,255,255,.10);
    --text:          #f0f0f0;
    --text-soft:     #c0c0c0;
    --muted:         #888888;
    --accent:        #52c1af;
    --accent-hover:  #6dd0bf;
    --accent-glow:   rgba(82,193,175,.18);
    --accent-text:   #0a0a0a;                /* light accent button → black text */

    --backdrop-overlay-rgb: 10, 10, 10;
    --backdrop-text:        #ffffff;
    --backdrop-text-shadow: 0 2px 8px rgba(0,0,0,.7);
    --backdrop-text-soft:   rgba(255,255,255,.85);

    --bubble-bg:            rgba(0,0,0,.55);
    --bubble-border:        rgba(255,255,255,.10);
    --bubble-shadow:        0 6px 20px rgba(0,0,0,.4);
    /* --spotify stays constant */

    /* Canonical glass tokens (dark) */
    --glass-surface:        rgba(15, 20, 22, 0.78);
    --glass-surface-hover:  rgba(20, 28, 30, 0.85);
    --glass-border:         rgba(255, 255, 255, 0.10);
    --glass-border-hover:   rgba(255, 255, 255, 0.18);
    --glass-shadow:         0 8px 28px rgba(0, 0, 0, 0.35);
    --glass-shadow-sm:      0 6px 18px rgba(0, 0, 0, 0.25);
}

/* ─── Reset + base ─────────────────────────────────────────────── */

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--text);
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    min-height: 100vh;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }

/* ─── Persistent public nav ────────────────────────────────────── */

.pub-head {
    background: var(--surface-1);
    border-bottom: 1px solid var(--border-1);
    position: sticky;
    top: 0;
    z-index: 10;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}
.pub-head-inner {
    max-width: 1080px;
    margin: 0 auto;
    padding: 12px 20px;
    display: flex;
    align-items: center;
    gap: 24px;
    flex-wrap: wrap;
}
.pub-brand {
    color: var(--text);
    font-weight: 800;
    font-size: 1.05rem;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 10px;
}
.pub-brand:hover { color: var(--accent); }
.pub-brand-logo {
    height: 48px;
    width: auto;
    display: block;
    flex-shrink: 0;
}
/* Two-logo variants: if both dark + light logos are uploaded, CSS swaps
   them with theme. If only one is uploaded, the helper drops the variant
   classes and shows it in both modes. */
.pub-brand-logo-dark  { display: none; }
.pub-brand-logo-light { display: block; }
[data-theme="dark"] .pub-brand-logo-dark  { display: block; }
[data-theme="dark"] .pub-brand-logo-light { display: none; }

.pub-nav { display: flex; gap: 4px; flex-wrap: wrap; margin-left: auto; }
.pub-nav a {
    color: var(--text-soft);
    padding: 6px 12px;
    border-radius: 999px;
    font-size: 0.88rem;
    font-weight: 500;
    transition: background 0.12s, color 0.12s;
}
.pub-nav a:hover { background: var(--surface-2); color: var(--text); }
.pub-nav a.is-active { color: var(--accent); background: var(--accent-glow); }

/* ─── Shared public page-header card (Bundle SS) ────────────────────
   One block that replaces four drifted per-page copies (.pub-glass-head
   in index/series, .ws-head in worship, .playlist-head in playlist).
   Left-aligned title, ministry name as eyebrow, text-shadow on all
   pages (needed for legibility over the mosaic backdrop on worship and
   playlist; harmless on lessons/series).

   The optional .pub-page-head-extra slot flexes right on wide viewports
   for trailing content (worship's sort dropdown, playlist's Spotify
   CTA) and drops beneath the title on narrow ones. Callers pass HTML
   into that slot via renderPublicPageHeader($title, $subtitle, $extra). */
.pub-page-head {
    position: relative;
    z-index: 1;
    margin: 0 0 36px;
    padding: 28px 32px;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
    background: var(--glass-surface);
    backdrop-filter: var(--glass-blur-head);
    -webkit-backdrop-filter: var(--glass-blur-head);
    border: 1px solid var(--glass-border);
    border-radius: 20px;
    box-shadow: var(--glass-shadow);
}
.pub-page-head-text { min-width: 0; flex: 1; }
.pub-page-head-eyebrow {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--accent);
    margin: 0 0 8px;
    text-shadow: var(--backdrop-text-shadow);
}
.pub-page-head-title {
    font-size: 2rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    margin: 0;
    line-height: 1.1;
    text-shadow: var(--backdrop-text-shadow);
}
.pub-page-head-sub {
    color: var(--text-soft);
    font-size: 0.95rem;
    margin: 8px 0 0;
    text-shadow: var(--backdrop-text-shadow);
}
.pub-page-head-extra {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
    flex-wrap: wrap;
}
@media (max-width: 640px) {
    .pub-page-head { padding: 20px 18px; border-radius: 14px; margin-bottom: 24px; }
    .pub-page-head-title { font-size: 1.6rem; }
}


/* Theme toggle button — fixed-position FAB at the bottom-right corner.
   Always visible regardless of scroll. The icon shows the *current*
   theme: sun for light, moon for dark. Aria-label clarifies the action. */
.pub-theme-toggle {
    position: fixed;
    bottom: 20px;
    right: 20px;
    z-index: 100;
    background: var(--surface-1);
    border: 1px solid var(--border-2);
    color: var(--text-soft);
    width: 44px;
    height: 44px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: color 0.12s, border-color 0.12s, background 0.12s, transform 0.12s, box-shadow 0.12s;
    flex-shrink: 0;
    padding: 0;
    box-shadow: 0 4px 14px rgba(0,0,0,.18);
}
.pub-theme-toggle:hover {
    color: var(--accent);
    border-color: var(--accent);
    transform: scale(1.05);
    box-shadow: 0 6px 18px rgba(0,0,0,.22);
}
.pub-theme-toggle:active { transform: scale(0.96); }

/* Icon visibility: in light mode show sun (current state); in dark show
   moon. Click the button to flip. The two svgs are siblings inside the
   button; only one is `display: block` at a time. */
.theme-icon-sun  { display: block; }
.theme-icon-moon { display: none; }
[data-theme="dark"] .theme-icon-sun  { display: none; }
[data-theme="dark"] .theme-icon-moon { display: block; }

/* ─── Hide-content toggle (Bundle EE) ──────────────────────────
   Sits to the LEFT of the theme toggle, same FAB treatment. Toggles
   `is-content-hidden` on body; the body class hides the page's main
   container and shows just the backdrop, logo, and the two FABs.
   Esc restores. */
.pub-hide-toggle {
    position: fixed;
    bottom: 20px;
    right: 74px; /* theme toggle 20 + 44 + 10 gap = 74 */
    z-index: 100;
    background: var(--surface-1);
    border: 1px solid var(--border-2);
    color: var(--text-soft);
    width: 44px;
    height: 44px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: color 0.12s, border-color 0.12s, background 0.12s, transform 0.12s, box-shadow 0.12s;
    flex-shrink: 0;
    padding: 0;
    box-shadow: 0 4px 14px rgba(0,0,0,.18);
}
.pub-hide-toggle:hover {
    color: var(--accent);
    border-color: var(--accent);
    transform: scale(1.05);
    box-shadow: 0 6px 18px rgba(0,0,0,.22);
}
.pub-hide-toggle:active { transform: scale(0.96); }

/* Icon swap: show "eye" when content is visible (click → hide),
   show "eye-off" when content is hidden (click → show). */
.hide-icon-show { display: block; }
.hide-icon-hide { display: none; }
body.is-content-hidden .pub-hide-toggle { color: var(--accent); border-color: var(--accent); }
body.is-content-hidden .hide-icon-show { display: none; }
body.is-content-hidden .hide-icon-hide { display: block; }

/* Content fade-out. We target every known "main" container so the
   hide-content button works without needing each page to call it
   explicitly. The fade gives motion; the visibility:hidden after the
   transition stops the screenreader / tab cycle from finding the
   contents. */
/* Content fade-out. We target every known "main" container so the
   hide-content button works without needing each page to call it
   explicitly. The fade gives motion; the visibility:hidden after the
   transition stops the screenreader / tab cycle from finding the
   contents.
   Bundle GG — explicit `opacity: 1` base state so the transition has
   a concrete starting value, and `!important` on the hide rule so
   per-page local styles (worship.php's .ws-shell has its own block)
   can't beat the body-class compound selector via load order.
   Bundle HH — added `body[data-content-hidden]` selector ALONGSIDE
   the .is-content-hidden class selector for redundancy. If anything
   ever blocks classList add (CSS, JS), the data attribute path is
   set in parallel, so the fade still fires. Also: the button now has
   a clear pressed-state border so the user can tell the click
   registered even if the content fade somehow fails. */
#pub-main, .pub-main, .ws-shell, .playlist-shell, .lr-main {
    opacity: 1;
    transition: opacity 320ms ease, transform 320ms ease;
}
body.is-content-hidden #pub-main,
body.is-content-hidden .pub-main,
body.is-content-hidden .ws-shell,
body.is-content-hidden .playlist-shell,
body.is-content-hidden .lr-main,
body[data-content-hidden] #pub-main,
body[data-content-hidden] .pub-main,
body[data-content-hidden] .ws-shell,
body[data-content-hidden] .playlist-shell,
body[data-content-hidden] .lr-main {
    opacity: 0 !important;
    transform: translateY(8px);
    pointer-events: none;
}
/* Strong pressed-state on the button so the click registers visibly
   even if something else upstream stops the fade. */
body.is-content-hidden .pub-hide-toggle,
body[data-content-hidden] .pub-hide-toggle {
    color: var(--accent) !important;
    border-color: var(--accent) !important;
    background: rgba(82, 193, 175, 0.15) !important;
}

/* Also hide the pub-nav so only the logo + FABs remain. The brand
   logo lives INSIDE pub-head; we hide everything in there EXCEPT the
   brand. */
body.is-content-hidden .pub-head .pub-nav { opacity: 0; pointer-events: none; transition: opacity 220ms; }

@media (prefers-reduced-motion: reduce) {
    #pub-main, .pub-main, .ws-shell, .playlist-shell, .lr-main {
        transition: none;
    }
    body.is-content-hidden #pub-main,
    body.is-content-hidden .pub-main,
    body.is-content-hidden .ws-shell,
    body.is-content-hidden .playlist-shell,
    body.is-content-hidden .lr-main {
        transform: none;
    }
}

/* ─── Footer ───────────────────────────────────────────────────
   Works whether the <p class="pub-foot"> sits inside the page main
   container or stands as a sibling — the max-width centres it either
   way. Margin-top creates a visual separator. */
.pub-foot {
    max-width: 1080px;
    margin: 48px auto 0;
    padding: 24px 20px;
    text-align: center;
    color: var(--muted);
    font-size: 0.82rem;
    border-top: 1px solid var(--border-1);
}
.pub-foot-admin { color: var(--muted); }
.pub-foot-admin:hover { color: var(--accent); }

/* ─── Mobile chrome adjustments ────────────────────────────────── */

@media (max-width: 480px) {
    .pub-nav a { padding: 6px 10px; font-size: 0.82rem; }
    .pub-brand-logo { height: 38px; }
}

/* ─── Public banner (Bundle FF) ────────────────────────────────────
   Sits between the header and the page main content. Frosted-glass
   panel like .pub-page-head but horizontal and narrower vertically.
   Image (uploaded file OR SVG icon) on the left, Quill-rendered HTML
   on the right.
   Variations:
   - When the banner has a banner_link_url, the whole tile becomes an
     anchor (.is-linked) with a subtle hover lift
   - When no image is configured, the .pub-banner-image div isn't
     rendered and text fills the row
   - On print contexts (anything in @media print), suppressed entirely
     because handout printouts shouldn't carry transient announcements */
.pub-banner {
    display: flex;
    align-items: center;
    gap: 14px;
    /* Bundle GG — width matches the worship content card edge.
       Bundle HH — switched to a CSS variable so playlist pages (which
       have a 620px content shell) can override locally without the
       banner extending past their narrower content card. */
    max-width: var(--pub-banner-max, 1040px);
    margin: 20px auto 28px;
    padding: 10px 18px;
    background: var(--bubble-bg);
    backdrop-filter: blur(20px) saturate(140%);
    -webkit-backdrop-filter: blur(20px) saturate(140%);
    border: 1px solid var(--bubble-border);
    border-left: 4px solid var(--accent);
    border-radius: 14px;
    box-shadow: var(--bubble-shadow);
    text-decoration: none;
    color: inherit;
    position: relative;
    z-index: 1;
}
/* Pages that have a narrower content shell can opt-in to a matching
   banner width by adding `pub-narrow` to body. Currently used by
   playlist.php (620px content), so the banner edge aligns with the
   .pub-page-head card edge. */
body.pub-narrow {
    --pub-banner-max: 620px;
}
.pub-banner.is-linked {
    transition: transform 0.16s, box-shadow 0.16s, border-left-color 0.16s;
}
.pub-banner.is-linked:hover {
    transform: translateY(-1px);
    box-shadow: 0 8px 22px rgba(0,0,0,.22);
    border-left-color: var(--accent);
}
.pub-banner-image {
    flex-shrink: 0;
    width: 52px;
    height: 52px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--accent);
    border-radius: 8px;
    overflow: hidden;
    background: rgba(0,0,0,.04);
}
[data-theme="dark"] .pub-banner-image { background: rgba(255,255,255,.04); }
.pub-banner-img {
    max-width: 100%;
    max-height: 100%;
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}
.pub-banner-svg {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    padding: 12px;
    box-sizing: border-box;
}
.pub-banner-svg svg {
    width: 100%;
    height: 100%;
}
.pub-banner-text {
    flex: 1;
    min-width: 0;
    font-size: 0.95rem;
    line-height: 1.5;
}
.pub-banner-text p { margin: 0; }
.pub-banner-text p + p { margin-top: 8px; }
.pub-banner-text a {
    color: var(--accent);
    text-decoration: underline;
}
.pub-banner-text strong { color: var(--text); }

/* Banner participates in the hide-content toggle (Bundle EE) so it
   fades along with everything else when the viewer wants to admire
   the backdrop. */
.pub-banner {
    transition: opacity 320ms ease, transform 320ms ease,
                box-shadow 0.16s, border-left-color 0.16s;
}
body.is-content-hidden .pub-banner {
    opacity: 0;
    pointer-events: none;
}

@media (max-width: 600px) {
    .pub-banner {
        flex-direction: column;
        text-align: center;
        padding: 16px;
    }
    .pub-banner-image {
        width: 80px;
        height: 80px;
    }
}

@media print {
    .pub-banner { display: none !important; }
}
