/* =============================================================
   PULSE — shared design system
   Colors and typography per Anytime Fitness Brand Manual:
     Burple #5A4294 (PMS 2097C) — primary
     Cyan   #47BEDB (PMS 3125C) — secondary
     Red    #F5333F (PMS 032C)  — accent
     Dark Grey PMS 425C
     Typography: Montserrat (digital backup for F37 Moon)
   ============================================================= */

/* WL#12 — FOUC reveal. Pages opt-in via a tiny inline <style>+<script>
   block in <head> that hides <html> until either this rule applies
   (styles.css finished parsing) OR a 2.5s safety timer fires. Result:
   no flash of unstyled HTML during cold loads. */
html { visibility: visible; }
:root {
  color-scheme: light;
  --brand:       #5A4294;
  --brand-dark:  #2D2160;
  --brand-soft:  #EFEAF7;
  --accent:      #F5333F;
  --accent-soft: #FEE5E7;
  --info:        #47BEDB;
  --info-soft:   #E1F4F9;
  --warn:        #B45309;
  --warn-soft:   #FEF3C7;
  --ok:          #15803D;
  --ok-soft:     #DCFCE7;
  --danger:      #DC2626;
  --danger-soft: #FEE2E2;
  --bg:          #F6F4FB;          /* faint Burple-tinted neutral */
  --card:        #FFFFFF;
  --ink:         #0E0E1A;
  --ink-soft:    #62607A;
  --ink-faint:   #8B89A1;
  --line:        #ECEAF3;
  --line-strong: #DCD9E8;
  /* Modernized: crisper, less diffuse shadows. Lifts cards a hair without that Web 2.0 glow. */
  --shadow:    0 1px 2px rgba(15, 15, 26, 0.04);
  --shadow-md: 0 4px 12px rgba(15, 15, 26, 0.06), 0 1px 2px rgba(15, 15, 26, 0.04);
  --shadow-lg: 0 16px 40px rgba(15, 15, 26, 0.10), 0 2px 6px rgba(15, 15, 26, 0.04);
  /* Spacing + radius tokens — used to drive a tighter, Linear-esque grid. */
  --r-sm: 6px;
  --r-md: 8px;
  --r-lg: 10px;
  /* Bumped 16 → 20 so curvature is prominent enough that the eye
     stops measuring relative-to-width — a wide announcement card
     and a narrow clock card both read as "very rounded" instead
     of "wide one looks flatter." iOS / Liquid-Glass-adjacent feel.
     Matches the inline 20px now used everywhere on hub.html. */
  --r-xl: 20px;

  /* ---- Motion design tokens ----
     Centralizing duration + easing keeps every transition feeling
     like part of the same product. New code should reach for these
     instead of hand-rolling values.
       --ease-out    : standard "snappy in, settle out" curve
       --ease-spring : bouncier — use sparingly for delight moments
       --ease-in     : "linger, then go" — use for exit-only transitions
       --dur-fast    : hover/focus feedback (140ms)
       --dur-base    : drawers, modals, toggles (220ms)
       --dur-slow    : page-level entrances, big reveals (420ms) */
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-in:     cubic-bezier(0.4, 0, 1, 1);
  --dur-fast: 140ms;
  --dur-base: 220ms;
  --dur-slow: 420ms;

  /* ---- Liquid Glass tokens ----
     Used by the Hub card rules at the bottom of this file (and the
     Hub-only body gradient) to give cards a frosted-pane feel — the
     iOS / visionOS aesthetic. Light mode uses a near-white translucent
     fill; behind a card you see a faint colour wash from the body
     gradient. Dark mode uses a near-black translucent fill so cards
     read as dim panes of glass.
       --glass-fill      : card surface (rgba so backdrop-filter shows through)
       --glass-blur      : backdrop blur + saturation lift
       --glass-highlight : inset top edge (catches the imaginary light source)
       --glass-shadow    : ambient float shadow under the card
       --glass-border    : outline (slightly stronger than --line so the
                            edge is crisp even on a saturated background) */
  /* Intensity dial v3 — Ben said v2 still wasn't obvious. Going
     full visionOS: cards are now 32% opaque so the mesh shows
     through dramatically; blur is 40px (was 28) so what shows
     through reads as a colour wash, not legible content behind;
     saturate 240% so colours pop like wet glass; double inset
     highlights for a polished-bevel look; coloured edge glow on
     the border to suggest internal refraction. */
  --glass-fill:      rgba(255, 255, 255, 0.32);
  --glass-blur:      blur(40px) saturate(240%);
  --glass-highlight: inset 0 1px 0 rgba(255, 255, 255, 1),
                     inset 0 -1px 0 rgba(255, 255, 255, 0.35),
                     inset 1px 0 0 rgba(255, 255, 255, 0.20),
                     inset -1px 0 0 rgba(255, 255, 255, 0.20);
  --glass-shadow:    0 18px 48px rgba(90, 66, 148, 0.18),
                     0 6px 16px rgba(15, 15, 26, 0.08),
                     0 1px 2px rgba(15, 15, 26, 0.04);
  --glass-border:    rgba(255, 255, 255, 0.75);
}

/* ---- Dark theme ----
   Activated by setting data-theme="dark" on the <html> element.
   Tuned for WCAG AA on body text + visible separation between
   surface, card, hover and active states. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --brand:       #B49AFF;        /* lifted from #9C7FE0 — passes AA on dark bg */
  --brand-dark:  #6A4FB8;
  --brand-soft:  rgba(180, 154, 255, 0.22);  /* stronger so active/hover states read */
  --accent:      #FF8085;
  --accent-soft: rgba(255, 128, 133, 0.22);
  --info:        #6ED3E8;
  --info-soft:   rgba(110, 211, 232, 0.20);
  --warn:        #F4BD68;
  --warn-soft:   rgba(244, 189, 104, 0.22);
  --ok:          #6FD89A;
  --ok-soft:     rgba(111, 216, 154, 0.22);
  --danger:      #F87171;
  --danger-soft: rgba(248, 113, 113, 0.22);
  --bg:          #0E0E16;
  --card:        #1A1925;
  --ink:         #F2F1F8;
  --ink-soft:    #B8B5CC;
  --ink-faint:   #7B7891;
  --line:        #2E2C3D;
  --line-strong: #3D3B4F;
  --shadow:    0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 16px 40px rgba(0, 0, 0, 0.55), 0 2px 6px rgba(0, 0, 0, 0.35);

  /* Dark-mode glass v3 — smoked obsidian. Same intensity rules
     as light, just inverted: very low alpha so mesh bleeds
     through, big blur, brighter inset top edge for that
     wet-polish reflection. */
  --glass-fill:      rgba(26, 25, 37, 0.28);
  --glass-blur:      blur(44px) saturate(220%);
  --glass-highlight: inset 0 1px 0 rgba(255, 255, 255, 0.22),
                     inset 0 -1px 0 rgba(255, 255, 255, 0.06),
                     inset 1px 0 0 rgba(255, 255, 255, 0.06),
                     inset -1px 0 0 rgba(255, 255, 255, 0.06);
  --glass-shadow:    0 22px 56px rgba(0, 0, 0, 0.65),
                     0 6px 16px rgba(0, 0, 0, 0.45),
                     0 1px 2px rgba(0, 0, 0, 0.30);
  --glass-border:    rgba(255, 255, 255, 0.18);
}
:root[data-theme="dark"] .topbar { background: var(--card); border-bottom-color: var(--line); }
:root[data-theme="dark"] .chat-main { background: #16151F; }
:root[data-theme="dark"] .chat-sidebar { background: #1A1925; border-right-color: var(--line); }
:root[data-theme="dark"] .modal-bg { background: rgba(0,0,0,0.7); }
:root[data-theme="dark"] .msg .att-file { background: rgba(255,255,255,0.08); border-color: var(--line); color: var(--ink); }
:root[data-theme="dark"] .msg.system .bubble { color: var(--ink-soft); }
:root[data-theme="dark"] .msg:not(.own) .bubble { background: #25243A; border-color: var(--line); color: var(--ink); }
:root[data-theme="dark"] .day-divider { background: #25243A; color: var(--ink-soft); }
:root[data-theme="dark"] table.dataset thead th { background: rgba(180,154,255,0.10); color: var(--ink); }
:root[data-theme="dark"] table.dataset tbody tr:hover { background: rgba(180,154,255,0.08); }
:root[data-theme="dark"] .chat-composer { background: var(--card); border-top-color: var(--line); }
:root[data-theme="dark"] .chat-composer textarea,
:root[data-theme="dark"] .field input,
:root[data-theme="dark"] .field textarea,
:root[data-theme="dark"] .field select {
  background: #25243A; color: var(--ink); border-color: var(--line);
}
:root[data-theme="dark"] .chat-composer textarea::placeholder,
:root[data-theme="dark"] .field input::placeholder,
:root[data-theme="dark"] .field textarea::placeholder { color: rgba(184,181,204,0.65); }
:root[data-theme="dark"] .pill.muted { background: rgba(255,255,255,0.10); color: var(--ink); }
:root[data-theme="dark"] .pill.brand { background: rgba(180,154,255,0.22); color: var(--brand); }
:root[data-theme="dark"] .article-body code { background: rgba(180,154,255,0.20); }
:root[data-theme="dark"] .article-body blockquote { background: rgba(180,154,255,0.12); }

/* Sidebar room rows — give hover + active states real visual weight in dark mode */
:root[data-theme="dark"] .chat-rooms button.room:hover,
:root[data-theme="dark"] .chat-rooms button.group-header:hover { background: rgba(180,154,255,0.14); }
:root[data-theme="dark"] .chat-rooms button.room.active {
  background: rgba(180,154,255,0.28); color: #fff;
}
:root[data-theme="dark"] .chat-rooms .room .room-icon { background: rgba(180,154,255,0.20); color: var(--brand); }

/* User menu + club switcher dropdowns — bump separator & icon visibility */
:root[data-theme="dark"] .user-menu .user-menu-pop,
:root[data-theme="dark"] .club-switcher .menu { background: var(--card); border-color: var(--line); }
:root[data-theme="dark"] .user-menu .user-menu-icon { color: var(--ink); }
:root[data-theme="dark"] .user-menu .user-menu-icon:hover { background: rgba(180,154,255,0.20); color: var(--brand); }
:root[data-theme="dark"] .club-switcher .trigger { background: rgba(255,255,255,0.06); border-color: var(--line); }
:root[data-theme="dark"] .club-switcher .menu button:hover { background: rgba(180,154,255,0.14); }

/* Trust banner — readable on dark sidebar */
:root[data-theme="dark"] .chat-trust-banner {
  background: rgba(180,154,255,0.10);
  border-color: rgba(180,154,255,0.25);
  color: var(--ink-soft);
}
:root[data-theme="dark"] .chat-trust-banner strong { color: var(--ink); }

/* Pending attachments chip — dark mode contrast */
:root[data-theme="dark"] .chat-pending .pending-item {
  background: rgba(180,154,255,0.20);
  border-color: rgba(180,154,255,0.35);
  color: var(--brand);
}

/* Cards on hub need a touch more separation in dark mode */
:root[data-theme="dark"] .card { background: var(--card); border-color: var(--line); }
:root[data-theme="dark"] .card:hover { border-color: var(--brand); }

/* Topbar nav links read better with a stronger active state */
:root[data-theme="dark"] .topbar .nav a,
:root[data-theme="dark"] .topbar .nav button { color: var(--ink); }
:root[data-theme="dark"] .topbar .nav a:hover,
:root[data-theme="dark"] .topbar .nav button:hover,
:root[data-theme="dark"] .topbar .nav a.active { background: rgba(180,154,255,0.20); color: var(--brand); }

* { box-sizing: border-box; }
html, body {
  margin: 0; padding: 0;
  background: var(--bg); color: var(--ink);
  font-family: "Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---- Layout ---- */
.wrap { max-width: 1080px; margin: 0 auto; padding: 28px 22px 56px; }
/* Use dynamic viewport units so iOS Safari's URL bar doesn't push the
   centred card below the visual midpoint. 100vh measures the layout
   viewport (URL bar excluded), making the wrapper taller than the
   visible area on mobile; 100dvh adjusts as the bar collapses. The
   100vh declaration stays first as a fallback for older browsers. */
.center-wrap { min-height: 100vh; min-height: 100dvh; display: flex; align-items: center; justify-content: center; padding: 24px; }

/* ---- Top bar ----
   The wrapper #topbar is the sticky container. The inner .topbar
   element keeps its own background + border so the sticky chrome
   reads cleanly over scrolled content. */
#topbar {
  position: sticky; top: 0; z-index: 100;
  background: var(--card);
}
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 20px; background: var(--card); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 100;
  backdrop-filter: saturate(180%) blur(8px);
  box-shadow: 0 1px 0 rgba(15, 15, 26, 0.04);
}
:root[data-theme="dark"] #topbar { background: var(--card); }
.topbar .brand { display: flex; align-items: center; gap: 10px; }
/* Left-side cluster of the topbar — wordmark + energy dot + club switcher.
   Putting the switcher on the left makes the PULSE wordmark's pulse
   animation visually flow *into* the active club. */
.topbar-left { display: flex; align-items: center; gap: 14px; min-width: 0; }
.topbar-left > .club-switcher { flex-shrink: 1; min-width: 0; }
.pulse-energy-link {
  display: inline-block; width: 18px; height: 2px;
  background: linear-gradient(90deg, var(--brand) 0%, var(--brand) 60%, transparent 100%);
  border-radius: 2px; position: relative;
  animation: pulse-energy-flow 2.4s ease-in-out infinite;
}
.pulse-energy-link::after {
  content: ""; position: absolute; right: -3px; top: 50%;
  transform: translateY(-50%);
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--brand);
  box-shadow: 0 0 6px var(--brand);
}
@keyframes pulse-energy-flow {
  0%, 100% { opacity: 0.55; transform: translateX(0); }
  50%      { opacity: 1;    transform: translateX(2px); }
}
@media (prefers-reduced-motion: reduce) {
  .pulse-energy-link { animation: none; opacity: 0.7; }
}
@media (max-width: 640px) {
  .pulse-energy-link { display: none; }
  .topbar-left { gap: 10px; }
}
.topbar .logo {
  width: 28px; height: 28px;
  display: grid; place-items: center;
  background: transparent;
}
.topbar .logo img {
  width: 100%; height: 100%; object-fit: contain; display: block;
  transform-origin: 50% 80%;     /* pivot near the feet so the bob looks like running */
  animation: pulse-runner 9s ease-in-out infinite;
}
/* Subtle run-cycle: the logo sits still ~85% of the time, then bursts into a
   short 4-step gait (tilt + bob) before settling. Calibrated to be playful
   without being distracting. */
@keyframes pulse-runner {
  0%, 78%, 100% { transform: translateY(0) rotate(0deg); }
  80%  { transform: translateY(-3px) rotate(-6deg); }
  82%  { transform: translateY(0)    rotate(0deg); }
  85%  { transform: translateY(-3px) rotate(6deg); }
  88%  { transform: translateY(0)    rotate(0deg); }
  91%  { transform: translateY(-3px) rotate(-6deg); }
  94%  { transform: translateY(0)    rotate(0deg); }
}
/* Honour the user's "reduce motion" preference. */
@media (prefers-reduced-motion: reduce) {
  .topbar .logo img { animation: none; }
}
.topbar .brand-text .name { font-size: 15px; font-weight: 700; letter-spacing: -0.3px; color: var(--ink); display: inline-flex; align-items: center; gap: 4px; }
.brand-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent);
  display: inline-block;
  box-shadow: 0 0 0 2px rgba(245,51,63,0.18);
  /* Subtle pulse — a nod to the product name. */
  animation: brand-pulse 2.4s ease-in-out infinite;
}
@keyframes brand-pulse {
  0%, 100% { opacity: 1;   transform: scale(1); }
  50%      { opacity: 0.6; transform: scale(1.15); }
}
.topbar .brand-text .tagline { font-size: 11px; font-weight: 600; color: var(--ink-soft); letter-spacing: 0.5px; margin-top: 1px; }
.topbar .nav { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.chat-badge {
  background: var(--accent);
  color: #fff;
  font-size: 10px;
  font-weight: 800;
  padding: 1px 6px;
  border-radius: 999px;
  margin-left: 6px;
  min-width: 18px;
  text-align: center;
  letter-spacing: 0.2px;
  display: inline-block;
  vertical-align: middle;
  animation: chat-badge-pop 0.18s ease-out;
}
/* Auto-mounted via [data-chat-badge] — hide when toggled off so an
   empty pill doesn't appear next to "Chat" while the count is 0. */
.chat-badge[hidden] { display: none !important; }
@keyframes chat-badge-pop {
  0%   { transform: scale(0.6); opacity: 0; }
  100% { transform: scale(1);   opacity: 1; }
}

/* Floating help FAB + chat-bot style panel — replaces the old (?) icon.
   Pinned bottom-right on desktop, expands full-screen on mobile so it's
   just as usable on a phone. */
.help-fab {
  /* Pill shape (was: 56x56 circle) so the "Help" label sits inside.
     Ben's feedback — too easy to mistake the round chat-bubble FAB
     for a chat icon; making it explicit kills that ambiguity. */
  position: fixed; right: 20px; bottom: 20px;
  min-width: 56px; height: 52px; padding: 0 18px 0 16px;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--brand) 0%, var(--brand-dark) 100%);
  color: #fff;
  border: none;
  box-shadow: 0 8px 22px rgba(90, 66, 148, 0.32), 0 2px 6px rgba(0,0,0,0.18);
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  z-index: 220;
  font-family: inherit; font-size: 14px; font-weight: 700;
  transition: transform 0.18s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.18s ease;
}
.help-fab:hover { transform: translateY(-2px) scale(1.04); box-shadow: 0 12px 28px rgba(90,66,148,0.42); }
.help-fab:active { transform: translateY(0) scale(0.98); }
.help-fab.active { transform: scale(0.92); box-shadow: 0 4px 12px rgba(90,66,148,0.32); }
.help-fab svg { width: 22px; height: 22px; position: relative; z-index: 1; flex-shrink: 0; }
.help-fab .help-fab-label {
  position: relative; z-index: 1;
  font-size: 13px; font-weight: 700; letter-spacing: 0.2px;
  white-space: nowrap;
}
/* Collapse to just the "?" on very narrow viewports so the FAB
   doesn't crowd a phone screen. */
@media (max-width: 480px) {
  .help-fab { padding: 0; width: 52px; height: 52px; justify-content: center; }
  .help-fab .help-fab-label { display: none; }
}
/* Soft pulsing aura so the button feels alive (subtle — every ~3s). */
.help-fab .help-fab-pulse {
  position: absolute; inset: 0; border-radius: 50%;
  background: var(--brand); opacity: 0.45; pointer-events: none;
  animation: help-fab-pulse 3.2s ease-out infinite;
}
@keyframes help-fab-pulse {
  0%   { transform: scale(0.9); opacity: 0.55; }
  70%  { transform: scale(1.45); opacity: 0; }
  100% { transform: scale(1.45); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .help-fab .help-fab-pulse { animation: none; opacity: 0; }
}

.help-panel {
  position: fixed; right: 20px; bottom: 90px;
  width: 380px; max-width: calc(100vw - 24px);
  height: min(560px, calc(100vh - 120px));
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: 0 18px 48px rgba(15, 15, 26, 0.22), 0 6px 16px rgba(15, 15, 26, 0.10);
  z-index: 219;
  display: none;
  flex-direction: column;
  overflow: hidden;
  transform-origin: 100% 100%;
  animation: help-panel-out 0.16s cubic-bezier(0.4, 0, 1, 1);
}
.help-panel.open {
  display: flex;
  animation: help-panel-in 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes help-panel-in {
  from { opacity: 0; transform: translateY(12px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes help-panel-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}

.help-panel-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 14px 14px 12px;
  background: linear-gradient(135deg, var(--brand) 0%, var(--brand-dark) 100%);
  color: #fff;
  flex-shrink: 0;
}
.help-panel-title { display: flex; align-items: center; gap: 10px; min-width: 0; }
.help-bot-avatar {
  width: 36px; height: 36px; border-radius: 50%;
  background: rgba(255,255,255,0.18); border: 1px solid rgba(255,255,255,0.25);
  display: grid; place-items: center; font-size: 18px;
  flex-shrink: 0;
}
.help-bot-name { font-size: 14px; font-weight: 700; letter-spacing: -0.1px; }
.help-bot-status { font-size: 11px; color: rgba(255,255,255,0.85); margin-top: 1px; }
.help-panel-close {
  width: 30px; height: 30px; border-radius: 50%;
  background: rgba(255,255,255,0.14); border: 1px solid rgba(255,255,255,0.22);
  color: #fff; cursor: pointer; display: grid; place-items: center;
  flex-shrink: 0;
  transition: background 0.12s ease;
}
.help-panel-close:hover { background: rgba(255,255,255,0.24); }

.help-panel-search {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px; border-bottom: 1px solid var(--line);
  flex-shrink: 0;
}
.help-panel-search input {
  flex: 1; background: transparent; border: none; outline: none;
  font-family: inherit; font-size: 14px; color: var(--ink);
}
.help-panel-search input::placeholder { color: var(--ink-faint); }

.help-panel-results {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: 8px 12px 14px;
}

/* Mobile: full-screen so it's actually usable on a phone. */
@media (max-width: 640px) {
  .help-fab { right: 14px; bottom: 14px; width: 52px; height: 52px; }
  .help-panel {
    right: 0; bottom: 0; left: 0; top: 0;
    width: 100%; max-width: none;
    height: 100dvh;
    border-radius: 0; border: none;
  }
}

/* Old topbar help (?) and theme buttons (kept for legacy/external pages) */
.help-btn {
  width: 32px; height: 32px;
  border-radius: 50%;
  background: var(--brand-soft);
  color: var(--brand);
  border: none;
  display: inline-grid; place-items: center;
  cursor: pointer; font-family: inherit;
  transition: background 0.15s ease, color 0.15s ease;
}
.help-btn:hover { background: var(--brand); color: #fff; }
.help-btn svg { width: 16px; height: 16px; }
.help-btn.theme-btn { background: transparent; color: var(--ink-soft); }
.help-btn.theme-btn:hover { background: var(--brand-soft); color: var(--brand); }

/* Country flag (emoji) — slightly larger than surrounding text and shifted up
   to optically balance the line. */
.flag {
  font-size: 1.05em;
  line-height: 1;
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
}
.topbar .nav a, .topbar .nav button {
  font-size: 13px; font-weight: 500; padding: 6px 10px; border-radius: var(--r-md);
  color: var(--ink-soft); border: none; background: transparent; cursor: pointer;
  transition: color 0.12s ease, background 0.12s ease;
}
.topbar .nav a:hover, .topbar .nav button:hover { background: var(--bg); color: var(--ink); text-decoration: none; }
/* Brand: active nav tab gets a soft brand wash + brand text. */
.topbar .nav a.active { background: var(--brand-soft); color: var(--brand); font-weight: 600; }
.topbar .user-pill { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-soft); padding: 6px 10px; border-radius: 999px; background: var(--bg); border: 1px solid var(--line); }

/* Topbar Tools dropdown — collects club-specific tools (email, checklist, bad-debt, …)
   so the topbar doesn't get crowded as features are added. Hidden on mobile;
   the same tools surface in the Hub's "Tools for [club]" section there. */
.topbar-tools-wrap { position: relative; display: inline-block; }
.topbar-tools-btn {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 6px 12px;
  font-family: inherit; font-size: 13px; font-weight: 500;
  color: var(--ink-soft);
  background: transparent; border: none;
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.topbar-tools-btn:hover { background: var(--bg); color: var(--ink); }
.topbar-tools-btn.active { background: var(--brand-soft); color: var(--brand); font-weight: 600; }

/* ============================================================
   Inbox + Help (Patch ZZ52)
   The topbar pair: Inbox (badge) + Help (solid pill). Inbox sits
   next to Chat as a distinct destination — actionable items live
   here, not in chat scrollback. Help is a solid pill so new
   staff find it at first glance.
   ============================================================ */
.topbar-inbox-btn {
  display: inline-flex; align-items: center;
  padding: 6px 12px;
  font-family: inherit; font-size: 13px; font-weight: 500;
  color: var(--ink-soft);
  background: transparent; border: none;
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
  position: relative;
}
.topbar-inbox-btn:hover { background: var(--bg); color: var(--ink); }
.topbar-inbox-btn.active { background: var(--brand-soft); color: var(--brand); font-weight: 600; }
.inbox-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 18px; height: 18px; padding: 0 5px;
  background: #DC2626; color: #fff;
  font-size: 10px; font-weight: 800; font-variant-numeric: tabular-nums;
  border-radius: 999px;
  margin-left: 5px;
}
.inbox-badge[hidden] { display: none; }
/* Urgent state (Patch ZZ58) — badge pulses red when any unread
   urgent_* item exists. Stays subtle so non-urgent counts don't
   feel screamy, but it's clearly different from the normal red. */
.inbox-badge.urgent {
  background: #B91C1C;
  box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.7);
  animation: inbox-urgent-pulse 1.6s ease-out infinite;
}
@keyframes inbox-urgent-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0.55); }
  70%  { box-shadow: 0 0 0 8px rgba(220, 38, 38, 0); }
  100% { box-shadow: 0 0 0 0 rgba(220, 38, 38, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .inbox-badge.urgent { animation: none; }
}
.inbox-item.urgent {
  border-left: 3px solid #DC2626;
  background: linear-gradient(90deg, #FEF2F2 0%, var(--card) 60%);
}
.inbox-item.urgent.unread { background: linear-gradient(90deg, #FEE2E2 0%, var(--brand-soft) 80%); }
.inbox-item.urgent .inbox-item-title { color: #991B1B; }
/* Inline Claim button on new-lead urgent items (Patch ZZ61).
   Stops propagation on its own click handler so tapping it
   doesn't ALSO open the link — the handler explicitly redirects
   after a successful claim. */
.inbox-item-claim {
  background: var(--brand); color: #fff;
  border: 0; border-radius: 6px;
  padding: 5px 10px;
  font-family: inherit; font-size: 11px; font-weight: 800;
  cursor: pointer;
  flex-shrink: 0;
  margin-right: 6px;
  text-transform: uppercase; letter-spacing: 0.3px;
  transition: background 0.12s ease, transform 0.1s;
}
.inbox-item-claim:hover { background: var(--brand-dark); transform: scale(1.04); }
.inbox-item-claim:disabled { background: var(--ink-soft); cursor: wait; }

.topbar-inbox-pop {
  position: absolute; top: calc(100% + 6px); right: 0;
  width: 360px; max-width: 90vw;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: 0 12px 32px rgba(0,0,0,0.15);
  z-index: 100;
  overflow: hidden;
}
.topbar-inbox-pop[hidden] { display: none; }
/* On mobile the bell sits inside the hidden .nav row, so the absolute
   positioning above resolves against an invisible parent and the panel
   would otherwise pop off-screen on the right. Force it to fixed-viewport
   coordinates with comfortable side margins so it always fits the screen. */
@media (max-width: 768px) {
  .topbar-inbox-pop {
    position: fixed !important;
    top: 64px !important;
    left: 10px !important;
    right: 10px !important;
    width: auto !important;
    max-width: none !important;
    max-height: calc(100vh - 80px);
    overflow-y: auto;
    z-index: 9700;
  }
}
.inbox-pop-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  font-size: 12px; font-weight: 800; color: var(--ink);
  text-transform: uppercase; letter-spacing: 0.5px;
}
.inbox-pop-head button {
  background: transparent; border: 0;
  font-size: 11px; font-weight: 600; color: var(--brand);
  cursor: pointer; padding: 0;
  text-transform: none; letter-spacing: 0;
}
.inbox-pop-head button:hover { text-decoration: underline; }
/* ZZ75 channel tabs — Urgent / Attention / Activity. Lives between
   the head and the list. Each tab carries a small count chip that
   only shows when > 0 so empty channels stay quiet. */
.inbox-pop-tabs {
  display: flex; gap: 2px;
  padding: 6px 8px 0;
  background: var(--card);
  border-bottom: 1px solid var(--line);
}
.inbox-tab {
  background: transparent; border: none;
  padding: 6px 10px;
  font-size: 11.5px; font-weight: 700;
  color: var(--ink-soft);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  display: inline-flex; align-items: center; gap: 5px;
  transition: color 0.12s, border-color 0.12s;
}
.inbox-tab:hover { color: var(--ink); }
.inbox-tab.on { color: var(--brand); border-bottom-color: var(--brand); }
.inbox-tab .ct {
  background: var(--brand-soft); color: var(--brand);
  font-size: 10px; font-weight: 800;
  padding: 0 6px; border-radius: 999px; line-height: 1.4;
}
.inbox-tab.on .ct { background: var(--brand); color: #fff; }
.inbox-pop-list { max-height: 420px; overflow-y: auto; }
.inbox-empty {
  padding: 28px 16px; text-align: center;
  color: var(--ink-soft); font-size: 13px;
}
/* Section dividers in the dropdown (Patch ZZ57 — unified Attention).
   Splits routed action items from operational items so reps see
   the structure at a glance. */
.inbox-section-head {
  padding: 9px 14px 6px;
  background: var(--bg);
  font-size: 10px; font-weight: 800;
  color: var(--ink-soft);
  text-transform: uppercase; letter-spacing: 0.5px;
  border-top: 1px solid var(--line);
}
.inbox-section-head:first-child { border-top: 0; }
.inbox-item {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  text-decoration: none; color: var(--ink);
  transition: background 0.1s;
}
.inbox-item:last-child { border-bottom: 0; }
.inbox-item:hover { background: var(--bg); }
.inbox-item.unread { background: var(--brand-soft); }
.inbox-item.unread:hover { background: var(--bg); }
.inbox-item-icon {
  font-size: 18px; line-height: 1;
  flex-shrink: 0; margin-top: 1px;
}
.inbox-item-body { flex: 1; min-width: 0; }
.inbox-item-title {
  display: block;
  font-size: 13px; font-weight: 700; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.inbox-item.unread .inbox-item-title { color: var(--brand); }
.inbox-item-preview {
  display: block;
  font-size: 11px; color: var(--ink-soft);
  margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.inbox-item-when {
  font-size: 11px; color: var(--ink-soft);
  flex-shrink: 0; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Solid Help pill. Outline at rest, fills on hover so it reads as
   "tappable and waiting". Slightly different from Tools to avoid
   visual collision. */
.topbar-help-btn {
  display: inline-flex; align-items: center;
  padding: 5px 12px;
  font-family: inherit; font-size: 12px; font-weight: 700;
  color: var(--brand);
  background: var(--brand-soft);
  border: 1px solid transparent;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease, transform 0.1s;
  margin-left: 4px;
}
.topbar-help-btn:hover {
  background: var(--brand); color: #fff;
  transform: translateY(-1px);
}
@media (max-width: 720px) {
  /* On mobile the topbar is already tight — collapse the Help label
     and let the floating FAB carry the load. */
  .topbar-help-btn { padding: 5px 8px; }
  .topbar-help-btn svg { margin-right: 0; }
  .topbar-help-btn { font-size: 0; }
  .topbar-help-btn svg { width: 16px; height: 16px; }
}
/* Tools-menu group label + divider — used to slice the dropdown into
   functional sections (Sales / Operations / Finance / External). */
.topbar-tools-pop .tool-group-label {
  font-size: 10px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--ink-soft);
  padding: 8px 12px 4px;
}
.topbar-tools-pop .tool-group-divider {
  height: 1px;
  background: var(--line);
  margin: 6px 4px 2px;
}

.topbar-tools-pop {
  /* Anchored absolutely to the .topbar-tools-wrap (position: relative).
     We tried `position: fixed` to escape the topbar's stacking context
     but the topbar's `backdrop-filter: blur(8px)` creates a containing
     block for fixed descendants — so it didn't actually escape. The
     real fix lives on the OTHER side: any container with high-z-index
     internals (like Leaflet maps via .live-map) declares
     `isolation: isolate` so its z-indexes can't leak past the topbar's
     z-index: 100. That keeps this dropdown reliably on top. */
  position: absolute; top: calc(100% + 6px); right: 0;
  min-width: 240px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  padding: 6px;
  z-index: 9000;
  max-height: calc(100vh - 80px);
  overflow-y: auto;
  animation: tools-pop-in 0.15s cubic-bezier(0.16, 1, 0.3, 1);
}
.topbar-tools-pop[hidden] { display: none; }
.topbar-tools-pop a, .topbar-tools-pop button {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 9px 12px;
  background: transparent; border: none;
  border-radius: 8px;
  font-family: inherit; font-size: 13px; font-weight: 500;
  color: var(--ink); text-align: left;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.1s ease;
}
.topbar-tools-pop a:hover, .topbar-tools-pop button:hover {
  background: var(--brand-soft); color: var(--brand);
  text-decoration: none;
}
.topbar-tools-pop .tool-icon {
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 6px;
  background: var(--brand-soft);
  color: var(--brand);
  flex-shrink: 0;
}
.topbar-tools-pop .tool-extlink {
  margin-left: auto;
  font-size: 12px;
  color: var(--ink-faint);
}
.topbar-tools-empty {
  display: flex; flex-direction: column; gap: 4px;
  padding: 12px;
  font-size: 12px; color: var(--ink-soft);
}
.topbar-tools-empty strong { color: var(--ink); font-weight: 600; }
@keyframes tools-pop-in {
  from { opacity: 0; transform: translateY(-4px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@media (max-width: 768px) {
  .topbar-tools-wrap { display: none; }
}
.topbar .user-pill .avatar { width: 22px; height: 22px; border-radius: 50%; background: var(--brand); color: #fff; display: grid; place-items: center; font-size: 11px; font-weight: 800; }

/* User dropdown — consolidates name, theme toggle, sign out under the avatar.
   Selectors include .topbar so they win over .topbar .nav button rules. */
.topbar .user-menu, .user-menu { position: relative; }
.topbar .nav .user-menu-trigger,
.user-menu .user-menu-trigger {
  width: 36px !important; height: 36px !important; border-radius: 50% !important;
  background: transparent; border: 1px solid transparent;
  cursor: pointer; padding: 0 !important;
  display: grid; place-items: center;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.topbar .nav .user-menu-trigger:hover,
.user-menu .user-menu-trigger:hover { background: transparent; border-color: var(--brand); }
.user-menu .user-menu-trigger .avatar,
.user-menu .user-menu-trigger .avatar-img {
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--brand); color: #fff;
  display: grid; place-items: center;
  font-size: 11px; font-weight: 800;
  object-fit: cover;
}
.user-menu .user-menu-pop {
  position: absolute; top: calc(100% + 6px); right: 0;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow-lg);
  min-width: 240px; padding: 6px; z-index: 60;
  display: none;
}
.user-menu.open .user-menu-pop { display: block; }
.user-menu .user-menu-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 10px 12px; border-bottom: 1px solid var(--line); margin-bottom: 4px;
}
.user-menu .user-menu-head .avatar,
.user-menu .user-menu-head .avatar-img {
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--brand); color: #fff;
  display: grid; place-items: center;
  font-size: 13px; font-weight: 800;
  flex-shrink: 0;
  object-fit: cover;
}
.user-menu .user-menu-head .who { min-width: 0; }
.user-menu .user-menu-head .nm { font-size: 13px; font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-menu .user-menu-head .em { font-size: 11px; color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Avatar in the dropdown header — click to upload, hover reveals pencil.
   The button IS the circle (carries the brand background + initials)
   instead of nesting a separate .avatar inside. This avoids the nested-
   sizing / line-height / overflow-hidden interactions that were leaving
   the initials text anchored to a corner. */
.user-menu .user-menu-avatar-btn {
  position: relative;
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--brand); color: #fff;
  border: none; padding: 0; margin: 0;
  cursor: pointer;
  flex-shrink: 0;
  border-radius: 50%;
  overflow: hidden;
  outline: none;
  font-family: inherit;
  font-size: 14px; font-weight: 800; line-height: 1;
  letter-spacing: 0;
  transition: transform 0.12s ease;
}
.user-menu .user-menu-avatar-btn:hover { transform: scale(1.04); }
.user-menu .user-menu-avatar-btn:focus-visible { box-shadow: 0 0 0 2px var(--brand); }
/* Inner .avatar (initials) and .avatar-img (uploaded photo) fully fill the
   button so the click target = the visible avatar. */
.user-menu .user-menu-avatar-btn .avatar,
.user-menu .user-menu-avatar-btn .avatar-img {
  display: flex !important; align-items: center; justify-content: center;
  position: absolute; inset: 0;
  width: 100% !important; height: 100% !important;
  border-radius: 50% !important;
  background: transparent;
  color: inherit;
  font-size: inherit; font-weight: inherit; line-height: 1;
  text-align: center;
  object-fit: cover;
  margin: 0; padding: 0;
}
.user-menu .avatar-edit-overlay {
  position: absolute; inset: 0;
  border-radius: 50%;
  background: rgba(15, 15, 26, 0.55);
  display: grid; place-items: center;
  color: #fff;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s ease;
}
.user-menu .avatar-edit-overlay svg { width: 14px; height: 14px; display: block; }
.user-menu .user-menu-avatar-btn:hover .avatar-edit-overlay,
.user-menu .user-menu-avatar-btn:focus-visible .avatar-edit-overlay { opacity: 1; }
.user-menu .user-menu-avatar-remove {
  background: transparent; border: none; padding: 4px;
  color: var(--ink-faint); cursor: pointer;
  border-radius: var(--r-sm);
  transition: color 0.12s ease, background 0.12s ease;
}
.user-menu .user-menu-avatar-remove:hover { color: var(--accent); background: var(--accent-soft); }
/* Icon-only action row at the bottom of the user menu */
.user-menu .user-menu-actions {
  display: flex; gap: 4px; padding: 6px 4px 2px;
  justify-content: space-around;
}
.user-menu .user-menu-icon {
  flex: 1;
  background: transparent; border: none;
  display: grid; place-items: center;
  padding: 10px 8px; border-radius: 8px;
  cursor: pointer; font-family: inherit;
  color: var(--ink-soft);
  transition: background 0.12s ease, color 0.12s ease;
}
.user-menu .user-menu-icon:hover { background: var(--brand-soft); color: var(--brand); }

/* Presence row inside the avatar dropdown — quick one-click status change */
.user-menu .user-menu-presence {
  padding: 8px 6px 6px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 4px;
}
.user-menu .user-menu-presence-label {
  font-size: 10px; font-weight: 700; color: var(--ink-soft);
  letter-spacing: 0.5px; text-transform: uppercase;
  padding: 0 6px 6px;
}
.user-menu .user-menu-presence-row {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 4px;
}
.user-menu .presence-opt {
  display: inline-flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 8px 4px;
  background: transparent; border: 1px solid transparent;
  border-radius: var(--r-md);
  font-family: inherit; font-size: 11px; font-weight: 500;
  color: var(--ink-soft);
  cursor: pointer;
  transition: all 0.12s ease;
}
.user-menu .presence-opt:hover { background: var(--bg); color: var(--ink); border-color: var(--line); }
.user-menu .presence-opt.active {
  background: var(--brand-soft); color: var(--brand); border-color: var(--brand);
}
.user-menu .presence-opt-dot {
  width: 8px; height: 8px; border-radius: 50%;
  flex-shrink: 0;
}
.user-menu .presence-opt-dot.dot-auto   { background: var(--ink-faint); }
.user-menu .presence-opt-dot.dot-online { background: var(--ok);   box-shadow: 0 0 0 2px rgba(21,128,61,0.18); }
.user-menu .presence-opt-dot.dot-away   { background: var(--warn); }
.user-menu .presence-opt-dot.dot-dnd    { background: var(--accent); box-shadow: 0 0 0 2px rgba(245,51,63,0.20); }
.user-menu .presence-opt-dot.dot-ooo    { background: #B07A1A; }
.user-menu .presence-opt-dot.dot-system { background: var(--ink-faint); }
.user-menu .presence-opt-dot.dot-time   { background: linear-gradient(135deg, var(--warn) 50%, var(--brand-dark) 50%); }
.user-menu .presence-opt-dot.dot-light  { background: var(--warn); }
.user-menu .presence-opt-dot.dot-dark   { background: var(--ink); }
.user-menu .presence-opt.presence-opt-ooo.active {
  background: var(--warn-soft); color: var(--warn); border-color: var(--warn);
}

/* Patch ZZ71 — smooth day ↔ night transition.
   `.theme-transitioning` is added to <html> by setTheme() for the
   duration of a theme flip (~320ms), then removed. While it's on,
   every element cross-fades its colour properties. We can't put
   transitions on these properties permanently because every hover
   / focus / dropdown open would then take 320ms to settle — which
   feels laggy. By scoping to a brief class window, only the actual
   theme change animates. */
html.theme-transitioning,
html.theme-transitioning *,
html.theme-transitioning *::before,
html.theme-transitioning *::after {
  transition:
    background-color 320ms ease,
    color            320ms ease,
    border-color     320ms ease,
    fill             320ms ease,
    stroke           320ms ease,
    box-shadow       320ms ease,
    opacity          320ms ease !important;
}
/* Respect prefers-reduced-motion — snap instead of cross-fade. */
@media (prefers-reduced-motion: reduce) {
  html.theme-transitioning,
  html.theme-transitioning *,
  html.theme-transitioning *::before,
  html.theme-transitioning *::after {
    transition: none !important;
  }
}

/* Patch ZZ70 — collapsible <details> toggle for Appearance + Language.
   Hides the default disclosure marker, lays the summary out as a single
   row showing the section label + current selection + chevron. When
   open, the chevron rotates and the chip row appears below. */
.user-menu details.user-menu-toggle { padding: 6px 6px 8px; }
.user-menu details.user-menu-toggle[open] { padding-bottom: 8px; }
.user-menu .user-menu-toggle-summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 10px;
  padding: 6px 6px;
  border-radius: var(--r-md);
  user-select: none;
}
.user-menu .user-menu-toggle-summary::-webkit-details-marker { display: none; }
.user-menu .user-menu-toggle-summary::marker { content: ''; }
.user-menu .user-menu-toggle-summary:hover { background: var(--bg); }
.user-menu .user-menu-toggle-label {
  font-size: 10px; font-weight: 700; color: var(--ink-soft);
  letter-spacing: 0.5px; text-transform: uppercase;
  flex-shrink: 0;
}
.user-menu .user-menu-toggle-value {
  display: inline-flex; align-items: center; gap: 6px;
  margin-left: auto;
  font-size: 12px; font-weight: 600; color: var(--ink);
}
.user-menu .user-menu-toggle-value .presence-opt-dot {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
}
.user-menu .user-menu-toggle-chevron {
  width: 14px; height: 14px;
  color: var(--ink-faint);
  flex-shrink: 0;
  transition: transform 0.18s ease;
}
.user-menu details.user-menu-toggle[open] .user-menu-toggle-chevron {
  transform: rotate(180deg);
}
.user-menu details.user-menu-toggle[open] .user-menu-presence-row {
  margin-top: 6px;
  animation: userMenuToggleSlide 0.16s ease-out;
}
/* Toggle rows don't have the 5-chip Presence row's fixed column count.
   auto-fit + minmax(0, 1fr) stretches whatever buttons are there across
   the full width, so the 4-button Appearance row and 3-button Language
   row both fill edge-to-edge. */
.user-menu details.user-menu-toggle .user-menu-presence-row {
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
}
@keyframes userMenuToggleSlide {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}
.user-menu .user-menu-icon.danger:hover { background: var(--accent-soft); color: var(--accent); }
.user-menu .user-menu-icon svg { width: 18px; height: 18px; }

/* Club switcher in topbar */
.club-switcher { position: relative; }
.club-switcher .trigger {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 12px; border-radius: 999px;
  background: var(--card); border: 1px solid var(--line);
  font-size: 13px; font-weight: 700; color: var(--ink); cursor: pointer; font-family: inherit;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.club-switcher .trigger:hover { border-color: var(--brand); }
.club-switcher .trigger .country-tag {
  font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 999px;
  background: var(--brand-soft); color: var(--brand); letter-spacing: 0.4px;
}
.club-switcher .trigger svg { width: 12px; height: 12px; opacity: 0.6; }
.club-switcher .menu {
  /* Switcher now lives on the LEFT of the topbar — anchor the dropdown
     to the trigger's left edge so it opens directly below it instead of
     spilling off the page to the right. */
  position: absolute; top: calc(100% + 6px); left: 0; right: auto;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow-lg); min-width: 280px; padding: 6px; z-index: 60;
  display: none;
}
.club-switcher.open .menu { display: block; }
.club-switcher .menu .menu-section { font-size: 10px; font-weight: 700; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.7px; padding: 8px 10px 4px; }
.club-switcher .menu button {
  width: 100%; text-align: left; background: transparent; border: none;
  display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 8px;
  font-size: 13px; font-weight: 600; color: var(--ink); cursor: pointer; font-family: inherit;
}
.club-switcher .menu button:hover { background: var(--brand-soft); }
.club-switcher .menu button.active { background: var(--brand-soft); color: var(--brand); }
.club-switcher .menu button .check { margin-left: auto; color: var(--brand); opacity: 0; }
.club-switcher .menu button.active .check { opacity: 1; }
.club-switcher .menu button .country-tag {
  font-size: 10px; font-weight: 700; padding: 2px 6px; border-radius: 999px;
  background: var(--bg); color: var(--ink-soft); margin-left: auto; letter-spacing: 0.4px;
}
.club-switcher .menu button.active .country-tag { background: rgba(90,66,148,0.12); color: var(--brand); }

/* ---- Hero ----
   Bold AF-brand surface — Burple → Burple-dark with a Cyan glow.
   White text, big headline. Restores brand presence without losing modernity. */
.hero {
  background: linear-gradient(135deg, var(--brand) 0%, var(--brand-dark) 60%, #3F2E78 100%);
  color: #fff;
  border: 1px solid var(--brand-dark);
  border-radius: var(--r-xl); padding: 26px 28px;
  position: relative; overflow: hidden; margin-bottom: 28px;
  box-shadow: var(--shadow-md);
}
.hero::after {
  /* Subtle cyan gleam in the corner. */
  content: ""; position: absolute;
  right: -80px; top: -80px; width: 260px; height: 260px;
  background: radial-gradient(circle, rgba(71,190,219,0.40), transparent 70%);
  border-radius: 50%; pointer-events: none;
}
.hero::before {
  /* Bright cyan accent stripe on the left edge. */
  content: ""; position: absolute;
  left: 0; top: 0; bottom: 0; width: 4px;
  background: var(--info);
}
.hero h1 { margin: 0 0 6px; font-size: 26px; font-weight: 700; letter-spacing: -0.5px; color: #fff; position: relative; z-index: 1; }
.hero p  { margin: 0; font-size: 14px; color: rgba(255,255,255,0.85); max-width: 640px; line-height: 1.55; position: relative; z-index: 1; }
.hero .country-row { margin-top: 16px; display: flex; flex-wrap: wrap; gap: 6px; position: relative; z-index: 1; }

/* ---- Quote of the day (hub) ----
   Sits just below the welcome hero. Subtle, brand-tinted, never
   shouty. Role-aware copy comes from /assets/quotes.js; this is just
   the chrome. */
.hub-quote {
  display: flex; align-items: flex-start; gap: 14px;
  background: linear-gradient(135deg, var(--brand-soft) 0%, var(--card) 80%);
  border: 1px solid var(--line);
  border-left: 4px solid var(--brand);
  border-radius: var(--r-lg);
  padding: 14px 18px;
  margin: -4px 0 18px;
}
.hub-quote-mark {
  font-family: Georgia, "Times New Roman", serif;
  font-size: 48px; line-height: 0.8;
  color: var(--brand); opacity: 0.55;
  flex-shrink: 0; padding-top: 6px;
}
.hub-quote-body { flex: 1; min-width: 0; }
.hub-quote-text {
  font-size: 15px; font-weight: 600; color: var(--ink);
  line-height: 1.5; letter-spacing: -0.1px;
}
.hub-quote-meta {
  display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap;
  margin-top: 6px;
}
.hub-quote-author {
  font-size: 12px; font-weight: 700; color: var(--brand);
  letter-spacing: 0.2px;
}
.hub-quote-gloss {
  font-size: 12px; color: var(--ink-soft); font-style: italic;
  line-height: 1.5;
}
.hero .country-row .pill,
.hero .country-row span {
  background: rgba(255,255,255,0.18) !important;
  border: 1px solid rgba(255,255,255,0.30) !important;
  padding: 4px 12px !important;
  border-radius: 999px !important;
  font-size: 12px !important;
  font-weight: 600 !important;
  color: #fff !important;
  backdrop-filter: blur(4px);
}

/* ---- Section ----
   Bigger, in brand purple — labels read as headings, not afterthoughts. */
.section-title {
  font-size: 14px; font-weight: 700; color: var(--brand);
  letter-spacing: 0.2px;
  margin: 32px 4px 14px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--line);
}
.section-title > span { display: inline-flex; align-items: center; gap: 8px; color: var(--brand); }
.section-title > span::before {
  content: ""; display: inline-block;
  width: 4px; height: 14px;
  background: linear-gradient(180deg, var(--brand), var(--info));
  border-radius: 2px;
}
.section-title .actions { display: flex; gap: 6px; align-items: center; }

/* ---- Buttons ----
   Modernized: lighter font weight (semi-bold rather than 800), smaller corner
   radius, subtler hover state. Less "press me!" — more like a native control. */
.btn {
  border: 1px solid var(--line); background: var(--card); color: var(--ink);
  font-size: 13px; font-weight: 500; padding: 6px 12px; border-radius: var(--r-md);
  cursor: pointer; transition: background 0.12s ease, border-color 0.12s ease, color 0.12s ease;
  display: inline-flex; align-items: center; gap: 6px; font-family: inherit;
}
.btn:hover { background: var(--bg); border-color: var(--line-strong); }
.btn:active { background: var(--bg); }
.btn:disabled { opacity: 0.55; cursor: not-allowed; }
.btn:disabled:hover { background: var(--card); border-color: var(--line); color: var(--ink); }
.btn.primary { background: var(--brand); color: #fff; border-color: var(--brand); font-weight: 600; }
.btn.primary:hover { background: var(--brand-dark); border-color: var(--brand-dark); color: #fff; }
.btn.ghost { background: transparent; border-color: transparent; color: var(--ink-soft); }
.btn.ghost:hover { background: var(--bg); color: var(--ink); border-color: transparent; }
.btn.danger { color: var(--accent); border-color: var(--line); }
.btn.danger:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.btn.success { background: var(--ok); border-color: var(--ok); color: #fff; font-weight: 600; }
.btn.success:hover { filter: brightness(0.92); color: #fff; }
.btn.block { width: 100%; justify-content: center; padding: 10px 14px; font-size: 14px; }
.btn svg { width: 14px; height: 14px; }

/* ---- Cards ----
   Modernized: thinner borders, smaller radius, no shadow at rest, subtle
   hover lift via border + tiny translate. Cards behave more like list items. */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; }
.card {
  display: flex; flex-direction: column; gap: 8px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 16px;
  text-decoration: none; color: inherit;
  transition: border-color 0.12s ease, background 0.12s ease, transform 0.12s ease;
  position: relative;
}
.card:hover { border-color: var(--line-strong); transform: translateY(-1px); text-decoration: none; }
.card.disabled { cursor: not-allowed; opacity: 0.6; }
.card.disabled:hover { transform: none; border-color: var(--line); }
.card .icon {
  width: 36px; height: 36px; border-radius: var(--r-md);
  background: linear-gradient(135deg, var(--brand-soft), rgba(71,190,219,0.15));
  color: var(--brand); display: grid; place-items: center;
  border: 1px solid transparent;
  transition: background 0.12s ease, color 0.12s ease, transform 0.12s ease;
}
.card:hover .icon {
  background: var(--brand); color: #fff;
  transform: scale(1.05);
}
.card .icon svg { width: 16px; height: 16px; }
.card h3 { margin: 0; font-size: 14px; font-weight: 600; color: var(--ink); letter-spacing: -0.1px; }
.card p { margin: 0; font-size: 13px; color: var(--ink-soft); line-height: 1.5; }
.card .cta { margin-top: auto; padding-top: 8px; font-size: 12px; font-weight: 500; color: var(--ink-soft); display: inline-flex; align-items: center; gap: 4px; }
.card .cta::after { content: "→"; transition: transform 0.12s ease; opacity: 0.7; }
.card:hover .cta { color: var(--brand); }
.card:hover .cta::after { transform: translateX(2px); opacity: 1; }

/* When a card is rendered as a <button> (e.g. clickable club cards) */
button.card { font-family: inherit; text-align: left; cursor: pointer; }
button.card:focus { outline: none; box-shadow: 0 0 0 3px rgba(90,66,148,0.18); }
.club-card .cta { color: var(--brand); }
.club-card .cta svg { width: 14px; height: 14px; vertical-align: middle; }
.badge {
  position: absolute; top: 12px; right: 12px;
  font-size: 10px; font-weight: 600; color: var(--accent);
  background: var(--accent-soft); padding: 2px 7px; border-radius: var(--r-sm);
  letter-spacing: 0.2px;
}

/* ---- Quick links list ---- */
.quicklinks { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 4px; }
.quicklinks a {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border-radius: var(--r-md); text-decoration: none; color: var(--ink);
  font-size: 13px; font-weight: 500; transition: background 0.12s ease;
}
.quicklinks a:hover { background: var(--bg); text-decoration: none; }
.quicklinks a + a { border-top: 1px solid var(--line); }
.quicklinks .dot { width: 28px; height: 28px; border-radius: var(--r-sm); background: var(--info-soft); color: var(--info); display: grid; place-items: center; flex-shrink: 0; }
.quicklinks .dot svg { width: 14px; height: 14px; }
.quicklinks .meta { margin-left: auto; font-size: 12px; color: var(--ink-faint); font-weight: 500; }

/* ---- Forms ----
   Modernized: lowercase labels (sentence case), tighter input padding, subtler focus ring. */
.field { display: flex; flex-direction: column; gap: 5px; margin-bottom: 14px; }
.field label { font-size: 12px; font-weight: 600; color: var(--ink); letter-spacing: 0; text-transform: none; }
.field input, .field textarea, .field select {
  border: 1px solid var(--line); border-radius: var(--r-md); padding: 8px 10px;
  font-size: 14px; font-family: inherit; color: var(--ink); background: var(--card);
  outline: none; transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.field input:focus, .field textarea:focus, .field select:focus {
  border-color: var(--brand); box-shadow: 0 0 0 3px rgba(90,66,148,0.12);
}
.field textarea { resize: vertical; min-height: 90px; }
.field .help { font-size: 12px; color: var(--ink-soft); }
.field.error input, .field.error textarea, .field.error select { border-color: var(--accent); }
.field.error .help { color: var(--accent); }

/* ---- Auth pages ---- */
.auth-card {
  background: var(--card); border: 1px solid var(--line); border-radius: 18px;
  padding: 32px; width: 100%; max-width: 420px; box-shadow: var(--shadow-lg);
}
.auth-card .brand-stack { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; }
.auth-card .brand-stack .logo { width: 48px; height: 48px; display: grid; place-items: center; background: transparent; }
.auth-card .brand-stack .logo img { width: 100%; height: 100%; object-fit: contain; display: block; }
.auth-card h1 { font-size: 22px; margin: 0 0 4px; font-weight: 800; }
.auth-card .sub { color: var(--ink-soft); font-size: 14px; margin: 0 0 20px; }
.auth-card .switch { margin-top: 18px; text-align: center; font-size: 13px; color: var(--ink-soft); }

/* ---- Tags / pills ----
   Modernized: smaller, sentence case, less aggressive. Square radius like badges. */
.pill { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: var(--r-sm); letter-spacing: 0; text-transform: none; }
.pill.brand { background: var(--brand-soft); color: var(--brand); }
.pill.ok { background: var(--ok-soft); color: var(--ok); }
.pill.warn { background: var(--warn-soft); color: var(--warn); }
.pill.danger { background: var(--accent-soft); color: var(--accent); }
.pill.info { background: var(--info-soft); color: var(--info); }
.pill.muted { background: var(--bg); color: var(--ink-soft); border: 1px solid var(--line); }

/* ---- Tables ---- */
.table-wrap { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; }
table.dataset { width: 100%; border-collapse: collapse; font-size: 13px; }
table.dataset thead th { background: var(--bg); text-align: left; padding: 10px 14px; font-size: 11px; font-weight: 600; color: var(--ink-soft); letter-spacing: 0.2px; border-bottom: 1px solid var(--line); }
table.dataset tbody td { padding: 12px 14px; border-bottom: 1px solid var(--line); vertical-align: middle; color: var(--ink); }
table.dataset tbody tr:last-child td { border-bottom: none; }
table.dataset tbody tr:hover { background: var(--bg); }
table.dataset .row-actions { display: flex; gap: 6px; justify-content: flex-end; }

/* ---- Empty state ---- */
.empty-state {
  background: var(--card); border: 1px dashed var(--line);
  /* Hub-wide card radius — match real cards so empty states don't look
     like a different shape from the populated card next to them. */
  border-radius: var(--r-xl);
  padding: 28px; text-align: center; color: var(--ink-soft); font-size: 14px;
}

/* ---- Announcements ---- */
.announcements { display: flex; flex-direction: column; gap: 8px; }
/* Older non-card announcement defaults (kept minimal — most styling now
   lives in the card-style block below). */
.announcement-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; flex-wrap: wrap; }
.announcement h4   { margin: 0; font-size: 14px; font-weight: 600; letter-spacing: -0.1px; }

/* Brief glow when an announcement is targeted via #a-ID deep link */
.announcement.ann-highlight {
  animation: ann-glow 2.4s ease;
  box-shadow: 0 0 0 3px rgba(90, 66, 148, 0.25);
}
@keyframes ann-glow {
  0%   { box-shadow: 0 0 0 3px rgba(90, 66, 148, 0.45); }
  60%  { box-shadow: 0 0 0 3px rgba(90, 66, 148, 0.25); }
  100% { box-shadow: 0 0 0 3px rgba(90, 66, 148, 0); }
}

/* ============ Compact 7-day strip ============
   Replaces the standalone Calendar tab. Renders Today + next 6 days
   as small column cards. Picks up events + followups already loaded
   on the hub; birthdays slot in once Push B adds the schema. */
.week-strip {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 12px 14px; margin-bottom: 18px; box-shadow: var(--shadow);
}
.ws-head-row {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 10px;
}
.ws-title-text {
  font-size: 13px; font-weight: 800; color: var(--ink);
  text-transform: uppercase; letter-spacing: 0.4px;
}
.ws-jump {
  font-size: 11px; font-weight: 700; color: var(--brand);
  text-decoration: none;
}
.ws-jump:hover { text-decoration: underline; }
.ws-grid {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px;
}
@media (max-width: 880px) { .ws-grid { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 520px) { .ws-grid { grid-template-columns: repeat(2, 1fr); } }
.ws-col {
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 8px; min-height: 92px;
  display: flex; flex-direction: column; gap: 4px;
}
.ws-col.ws-today {
  background: var(--brand-soft);
  border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand);
}
.ws-head {
  display: flex; align-items: baseline; gap: 4px;
  font-size: 11px; color: var(--ink-soft); margin-bottom: 2px;
}
.ws-dow { font-weight: 700; text-transform: uppercase; letter-spacing: 0.4px; }
.ws-num { font-size: 18px; font-weight: 800; color: var(--ink); margin-left: auto; line-height: 1; }
.ws-mon { font-size: 10px; text-transform: uppercase; letter-spacing: 0.4px; }
.ws-col.ws-today .ws-num { color: var(--brand); }
.ws-list { display: flex; flex-direction: column; gap: 3px; min-height: 0; }
.ws-item {
  display: flex; gap: 4px; align-items: baseline;
  font-size: 11px; color: var(--ink); text-decoration: none;
  background: var(--card); border-radius: 4px; padding: 3px 6px;
  border-left: 2px solid var(--brand);
  overflow: hidden;
}
.ws-item:hover { background: var(--card); text-decoration: none; }
.ws-item.ws-fup  { border-left-color: var(--warn, #F2A93B); }
.ws-item.ws-bday { border-left-color: #EC4899; background: #FCE7F3; }
body[data-theme="dark"] .ws-item.ws-bday { background: rgba(236, 72, 153, 0.18); }
.ws-time {
  font-weight: 700; color: var(--ink-soft); font-size: 10px;
  flex-shrink: 0;
}
.ws-title {
  font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0;
}
.ws-empty { font-size: 11px; color: var(--ink-faint); text-align: center; padding: 16px 0; }
.ws-more {
  font-size: 10px; font-weight: 700; color: var(--brand); text-decoration: none;
  text-align: center; padding: 2px 0;
}
.ws-more:hover { text-decoration: underline; }

/* ============ Hub focus mode (PT + MC) ============
   When body has data-hub-mode="focus" (set by hub.html init for
   Personal Trainers and Membership Consultants), hide the noise
   sections wrapped in .hub-extras. They keep their Today's Focus,
   week strip, Needs Attention, and Followups — the actionable stuff. */
body[data-hub-mode="focus"] .hub-extras { display: none !important; }

/* Today's Focus (WL#20) — role-aware priority card that sits above
   Needs Attention. Uses a warmer accent (info-blue) so the visual order
   reads: Focus → Needs Attention → Followups. Top, of, the, hub. */
.todays-focus {
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 4px solid var(--info, #3D8BFD);
  /* --r-xl to match the clock card + shifts strip on hub.html which
     use an inline 14px radius. Without this all the rendered Hub
     cards (todays-focus, needs-attention, followups, announcement,
     event-card) ended up with visibly tighter corners than the two
     hand-styled cards next to them — Ben flagged the mismatch in
     the right column. */
  border-radius: var(--r-xl);
  padding: 14px 16px;
  margin-bottom: 14px;
  box-shadow: var(--shadow);
}
.tf-head {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 10px;
}
.tf-flag    { font-size: 18px; }
.tf-headline { font-size: 14px; font-weight: 700; color: var(--ink); }
/* `minmax(0, 1fr)` so the grid track is allowed to shrink below the
   intrinsic min-content width of its child. Without this, the nowrap
   `.tf-sub` line below forces the track wider than the container and
   the whole card bleeds past the right edge on narrow viewports. */
.tf-list    { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; }
.tf-item {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  color: var(--ink);
  text-decoration: none;
  /* Same trick at the flex level — let the item shrink below its
     content min-size so the ellipsised sub-line collapses gracefully. */
  min-width: 0; max-width: 100%;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.tf-item:hover {
  background: var(--card); border-color: var(--line-strong);
  text-decoration: none; transform: translateX(2px);
}
.tf-item.tf-item-empty { background: transparent; border-style: dashed; }
.tf-icon  { font-size: 18px; line-height: 1; flex-shrink: 0; }
.tf-pill  {
  min-width: 22px; height: 22px; padding: 0 6px;
  background: var(--info-soft, rgba(61, 139, 253, 0.16));
  color: var(--info, #3D8BFD);
  border-radius: 999px;
  display: inline-grid; place-items: center;
  font-size: 12px; font-weight: 700;
  flex-shrink: 0;
}
.tf-pill.danger { background: var(--danger-soft); color: var(--danger); }
.tf-pill.warn   { background: var(--warn-soft);   color: var(--warn); }
.tf-pill.brand  { background: var(--brand);       color: #fff; }
.tf-body  { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.tf-title { font-size: 13px; font-weight: 600; color: var(--ink); }
.tf-sub   {
  font-size: 12px; color: var(--ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 100%;
}

/* ============ Shared KPI strip ============
   Hoisted from bad-debt.html so other pages (admin Referrals tab,
   admin Commissions roll-up, future dashboards) can reach for the
   same card style without duplicating the rules. `.bd-kpi` /
   `.bd-kpis` is the historical class name — kept for backwards
   compatibility with existing pages. */
.bd-kpis {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: 16px;
}
@media (max-width: 1000px) { .bd-kpis { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px)  { .bd-kpis { grid-template-columns: 1fr; } }
.bd-kpi {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 16px 18px;
  position: relative;
  overflow: hidden;
}
.bd-kpi::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: var(--ink-soft); opacity: 0.3;
}
.bd-kpi.primary::before { background: var(--brand);     opacity: 1; }
.bd-kpi.accent::before  { background: #FF8C42;          opacity: 1; }
.bd-kpi.amber::before   { background: #F59E0B;          opacity: 1; }
.bd-kpi.danger::before  { background: var(--danger);    opacity: 1; }
.bd-kpi.ok::before      { background: var(--ok);        opacity: 1; }
.bd-kpi .lbl {
  text-transform: uppercase; letter-spacing: 0.5px;
  font-size: 11px; font-weight: 700;
  color: var(--ink-soft); margin-bottom: 4px;
}
.bd-kpi .val {
  font-size: 28px; font-weight: 800; color: var(--ink);
  line-height: 1.1; letter-spacing: -0.5px;
}
.bd-kpi .sub { font-size: 12px; color: var(--ink-soft); margin-top: 4px; }
.bd-kpi .delta-up   { color: var(--danger, #B91C1C); font-weight: 800; }
.bd-kpi .delta-down { color: var(--ok,     #047857); font-weight: 800; }
.bd-kpi.trend-good  { /* used by trend-strip cards in bad-debt; opt-in */ }
.bd-kpi.trend-bad   { /* used by trend-strip cards in bad-debt; opt-in */ }

/* ============ Lifecycle requests inbox (WL#29) ============
   Shared between admin.html's Lifecycle tab and any future drawer
   that surfaces a member freeze/cancel/transfer request. Each card
   stacks: header (kind + status + when) → body (member, club, detail,
   reason) → optional actions row. Lives in /styles.css so dark mode
   inherits without per-page work. */
.mlr-list { display: flex; flex-direction: column; gap: 10px; }
.mlr-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 14px 16px;
  box-shadow: var(--shadow);
}
.mlr-head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-bottom: 8px;
}
.mlr-kind, .mlr-status {
  font-size: 11px; font-weight: 800;
  padding: 3px 10px; border-radius: 999px;
  letter-spacing: 0.3px;
}
.mlr-when { font-size: 11px; color: var(--ink-soft); margin-left: auto; }
.mlr-body { font-size: 13px; color: var(--ink); line-height: 1.55; }
.mlr-member { font-size: 14px; color: var(--ink); margin-bottom: 2px; }
.mlr-member strong { font-weight: 800; }
.mlr-ext {
  font-size: 11px; font-weight: 600; color: var(--ink-soft);
  font-family: 'SF Mono', Consolas, monospace;
  background: var(--bg); padding: 1px 6px; border-radius: 4px;
  margin-left: 4px;
}
.mlr-meta { font-size: 12px; color: var(--ink-soft); margin-bottom: 6px; }
.mlr-meta .flag { margin-right: 2px; }
.mlr-detail {
  font-size: 12px; color: var(--ink);
  background: var(--bg);
  border-radius: var(--r-md);
  padding: 6px 10px;
  margin-bottom: 8px;
}
.mlr-reason {
  font-size: 13px; color: var(--ink-soft);
  border-left: 3px solid var(--brand);
  background: var(--brand-soft);
  padding: 8px 12px;
  border-radius: 0 var(--r-md) var(--r-md) 0;
}
.mlr-decision {
  font-size: 11px; color: var(--ink-soft);
  margin-top: 8px;
}
.mlr-actions {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 12px;
}
.mlr-actions .btn { padding: 7px 14px; font-size: 12px; font-weight: 700; }

/* Needs attention card on the hub */
.needs-attention {
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 4px solid var(--brand);
  /* Hub-wide card radius — see comment on .todays-focus. */
  border-radius: var(--r-xl);
  padding: 14px 16px;
  margin-bottom: 24px;
  box-shadow: var(--shadow);
}

/* Followups card — surfaces snoozed chat messages whose remind_at has passed.
   Distinct accent color (warn/orange) so it doesn't blend with Needs Attention. */
.followups-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-left: 4px solid var(--warn, #F2A93B);
  /* Hub-wide card radius — see comment on .todays-focus. */
  border-radius: var(--r-xl);
  padding: 14px 16px;
  margin-bottom: 24px;
  box-shadow: var(--shadow);
}
.followups-head {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 12px;
}
.followups-icon { font-size: 18px; }
.followups-title { font-size: 14px; font-weight: 700; color: var(--ink); }
.followups-sub { font-size: 12px; color: var(--ink-soft); margin-left: auto; }
.followup-row {
  padding: 10px 12px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  margin-bottom: 8px;
}
.followup-row:last-child { margin-bottom: 0; }
.followup-meta { font-size: 12px; color: var(--ink-soft); margin-bottom: 4px; }
.followup-meta strong { color: var(--ink); font-weight: 700; }

/* Calendar-lane pill on each Followup row + each snoozed-chat marker
   on the calendar. Tells the user (at-a-glance) whether the snooze
   landed on the Work lane (group/channel default) or Personal lane
   (DM default). Set in chat.html → openSnoozePicker → segmented
   control; remembered per-room in localStorage. */
.followup-lane {
  display: inline-block;
  font-size: 10px; font-weight: 800;
  padding: 1px 7px; border-radius: 999px;
  margin-left: 4px;
  text-transform: uppercase; letter-spacing: 0.4px;
}
.followup-lane.lane-work     { background: var(--brand-soft); color: var(--brand); }
.followup-lane.lane-personal { background: var(--info-soft);  color: var(--info); }
.followup-room { color: var(--ink-soft); font-weight: 500; }
.followup-ts { color: var(--ink-faint); }
.followup-snippet {
  font-size: 13px; color: var(--ink); line-height: 1.4;
  margin-bottom: 8px;
  word-break: break-word;
  overflow-wrap: anywhere;
}
.followup-actions {
  display: flex; gap: 6px; justify-content: flex-end;
}
.followup-actions .btn { padding: 4px 12px; font-size: 12px; }
@media (max-width: 600px) {
  .followups-sub { display: none; }
}
.needs-attention.all-clear {
  border-left-color: var(--ok);
  display: flex; align-items: center; gap: 12px;
}
.needs-attention.all-clear .na-icon {
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--ok); color: #fff;
  display: grid; place-items: center; flex-shrink: 0;
  font-size: 16px; font-weight: 700;
}
.needs-attention .na-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px; font-weight: 700; color: var(--brand);
  margin-bottom: 10px;
}
.needs-attention .na-flag { font-size: 16px; }
.needs-attention .na-title { font-size: 14px; font-weight: 600; color: var(--ink); }
.needs-attention .na-sub   { font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
.needs-attention .na-list { display: grid; gap: 6px; }
.na-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  background: var(--bg);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  text-decoration: none; color: var(--ink);
  transition: all 0.12s ease;
}
.na-item:hover { background: var(--card); border-color: var(--line-strong); text-decoration: none; transform: translateX(2px); }

/* Collapsible "Needs attention" — badge by default, expand for the list */
details.needs-attention-collapsible {
  padding: 0;
  background: var(--card);
}
.na-summary-line {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px;
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition: background 0.12s ease;
}
.na-summary-line::-webkit-details-marker { display: none; }
.na-summary-line:hover { background: var(--bg); }
.na-summary-icon { font-size: 18px; }
.na-summary-text { flex: 1; min-width: 0; font-size: 14px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.na-summary-text strong { font-weight: 800; color: var(--brand); }
.na-summary-text .muted { color: var(--ink-soft); font-size: 13px; }
.na-summary-toggle {
  font-size: 12px; font-weight: 700; color: var(--ink-soft);
  flex-shrink: 0;
}
details.needs-attention-collapsible[open] .na-summary-toggle { color: var(--brand); }
@media (max-width: 600px) {
  .na-summary-text .muted { display: none; }
}

/* Club name header inside the expanded list — separates 5×3 mass into groups */
.na-club-head {
  font-size: 11px; font-weight: 800; letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 10px 4px 4px;
  border-top: 1px dashed var(--line);
  margin-top: 4px;
}
.na-list > .na-club-head:first-child { border-top: none; margin-top: 0; padding-top: 0; }
/* Checklist row carries an internal <a> + a "✕" dismiss button on the right */
.na-item-checklist { padding: 0; align-items: stretch; }
.na-item-checklist .na-item-link {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  text-decoration: none; color: var(--ink);
}
.na-item-checklist .na-item-link:hover { text-decoration: none; }
.na-dismiss {
  flex-shrink: 0;
  width: 28px;
  display: grid; place-items: center;
  background: transparent; color: var(--ink-faint);
  border: none; border-left: 1px solid transparent;
  cursor: pointer;
  font-size: 18px; line-height: 1; font-weight: 600;
  border-radius: 0 var(--r-md) var(--r-md) 0;
  transition: background 0.12s ease, color 0.12s ease;
}
.na-dismiss:hover { background: var(--accent-soft); color: var(--accent); }
.na-item-title { font-size: 13px; font-weight: 600; color: var(--ink); }
.na-item-sub   { font-size: 12px; color: var(--ink-soft); margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 380px; }
.na-pill {
  flex-shrink: 0;
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 12px; font-weight: 700;
  background: var(--brand-soft); color: var(--brand);
}
.na-pill.warn { background: var(--warn-soft); color: var(--warn); }
.na-pill.info { background: var(--info-soft); color: var(--info); }
.na-pill.brand { background: var(--brand); color: #fff; }
.na-pill.danger { background: var(--danger-soft); color: var(--danger); }

/* Contextual "?" help — small button + popover with bullet list */
.ctx-help-trigger {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--bg);
  border: 1px solid var(--line);
  color: var(--ink-soft);
  font-family: inherit; font-size: 12px; font-weight: 700;
  cursor: pointer;
  transition: all 0.12s ease;
  display: inline-grid; place-items: center;
}
.ctx-help-trigger:hover { background: var(--brand); color: #fff; border-color: var(--brand); }
.ctx-help-pop {
  background: var(--card);
  border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  width: 360px; max-width: calc(100vw - 24px);
  max-height: 70vh; overflow-y: auto;
  padding: 14px 16px;
  z-index: 600;
  animation: ctx-help-in 0.18s cubic-bezier(0.16, 1, 0.3, 1);
}
.ctx-help-pop .ctx-help-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid var(--line);
}
.ctx-help-pop .ctx-help-head strong { font-size: 14px; color: var(--brand); }
.ctx-help-pop .ctx-help-head button {
  background: transparent; border: none; padding: 2px 8px;
  font-size: 18px; line-height: 1; color: var(--ink-soft); cursor: pointer;
  border-radius: var(--r-sm);
}
.ctx-help-pop .ctx-help-head button:hover { background: var(--bg); color: var(--ink); }
.ctx-help-pop ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 8px; }
.ctx-help-pop li { font-size: 12.5px; color: var(--ink-soft); line-height: 1.5; }
.ctx-help-pop li strong { color: var(--ink); font-weight: 600; margin-right: 4px; }
@keyframes ctx-help-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* First-login onboarding tour overlay */
.tour-overlay {
  position: fixed; inset: 0; z-index: 500;
  display: none;
  pointer-events: auto;
  background: transparent;
}
.tour-overlay.open { display: block; }
.tour-overlay::before {
  /* Dim the rest of the page. */
  content: ""; position: absolute; inset: 0;
  background: rgba(15, 15, 26, 0.6);
  pointer-events: auto;
  animation: tour-fade-in 0.18s ease;
}
.tour-spot {
  position: absolute;
  border-radius: 12px;
  pointer-events: none;
  /* Spotlight: bright ring around the highlighted element. */
  box-shadow:
    0 0 0 9999px rgba(15, 15, 26, 0.6),
    0 0 0 3px var(--brand),
    0 0 22px 4px rgba(180, 154, 255, 0.55);
  transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: 1;
}
.tour-card {
  position: absolute;
  width: 320px; max-width: calc(100vw - 24px);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
  padding: 18px;
  z-index: 2;
  animation: tour-fade-in 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}
.tour-card .tour-step-indicator {
  font-size: 10px; font-weight: 700; color: var(--brand);
  letter-spacing: 0.6px; text-transform: uppercase;
  margin-bottom: 8px;
}
.tour-card h3 {
  margin: 0 0 6px;
  font-size: 16px; font-weight: 700; letter-spacing: -0.2px;
  color: var(--ink);
}
.tour-card p {
  margin: 0 0 16px;
  font-size: 13.5px; line-height: 1.55; color: var(--ink-soft);
}
.tour-card .tour-actions {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
@keyframes tour-fade-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* AI polish — composer button + dropdown menu, undo toast */
.ai-polish-wrap { position: relative; display: inline-block; }
.ai-polish-trigger {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 4px 8px;
  background: linear-gradient(135deg, var(--brand-soft), rgba(71,190,219,0.18));
  border: 1px solid rgba(90,66,148,0.18);
  border-radius: 999px;
  font-family: inherit; font-size: 11px; font-weight: 600; color: var(--brand);
  cursor: pointer; transition: all 0.12s ease;
}
.ai-polish-trigger:hover { background: var(--brand); color: #fff; border-color: var(--brand); }
.ai-polish-menu, .chat-ai-menu {
  position: absolute; top: calc(100% + 4px); right: 0;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  min-width: 240px; padding: 4px;
  z-index: 200;
}
.chat-ai-menu { position: fixed; }
.ai-polish-menu button, .chat-ai-menu button {
  display: block; width: 100%; text-align: left;
  background: transparent; border: none;
  padding: 8px 10px; border-radius: var(--r-sm);
  font-family: inherit; font-size: 13px; color: var(--ink);
  cursor: pointer;
}
.ai-polish-menu button:hover, .chat-ai-menu button:hover { background: var(--brand-soft); color: var(--brand); }

.ai-undo-toast {
  position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
  background: var(--ink); color: var(--card);
  padding: 10px 14px; border-radius: var(--r-md);
  font-size: 13px; display: inline-flex; align-items: center; gap: 12px;
  box-shadow: var(--shadow-lg);
  z-index: 300;
  animation: ai-toast-in 0.18s cubic-bezier(0.16, 1, 0.3, 1);
}
.ai-undo-toast button {
  background: transparent; border: 1px solid rgba(255,255,255,0.3);
  color: #fff; padding: 4px 10px; border-radius: var(--r-sm);
  font-family: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
}
.ai-undo-toast button:hover { background: rgba(255,255,255,0.18); }
@keyframes ai-toast-in {
  from { opacity: 0; transform: translateX(-50%) translateY(10px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

/* Event availability picker (Patch U) */
.evt-avail { display: flex; flex-direction: column; gap: 6px; }
.evt-avail-opt {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--line); border-radius: var(--r-md);
  cursor: pointer; transition: border-color 0.12s ease, background 0.12s ease;
}
.evt-avail-opt:hover { border-color: var(--line-strong); }
.evt-avail-opt input[type="radio"] { accent-color: var(--brand); margin: 0; }
.evt-avail-opt input[type="radio"]:checked ~ span:nth-child(3) strong { color: var(--brand); }
.evt-avail-opt:has(input:checked) { border-color: var(--brand); background: var(--brand-soft); }
.evt-avail-opt .dot {
  width: 10px; height: 10px; border-radius: 50%;
  flex-shrink: 0;
}
.evt-avail-opt .dot-busy      { background: var(--accent); }
.evt-avail-opt .dot-tentative { background: var(--warn); }
.evt-avail-opt .dot-free      { background: var(--ok); }
.evt-avail-opt strong { font-size: 13px; font-weight: 600; color: var(--ink); display: block; }
.evt-avail-opt small  { font-size: 11px; color: var(--ink-soft); display: block; margin-top: 1px; }

/* Calendar / events list (Patch R) */
.events-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.event-card {
  display: flex; align-items: stretch; gap: 12px;
  background: var(--card); border: 1px solid var(--line);
  border-left: 3px solid var(--info);
  /* Hub-wide card radius — see comment on .todays-focus. */
  border-radius: var(--r-xl); padding: 12px 14px;
}
.event-card.scope-personal { border-left-color: var(--brand); background: linear-gradient(90deg, rgba(90,66,148,0.04), transparent 12%); }
.event-card.scope-club     { border-left-color: var(--info); }
.event-card.scope-country  { border-left-color: var(--warn); }
.event-card.scope-global   { border-left-color: var(--accent); }
.event-card .event-date {
  flex-shrink: 0; width: 52px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 6px 0;
}
.event-card .event-date .d { font-size: 20px; font-weight: 700; color: var(--ink); line-height: 1; }
.event-card .event-date .m { font-size: 10px; font-weight: 600; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.5px; margin-top: 2px; }
.event-card .event-body { flex: 1; min-width: 0; }
.event-card .event-title { font-size: 14px; font-weight: 600; color: var(--ink); line-height: 1.3; }
.event-card .event-meta { font-size: 12px; color: var(--ink-soft); margin-top: 2px; }
.event-card .event-meta .event-scope { color: var(--brand); font-weight: 600; }
.event-card .event-desc { font-size: 13px; color: var(--ink); margin-top: 6px; line-height: 1.5; }
.event-card .event-link { font-size: 12px; color: var(--brand); display: inline-block; margin-top: 6px; }
.event-recur {
  display: inline-block; margin-left: 6px;
  font-size: 11px; font-weight: 600; color: var(--info);
  background: var(--info-soft); padding: 1px 6px; border-radius: var(--r-sm);
}
.event-rsvp { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; align-items: center; }
.event-rsvp-label { font-size: 12px; color: var(--ink-soft); margin-right: 4px; }
.rsvp-btn {
  font-family: inherit; font-size: 12px; font-weight: 500;
  padding: 4px 10px; border-radius: var(--r-md);
  background: var(--card); border: 1px solid var(--line); color: var(--ink-soft);
  cursor: pointer; transition: all 0.12s ease;
}
.rsvp-btn:hover { border-color: var(--line-strong); color: var(--ink); }
.rsvp-btn.active.going { background: var(--ok); color: #fff; border-color: var(--ok); }
.rsvp-btn.active.maybe { background: var(--warn); color: #fff; border-color: var(--warn); }
.rsvp-btn.active.no    { background: var(--accent); color: #fff; border-color: var(--accent); }
.event-rsvp-counts { font-size: 11px; color: var(--ink-faint); margin-left: auto; }

/* Template picker inside the announcement modal */
.ann-templates {
  display: flex; flex-wrap: wrap; gap: 6px;
}
.ann-template {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 10px; border-radius: var(--r-md);
  background: var(--card); border: 1px solid var(--line);
  font-family: inherit; font-size: 13px; color: var(--ink);
  cursor: pointer;
  transition: border-color 0.12s ease, background 0.12s ease;
}
.ann-template:hover { border-color: var(--brand); }
.ann-template.active { background: var(--brand); color: #fff; border-color: var(--brand); }
.ann-template .emoji { font-size: 15px; line-height: 1; }

/* Filter row above the announcements feed */
.ann-filter-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.ann-filter {
  padding: 4px 10px; border-radius: 999px;
  background: var(--card); border: 1px solid var(--line);
  font-family: inherit; font-size: 12px; font-weight: 500; color: var(--ink-soft);
  cursor: pointer; transition: all 0.12s ease;
}
.ann-filter:hover { color: var(--ink); border-color: var(--line-strong); }
.ann-filter.active { background: var(--brand); color: #fff; border-color: var(--brand); }

/* Card-style announcement — compact, icon-driven.
   Layout: cover (optional) → title row (priority dot + title + NEW badge) →
   preview → meta strip (icons + tags + time). Hover-only edit/delete icons
   tucked top-right for managers — they don't take up space when not needed. */
.ann-section-label {
  font-size: 11px; font-weight: 700; color: var(--ink-faint);
  text-transform: uppercase; letter-spacing: 0.6px;
  margin: 18px 4px 6px;
}
.announcement {
  background: var(--card);
  border: 1px solid var(--line);
  /* Hub-wide card radius — see comment on .todays-focus. */
  border-radius: var(--r-xl);
  overflow: hidden;
  padding: 0;
  position: relative;
  display: flex; flex-direction: column;
  transition: border-color 0.12s ease, transform 0.12s ease, box-shadow 0.12s ease;
}
.announcement:hover { border-color: var(--line-strong); transform: translateY(-1px); box-shadow: var(--shadow); }
.announcement.pinned {
  border-color: rgba(180,154,255,0.35);
  background: linear-gradient(180deg, var(--brand-soft) 0%, var(--card) 8%);
}

.ann-card-link {
  display: block;
  text-decoration: none; color: inherit;
  cursor: pointer;
}
.ann-card-link:hover { text-decoration: none; }
.ann-cover-thumb {
  width: 100%;
  aspect-ratio: 16 / 5;
  background: var(--brand-soft) center/cover no-repeat;
}
.announcement:not(.featured) .ann-cover-thumb { aspect-ratio: 16 / 4; }

.ann-card-body { padding: 14px 16px 12px; display: flex; flex-direction: column; gap: 8px; }
.ann-card-title {
  margin: 0; font-size: 16px; font-weight: 700;
  color: var(--ink); letter-spacing: -0.15px;
  line-height: 1.3;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.announcement.featured .ann-card-title { font-size: 20px; }
.ann-card-link:hover .ann-card-title > span:first-of-type { color: var(--brand); }

/* Priority dot — color = urgency, no text needed. */
.ann-prio-dot {
  width: 8px; height: 8px; border-radius: 50%;
  flex-shrink: 0;
  display: inline-block;
}
.ann-prio-dot.prio-urgent    { background: var(--accent); box-shadow: 0 0 0 3px rgba(245,51,63,0.18); }
.ann-prio-dot.prio-important { background: var(--warn);   box-shadow: 0 0 0 3px rgba(180,83,9,0.16); }
.ann-prio-dot.prio-info      { background: var(--info); }
.ann-prio-dot.prio-normal    { background: var(--ink-faint); }

/* Animated NEW badge — only shows for unseen recent posts. */
/* WL#1 — Beefed-up NEW badge so unread posts are impossible to miss.
   Was: tiny 9.5px pill with a subtle pulse.
   Now: bolder pill with an accent border, larger letters + spacing,
   gentle shadow, AND the parent .announcement.is-new gets a tinted
   left-border + a corner ribbon so the whole card screams "unread". */
.ann-new-badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 10px;
  background: var(--accent); color: #fff;
  border-radius: 999px;
  font-size: 11px; font-weight: 900; letter-spacing: 0.8px;
  text-transform: uppercase;
  position: relative;
  box-shadow: 0 2px 8px rgba(245, 51, 63, 0.32);
  animation: ann-new-pulse 2.4s ease-in-out infinite;
}
.ann-new-badge::before {
  content: "●";
  font-size: 10px; line-height: 1; opacity: 0.95;
}
.ann-new-badge::after {
  content: ""; position: absolute; inset: -1px;
  border-radius: 999px;
  border: 2px solid var(--accent);
  animation: ann-new-ring 2.4s ease-out infinite;
  pointer-events: none;
}

/* Card-level treatment when a post is new. Adds a strong accent
   left-border AND a soft tint so the whole row reads as "unread"
   without needing to scan for the pill. */
.announcement.is-new {
  border-left: 4px solid var(--accent);
  background: linear-gradient(90deg, rgba(245, 51, 63, 0.045) 0%, var(--card) 18%);
  position: relative;
}
.announcement.is-new::before {
  content: "NEW";
  position: absolute;
  top: 10px; right: -6px;
  background: var(--accent); color: #fff;
  font-size: 9px; font-weight: 900; letter-spacing: 0.8px;
  padding: 3px 10px 3px 14px;
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%, 6px 50%);
  box-shadow: 0 2px 6px rgba(245, 51, 63, 0.22);
  pointer-events: none;
}
@media (max-width: 640px) {
  .announcement.is-new::before { display: none; }    /* keep the inline pill only on mobile */
}
@keyframes ann-new-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.05); }
}
@keyframes ann-new-ring {
  0%   { opacity: 0.7; transform: scale(1);   }
  70%  { opacity: 0;   transform: scale(1.6); }
  100% { opacity: 0;   transform: scale(1.6); }
}
@media (prefers-reduced-motion: reduce) {
  .ann-new-badge { animation: none; }
  .ann-new-badge::after { animation: none; opacity: 0; }
}

.ann-card-body .body {
  font-size: 13.5px; color: var(--ink-soft); line-height: 1.55;
  margin: 0;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Meta strip — small icons, tags, then time. */
.ann-card-meta {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 12px; color: var(--ink-soft);
  padding-top: 4px;
}
.ann-card-meta .ann-meta-icon {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 6px;
  background: var(--bg); border-radius: var(--r-sm);
  font-size: 12px; color: var(--ink-soft);
}
.ann-card-meta .ann-meta-icon svg { width: 12px; height: 12px; }
.ann-card-meta .ann-meta-pin   { background: var(--brand-soft); color: var(--brand); }
.ann-card-meta .ann-meta-ack   { background: var(--ok-soft); color: var(--ok); }
.ann-card-meta .ann-meta-ack .ack-count { font-weight: 700; font-size: 11px; }
.ann-card-meta .ann-meta-spacer { flex: 1; min-width: 8px; }
.ann-card-meta .ann-card-meta-time { font-size: 11px; color: var(--ink-faint); }

.ann-tag-chip {
  display: inline-flex; align-items: center;
  padding: 2px 8px;
  background: var(--brand-soft); color: var(--brand);
  border: none; border-radius: var(--r-sm);
  font-family: inherit; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.4px;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.ann-tag-chip:hover { background: var(--brand); color: #fff; }

/* Manager edit/delete — floating top-right, hover-only. */
.ann-card-foot {
  position: absolute; top: 10px; right: 10px;
  display: flex; gap: 4px;
  opacity: 0;
  transition: opacity 0.12s ease;
}
.announcement:hover .ann-card-foot,
.announcement:focus-within .ann-card-foot { opacity: 1; }
.ann-foot-icon {
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--card); border: 1px solid var(--line);
  display: grid; place-items: center;
  color: var(--ink-soft); cursor: pointer;
  transition: all 0.12s ease;
}
.ann-foot-icon svg { width: 13px; height: 13px; }
.ann-foot-icon:hover { color: var(--brand); border-color: var(--brand); }
.ann-foot-icon.danger:hover { color: var(--accent); border-color: var(--accent); }

/* Acknowledgement bits inside an announcement */
.ack-row {
  margin: 8px 0 4px;
  padding: 10px 12px;
  border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: 13px;
  flex-wrap: wrap;
}
.ack-row.ack-pending { background: var(--warn-soft); color: var(--warn); border: 1px solid rgba(180,83,9,0.18); }
.ack-row.ack-done    { background: var(--ok-soft);   color: var(--ok);   border: 1px solid rgba(21,128,61,0.18); display: inline-flex; gap: 6px; padding: 4px 10px; }
.ack-row.ack-pending strong { color: var(--ink); }

.ack-progress {
  margin-top: 6px;
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--ink-soft);
}
.ack-progress.overdue { color: var(--accent); }

.ack-list { margin-top: 6px; padding: 8px; background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-md); }
.ack-list-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 4px; }
.ack-list-row {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 8px; border-radius: var(--r-sm);
  font-size: 12px; color: var(--ink);
}
.ack-list-row .ack-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.ack-list-row.done .ack-dot { background: var(--ok); }
.ack-list-row.pending .ack-dot { background: var(--warn); }
.ack-list-row .ack-when { margin-left: auto; color: var(--ink-faint); font-size: 11px; }
.ack-list-row { flex-wrap: wrap; }
.ack-read-stats {
  flex-basis: 100%;
  padding-left: 13px;            /* aligns with name (after dot) */
  font-size: 11px;
  color: var(--info);
  margin-top: 2px;
}
.ack-read-stats.muted { color: var(--ink-faint); }

/* ---- Modal ---- */
.modal-bg { position: fixed; inset: 0; background: rgba(15, 15, 26, 0.55); display: none; align-items: center; justify-content: center; padding: 20px; z-index: 100; backdrop-filter: blur(4px); }
.modal-bg.open { display: flex; animation: pulse-modal-bg-in var(--dur-fast, 140ms) ease-out; }
.modal { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-xl); width: 100%; max-width: 520px; padding: 22px; box-shadow: var(--shadow-lg); max-height: 90vh; overflow-y: auto; }
/* Soft scale-up so the modal feels anchored to the click that opened it
   rather than just appearing. Pairs with the backdrop fade. */
.modal-bg.open .modal { animation: pulse-modal-in var(--dur-base, 220ms) var(--ease-out, cubic-bezier(0.16, 1, 0.3, 1)); }
@keyframes pulse-modal-bg-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pulse-modal-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0)   scale(1); }
}
.modal h3 { margin: 0 0 14px; font-size: 16px; font-weight: 600; letter-spacing: -0.1px; }
.modal-actions { display: flex; justify-content: flex-end; gap: 6px; margin-top: 8px; }

/* ---- Banners / alerts ---- */
.alert { padding: 10px 12px; border-radius: var(--r-md); font-size: 13px; margin-bottom: 12px; line-height: 1.5; border: 1px solid transparent; }
.alert.ok     { background: var(--ok-soft);     color: var(--ok);     border-color: rgba(21,128,61,0.18); }
.alert.danger { background: var(--accent-soft); color: var(--accent); border-color: rgba(245,51,63,0.18); }
.alert.warn   { background: var(--warn-soft);   color: var(--warn);   border-color: rgba(180,83,9,0.18); }
.alert.info   { background: var(--info-soft);   color: var(--info);   border-color: rgba(71,190,219,0.25); }

/* ---- Tabs ----
   Brand: active tab uses Burple underline, not just neutral ink. */
.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin-bottom: 18px; }
.tabs button { background: none; border: none; padding: 8px 12px; font-size: 13px; font-weight: 500; color: var(--ink-soft); cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -1px; font-family: inherit; transition: color 0.12s ease, border-color 0.12s ease; }
.tabs button:hover { color: var(--ink); }
.tabs button.active { color: var(--brand); border-bottom-color: var(--brand); font-weight: 600; }

/* ---- Multi-checkbox ---- */
.checkgroup { display: flex; flex-direction: column; gap: 4px; padding: 8px; border: 1px solid var(--line); border-radius: var(--r-md); background: var(--card); max-height: 220px; overflow-y: auto; }
.checkgroup label { display: flex; align-items: center; gap: 10px; font-size: 13px; cursor: pointer; padding: 6px 8px; border-radius: var(--r-sm); }
.checkgroup label:hover { background: var(--bg); }
.checkgroup input[type="checkbox"] { accent-color: var(--brand); width: 15px; height: 15px; }
.checkgroup label small { color: var(--ink-faint); margin-left: auto; }

/* ---- Footer ---- */
footer { margin-top: 40px; text-align: center; font-size: 12px; color: var(--ink-soft); opacity: 0.8; }

/* ---- Loading ---- */
.spinner { width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--line); border-top-color: var(--brand); animation: spin 0.8s linear infinite; display: inline-block; vertical-align: middle; }
@keyframes spin { to { transform: rotate(360deg); } }
.loading-screen { display: flex; align-items: center; justify-content: center; min-height: 70vh; gap: 10px; color: var(--ink-soft); font-size: 14px; }

/* ---- Hub two-column layout (Patch ZZCO-d) ----
   Desktop (>= 900px) splits the Hub into two columns side-by-side:
     - .hub-col-left  = action / clock-in / attention / followups
     - .hub-col-right = announcements / events / coaching / KPIs
   The .hub-tabs strip is mobile-only and switches which column is
   visible. On desktop both columns render together and the tab strip
   is hidden. */
.hub-cols {
  display: grid;
  /* 70 / 30 split — the wide left column holds the Posts feed
     (announcements + events + coaching) and the narrow right column
     is the action sidebar (clock-in + shifts + attention). */
  grid-template-columns: minmax(0, 7fr) minmax(0, 3fr);
  gap: 20px;
  align-items: start;
}
.hub-col {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.hub-tabs {
  display: none;
  gap: 6px;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 4px;
  margin-bottom: 14px;
  position: sticky;
  top: 64px;
  z-index: 5;
  backdrop-filter: blur(8px);
}
.hub-tab {
  flex: 1;
  background: transparent;
  border: 0;
  padding: 9px 12px;
  border-radius: 8px;
  font: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.hub-tab:hover { background: rgba(0,0,0,0.04); }
body[data-theme="dark"] .hub-tab:hover { background: rgba(255,255,255,0.06); }
.hub-tab.is-active {
  background: var(--card);
  color: var(--brand);
  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
}
@media (max-width: 899px) {
  .hub-cols {
    display: block;
  }
  .hub-tabs { display: flex; }
  .hub-col { display: none; }
  .hub-col.is-active { display: flex; }
}

/* ---- Clock-in streak confetti (Patch ZZCO) ----
   Pure-CSS confetti burst that pops at 7/30/100-day clock-in streak
   milestones. The host element is positioned absolutely at the centre
   of the clock-card, and each child <span> uses --dx/--dy custom
   properties (set inline by fireConfetti()) for a randomised radial
   spread. Auto-removed by the caller after ~1.6s so no cleanup needed. */
.clock-confetti {
  position: fixed;
  pointer-events: none;
  z-index: 99999;
  width: 0;
  height: 0;
}
.clock-confetti span {
  position: absolute;
  left: 0; top: 0;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  transform: translate(-50%, -50%);
  animation: clockConfetti 1.4s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
@keyframes clockConfetti {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.4) rotate(0deg); }
  10%  { opacity: 1; }
  100% { opacity: 0; transform: translate(calc(-50% + var(--dx, 0)), calc(-50% + var(--dy, 0))) scale(0.8) rotate(360deg); }
}

/* Shared loading shell — sits inside any page's primary mount
   container as the initial HTML so users see content shape +
   movement instead of a blank white page during boot. Modelled
   on the campaigns page's empty state — hourglass icon, soft
   card with dashed border, gentle pulse + drift to signal that
   work is happening. Pages can replace the contents on first
   render; this CSS is purely visual and adds zero JS dependency. */
.pulse-loading {
  background: var(--card);
  border: 1px dashed var(--line-strong);
  border-radius: 14px;
  padding: 48px 24px;
  text-align: center;
  color: var(--ink-soft);
  max-width: 720px;
  margin: 40px auto;
  animation: pulseLoadingIn 0.32s ease-out;
}
.pulse-loading .ico {
  font-size: 40px;
  margin-bottom: 10px;
  display: inline-block;
  animation: pulseLoadingHourglass 1.8s ease-in-out infinite;
}
.pulse-loading h3 {
  color: var(--ink);
  margin: 0 0 6px;
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -0.2px;
}
.pulse-loading p {
  margin: 0;
  font-size: 13px;
  color: var(--ink-soft);
  line-height: 1.55;
  max-width: 380px;
  margin-left: auto;
  margin-right: auto;
}
@keyframes pulseLoadingIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
/* Subtle rock + scale on the hourglass — keeps the user feeling
   like something is happening even on the slowest cold-load. */
@keyframes pulseLoadingHourglass {
  0%   { transform: rotate(0deg)   scale(1); }
  45%  { transform: rotate(8deg)   scale(1.08); }
  50%  { transform: rotate(180deg) scale(1.08); }
  95%  { transform: rotate(188deg) scale(1); }
  100% { transform: rotate(360deg) scale(1); }
}

.hidden { display: none !important; }

/* =============================================================
   Profile drawer — opens when you click someone's name/avatar
   in chat. Right-side slide-in with avatar, contact info, and
   Message/Email/Call action buttons.
   ============================================================= */
.profile-drawer-bg {
  position: fixed; inset: 0; z-index: 150;
  background: rgba(15,15,26,0.45); backdrop-filter: blur(4px);
  display: none; justify-content: flex-end;
  opacity: 0; transition: opacity 0.18s ease;
}
.profile-drawer-bg.open { display: flex; opacity: 1; }
.profile-drawer {
  width: 100%; max-width: 380px; height: 100%;
  background: var(--card);
  border-left: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  padding: 22px 22px 28px;
  overflow-y: auto;
  position: relative;
  transform: translateX(20px); transition: transform 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}
.profile-drawer-bg.open .profile-drawer { transform: translateX(0); }
.profile-drawer-close {
  position: absolute; top: 14px; right: 14px;
  width: 30px; height: 30px; border-radius: var(--r-md);
  background: transparent; border: 1px solid transparent;
  color: var(--ink-soft); cursor: pointer; display: grid; place-items: center;
  transition: background 0.12s ease, color 0.12s ease;
}
.profile-drawer-close:hover { background: var(--bg); color: var(--ink); }

.profile-hero {
  display: flex; gap: 14px; align-items: center; margin-bottom: 18px; padding-top: 6px;
}
.profile-avatar {
  width: 64px; height: 64px; border-radius: 50%;
  background: var(--brand); color: #fff;
  display: grid; place-items: center;
  font-size: 22px; font-weight: 700;
  flex-shrink: 0;
  object-fit: cover;
  border: 1px solid var(--line);
}
img.profile-avatar { background: var(--bg); }
.profile-hero-text { min-width: 0; }
.profile-hero h2 { margin: 0; font-size: 18px; font-weight: 600; letter-spacing: -0.2px; color: var(--ink); }
.profile-position { margin-top: 2px; font-size: 13px; color: var(--ink-soft); }
.profile-presence {
  margin-top: 6px; display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--ink-soft);
}
.presence-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--ink-faint);
  display: inline-block;
}
.presence-online   .presence-dot { background: var(--ok);   box-shadow: 0 0 0 2px rgba(21,128,61,0.18); }
.presence-recent   .presence-dot { background: var(--info); box-shadow: 0 0 0 2px rgba(71,190,219,0.20); }
.presence-away     .presence-dot { background: var(--warn); }
.presence-dnd      .presence-dot { background: var(--accent); box-shadow: 0 0 0 2px rgba(245,51,63,0.20); }
.presence-ooo      .presence-dot { background: #B07A1A; }
.presence-offline  .presence-dot { background: var(--ink-faint); }

/* OOO banner inside profile drawer */
.profile-ooo-banner {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 12px 14px;
  background: linear-gradient(135deg, var(--warn-soft), rgba(180,123,26,0.06));
  border: 1px solid rgba(180,83,9,0.20);
  border-radius: var(--r-md);
  margin-bottom: 14px;
}
.profile-ooo-banner .ooo-icon { font-size: 22px; line-height: 1; }
.profile-ooo-banner .ooo-title { font-size: 13px; font-weight: 700; color: var(--warn); }
.profile-ooo-banner .ooo-msg { font-size: 12px; color: var(--ink); margin-top: 4px; line-height: 1.5; white-space: pre-wrap; }

.profile-actions {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 6px; margin-bottom: 20px;
}
.profile-action {
  display: inline-flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 10px 8px; border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--card); color: var(--ink); text-decoration: none;
  font-size: 12px; font-weight: 500; cursor: pointer; font-family: inherit;
  transition: border-color 0.12s ease, background 0.12s ease, color 0.12s ease;
}
.profile-action svg { width: 18px; height: 18px; }
.profile-action:hover { background: var(--bg); border-color: var(--line-strong); color: var(--ink); text-decoration: none; }
.profile-action.profile-action-primary { background: var(--brand); border-color: var(--brand); color: #fff; }
.profile-action.profile-action-primary:hover { background: var(--brand-dark); border-color: var(--brand-dark); color: #fff; }

.profile-section { padding: 12px 0; border-top: 1px solid var(--line); }
.profile-section:last-of-type { border-bottom: 1px solid var(--line); }
.profile-section-label { font-size: 11px; font-weight: 600; color: var(--ink-soft); margin-bottom: 4px; }
.profile-section-value { font-size: 13.5px; color: var(--ink); display: inline-flex; align-items: center; gap: 6px; }
.profile-section-value a { color: var(--brand); }
.profile-muted { color: var(--ink-faint); font-size: 13px; }
.profile-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.profile-chip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 8px; border-radius: var(--r-sm);
  background: var(--bg); border: 1px solid var(--line);
  font-size: 12px; color: var(--ink);
}
.profile-pill {
  display: inline-flex; align-items: center; padding: 1px 6px;
  font-size: 10px; font-weight: 600; border-radius: var(--r-sm);
  margin-left: 4px;
}
.profile-pill.warn { background: var(--warn-soft); color: var(--warn); }

/* Mobile: full-width drawer */
@media (max-width: 540px) {
  .profile-drawer { max-width: 100%; }
}

/* Clickable affordances for chat author/avatar/members rows */
.avatar-btn {
  background: transparent; border: none; padding: 0; cursor: pointer; font: inherit;
  display: inline-block; line-height: 0;
  border-radius: 50%; transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.avatar-btn:hover { transform: scale(1.04); }
.avatar-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.author-btn {
  background: transparent; border: none; padding: 0; cursor: pointer; font: inherit;
  color: inherit; transition: color 0.12s ease;
}
.author-btn:hover { color: var(--brand); text-decoration: underline; }
.thread-title .name.clickable { cursor: pointer; }
.thread-title .name.clickable:hover { color: var(--brand); }
.members-row.clickable {
  width: 100%; text-align: left; cursor: pointer; font-family: inherit;
  background: transparent; border: 1px solid transparent; border-radius: var(--r-md);
  padding: 8px 10px; display: flex; align-items: center; gap: 10px;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.members-row.clickable:hover { background: var(--bg); border-color: var(--line); }

/* =============================================================
   SPA page transitions — Apple-style soft cross-fade with subtle
   vertical drift. ease-out-quint (cubic-bezier(0.16, 1, 0.3, 1))
   gives the "snappy in, settle out" feel.
   ============================================================= */
body.spa-leaving > *:not(#topbar) {
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity 0.18s cubic-bezier(0.4, 0, 0.6, 1),
              transform 0.18s cubic-bezier(0.4, 0, 0.6, 1);
}
@keyframes pulse-page-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
body.spa-entering > *:not(#topbar) {
  animation: pulse-page-in 0.5s cubic-bezier(0.16, 1, 0.3, 1) backwards;
}
/* Stagger the major children of the main content area so cards/sections
   slide up sequentially instead of in one block — feels finer-grained. */
@keyframes pulse-stagger-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: translateY(0); }
}
body.spa-entering .wrap > *,
body.spa-entering .chat-shell > * {
  animation: pulse-stagger-in 0.55s cubic-bezier(0.16, 1, 0.3, 1) backwards;
}
body.spa-entering .wrap > *:nth-child(1),
body.spa-entering .chat-shell > *:nth-child(1) { animation-delay: 0.04s; }
body.spa-entering .wrap > *:nth-child(2),
body.spa-entering .chat-shell > *:nth-child(2) { animation-delay: 0.10s; }
body.spa-entering .wrap > *:nth-child(3) { animation-delay: 0.16s; }
body.spa-entering .wrap > *:nth-child(4) { animation-delay: 0.22s; }
body.spa-entering .wrap > *:nth-child(5) { animation-delay: 0.28s; }
body.spa-entering .wrap > *:nth-child(6) { animation-delay: 0.34s; }
body.spa-entering .wrap > *:nth-child(7) { animation-delay: 0.40s; }

/* Respect users who've turned off motion */
@media (prefers-reduced-motion: reduce) {
  body.spa-leaving > *:not(#topbar),
  body.spa-entering > *:not(#topbar),
  body.spa-entering .wrap > *,
  body.spa-entering .chat-shell > * {
    animation: none !important;
    transition: opacity 0.12s linear !important;
    transform: none !important;
  }
}

/* ---- Global reduced-motion safety net ----
   Every page and patch over the last year ships its own keyframes.
   Rather than chase every one of them with a scoped override, this
   catch-all kills decorative motion when the OS says the user
   prefers reduced motion. Per WCAG, we don't disable motion that
   conveys meaning — only durations/decoration. Anything genuinely
   needed (e.g. an active spinner) should explicitly opt back in
   inside this block. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  /* Spinners still need to spin to communicate "loading". Reduce
     to a much slower rotation rather than freezing them. */
  .spinner, .th-spinner {
    animation-duration: 1.6s !important;
    animation-iteration-count: infinite !important;
  }
}

/* ---- Responsive ---- */
@media (max-width: 640px) {
  .hero { padding: 22px; }
  .hero h1 { font-size: 20px; }
  .grid { grid-template-columns: 1fr; }
  .section-title { flex-direction: column; align-items: flex-start; gap: 8px; }
  table.dataset thead { display: none; }
  table.dataset tbody td { display: block; padding: 8px 14px; border: none; }
  table.dataset tbody tr { display: block; padding: 12px 0; border-bottom: 1px solid var(--line); }

  /* Topbar mobile redesign — hamburger pattern.
     The previous 2-row attempt still left the Hub pill bleeding
     out of the club switcher because the active-page badge
     and the nav row competed for the same horizontal space.
     The clean fix (per Ben's call): collapse the entire nav
     into a ☰ button on mobile, slide a panel in from the right
     when tapped. Single row, no overflow, no badge collision.

     Row contents on mobile: wordmark + club switcher (flexes
     to fill) + ☰ hamburger. Everything else is in the slide-in
     panel: nav links, tools menu, theme toggle, presence,
     avatar dropdown. */
  .topbar {
    padding: 10px 14px;
    gap: 8px;
  }
  .topbar-left {
    flex: 1 1 auto;
    min-width: 0;
    gap: 8px;
  }
  /* Truncate the club switcher trigger text so the "Hub" /
     "CRM" / etc. active-page badge can sit cleanly inside
     instead of bleeding onto the wordmark. */
  .topbar-left > .club-switcher { flex: 1 1 auto; min-width: 0; max-width: 100%; }
  .topbar-left > .club-switcher .cs-trigger {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  /* Hide the desktop nav row entirely on mobile.
     `display:none` (not visibility:hidden) so it doesn't
     take horizontal space. The body content moves into the
     slide-in panel below. */
  .topbar .nav { display: none; }
  /* Show the hamburger button — `display:none` by default
     on desktop, flipped to flex on mobile here. */
  .topbar-hamburger {
    display: inline-flex !important;
    align-items: center; justify-content: center;
    width: 40px; height: 40px;
    background: var(--bg);
    border: 1px solid var(--line);
    border-radius: 10px;
    cursor: pointer;
    color: var(--ink);
    flex-shrink: 0;
  }
  .topbar-hamburger:hover { background: var(--brand-soft); border-color: var(--brand); }
  .topbar-hamburger svg { width: 20px; height: 20px; }
}

/* Desktop: hide the hamburger entirely. */
.topbar-hamburger { display: none; }

/* Mobile quick-action icons (Chat + Attention) — hidden on desktop, shown
   on mobile inside the same media query as the hamburger. They live just
   to the left of the hamburger so the unread badges are visible at a glance
   without opening the menu. */
.topbar-mobile-quick { display: none; }
@media (max-width: 768px) {
  .topbar-mobile-quick {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
  }
  .topbar-mobile-icon {
    position: relative;
    width: 40px; height: 40px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--bg);
    border: 1px solid var(--line);
    border-radius: 10px;
    color: var(--ink);
    cursor: pointer;
    flex-shrink: 0;
    text-decoration: none;
  }
  .topbar-mobile-icon:hover,
  .topbar-mobile-icon:focus {
    background: var(--brand-soft);
    border-color: var(--brand);
    color: var(--brand);
  }
  .topbar-mobile-icon svg { width: 18px; height: 18px; }
  .topbar-mobile-badge {
    position: absolute; top: -4px; right: -4px;
    min-width: 18px; height: 18px;
    padding: 0 5px;
    background: #DC2626; color: #fff;
    border: 2px solid var(--card);
    border-radius: 999px;
    font-size: 10px; font-weight: 800;
    line-height: 14px; text-align: center;
    box-sizing: content-box;
  }
  .topbar-mobile-badge[hidden] { display: none; }
}

/* Slide-in mobile menu panel — opens from the right when
   the hamburger is tapped. Covers ~85% of the viewport so
   there's a sliver of dim backdrop on the left to tap-close. */
.mobile-menu-back {
  position: fixed; inset: 0;
  background: rgba(15,23,42,0.55);
  z-index: 9500;
  display: none;
  backdrop-filter: blur(2px);
  animation: mobile-menu-fade 0.16s ease;
}
.mobile-menu-back.is-open { display: block; }
.mobile-menu-panel {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: 85vw; max-width: 340px;
  background: var(--card);
  z-index: 9600;
  display: none;
  flex-direction: column;
  box-shadow: -20px 0 60px rgba(0,0,0,0.30);
  animation: mobile-menu-slide 0.22s ease;
}
.mobile-menu-panel.is-open { display: flex; }
@keyframes mobile-menu-slide {
  from { transform: translateX(100%); }
  to   { transform: translateX(0); }
}
@keyframes mobile-menu-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.mobile-menu-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 18px;
  border-bottom: 1px solid var(--line);
}
.mobile-menu-head-title {
  font-size: 11px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--ink-soft);
}
.mobile-menu-close {
  background: transparent; border: 0;
  font-size: 24px; line-height: 1;
  color: var(--ink-soft);
  cursor: pointer; padding: 4px 10px;
}
.mobile-menu-body { flex: 1; overflow-y: auto; padding: 8px 0; }
.mobile-menu-section {
  padding: 10px 18px 4px;
  font-size: 10px; font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--ink-soft);
  margin-top: 8px;
}
/* Sub-section header inside a single block (e.g. "Club ops" after
   "Members & leads"). Gets a thin divider above so the eye can find
   the boundary without us pushing the next section too far down. */
.mobile-menu-section-sub {
  margin-top: 12px;
  border-top: 1px solid var(--line);
  padding-top: 12px;
}
.mobile-menu-ext {
  margin-left: auto;
  font-size: 12px;
  color: var(--ink-faint);
}
.mobile-menu-link {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 18px;
  font-family: inherit; font-size: 14px; font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  border: 0; background: transparent;
  width: 100%; text-align: left;
  cursor: pointer;
}
.mobile-menu-link:hover { background: var(--brand-soft); color: var(--brand); }
.mobile-menu-link.active { background: var(--brand-soft); color: var(--brand); font-weight: 800; }
.mobile-menu-link .badge {
  margin-left: auto;
  background: #FEE2E2; color: #B91C1C;
  font-size: 10px; font-weight: 800;
  padding: 2px 7px; border-radius: 999px;
  min-width: 22px; text-align: center;
}
.mobile-menu-link .badge.brand { background: var(--brand-soft); color: var(--brand); }

/* =============================================================
   PULSE DESIGN SYSTEM — `.ds-*` primitives
   Reference page: bad-debt-report.html (Ben's pick).
   Rule: every NEW page builds with these classes. Existing pages
   migrate incrementally. Page-specific `.foo-*` classes are
   allowed only where the primitive doesn't fit — and that's a
   prompt to extend the system, not duplicate the styles.
   ============================================================= */

/* Page shell — every staff-facing page wraps content in this. */
.ds-wrap { max-width: 1280px; margin: 0 auto; padding: 24px 22px 80px; }
@media (max-width: 640px) { .ds-wrap { padding: 16px 14px 60px; } }

/* Header — the purple gradient hero. Canonical pattern: an eyebrow
   line (small uppercase scope text), a big bold title, a one-line
   subtitle in lighter white, and an optional .actions row of pill
   buttons. Used by every staff-facing page. CRM was the reference
   look; ds-head matches it 1:1 so a future "make all pages look like
   CRM" sweep is a no-op. */
.ds-head {
  background: linear-gradient(135deg, #2A1B4E 0%, #5A4294 50%, #7C3AED 100%);
  color: #fff;
  border-radius: var(--r-lg);
  padding: 26px 28px 28px;
  margin-bottom: 16px;
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
}
.ds-head .eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.7px;
  font-size: 11px;
  font-weight: 700;
  opacity: 0.75;
  margin-bottom: 5px;
}
.ds-head h1 {
  margin: 0;
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.5px;
  color: #fff;
}
.ds-head .sub {
  font-size: 13px;
  opacity: 0.82;
  margin-top: 4px;
  max-width: 540px;
  line-height: 1.5;
}
/* Actions row — sits on the right of the header. Pill-style buttons
   on a semi-transparent white background, plus a .primary variant
   for the call-to-action. Wraps below the title block on narrow
   viewports thanks to the parent's flex-wrap. */
.ds-head .actions,
.ds-head-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}
.ds-head .actions a,
.ds-head .actions button,
.ds-head-actions a,
.ds-head-actions .btn {
  background: rgba(255,255,255,0.15);
  color: #fff;
  border: 1px solid rgba(255,255,255,0.3);
  padding: 9px 14px;
  border-radius: var(--r-md);
  font-family: inherit;
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  transition: background 0.12s ease;
}
.ds-head .actions a:hover,
.ds-head .actions button:hover,
.ds-head-actions a:hover,
.ds-head-actions .btn:hover {
  background: rgba(255,255,255,0.25);
}
.ds-head .actions .btn.primary,
.ds-head-actions .btn.primary {
  background: #fff;
  color: #5A4294;
  border-color: #fff;
}
.ds-head .actions .btn.primary:hover,
.ds-head-actions .btn.primary:hover {
  background: #F3F4F6;
}
.ds-head .actions .btn.on,
.ds-head-actions .btn.on {
  background: rgba(255,255,255,0.32);
  border-color: rgba(255,255,255,0.55);
}
/* Back-link uses the same pill style — kept as a separate selector for
   backward compatibility with pages that wrap a single chevron link. */
.ds-head .back-link {
  background: rgba(255,255,255,0.15);
  color: #fff;
  border: 1px solid rgba(255,255,255,0.3);
  padding: 9px 14px;
  border-radius: var(--r-md);
  font-weight: 600;
  font-size: 13px;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Section heading + content card spacing */
.ds-section { margin-bottom: 24px; }
.ds-section-title {
  font-size: 11px; font-weight: 800; letter-spacing: 0.6px;
  text-transform: uppercase; color: var(--ink-soft); margin: 0 0 8px;
}

/* Scope picker card (country / club). Shared shape across modules. */
.ds-scope {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 14px 16px; margin-bottom: 16px;
}
.ds-scope-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.ds-scope-chip {
  background: var(--bg); color: var(--ink-soft); border: 1px solid var(--line);
  padding: 6px 12px; border-radius: 999px;
  font-family: inherit; font-size: 12px; font-weight: 700; cursor: pointer;
  transition: all 0.14s ease;
}
.ds-scope-chip:hover { color: var(--ink); border-color: var(--brand); }
.ds-scope-chip.active { background: var(--brand); color: #fff; border-color: var(--brand); }
.ds-scope-clubs {
  display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px;
  padding-top: 10px; border-top: 1px dashed var(--line);
}
.ds-scope-club {
  background: var(--bg); border: 1px solid var(--line);
  padding: 5px 10px; border-radius: 999px;
  font-size: 11px; font-weight: 600; color: var(--ink-soft);
  cursor: pointer; user-select: none;
}
.ds-scope-club.on { background: var(--brand-soft); color: var(--brand); border-color: var(--brand); font-weight: 700; }
.ds-scope-note { font-size: 11px; color: var(--ink-soft); margin-top: 8px; }

/* KPI tiles — colored left accent bar, big number, subtle subtitle. */
.ds-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; }
.ds-kpi {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 12px 14px; position: relative;
}
.ds-kpi::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: var(--brand); opacity: 0.7; border-radius: var(--r-lg) 0 0 var(--r-lg);
}
.ds-kpi.indigo::before { background: #6366F1; }
.ds-kpi.green::before  { background: #10B981; }
.ds-kpi.amber::before  { background: #F59E0B; }
.ds-kpi.rose::before   { background: #EC4899; }
.ds-kpi.red::before    { background: #DC2626; }
.ds-kpi.blue::before   { background: #3B82F6; }
.ds-kpi .lbl { font-size: 10px; font-weight: 700; letter-spacing: 0.5px; text-transform: uppercase; color: var(--ink-soft); }
.ds-kpi .val { font-size: 24px; font-weight: 800; color: var(--ink); margin-top: 2px; letter-spacing: -0.4px; line-height: 1.1; }
.ds-kpi .sub { font-size: 11px; color: var(--ink-soft); margin-top: 3px; line-height: 1.5; }

/* Watch-out cards — owner-grade signals. */
.ds-watch-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 10px; }
.ds-watch {
  background: var(--card); border: 1px solid var(--line);
  border-left: 4px solid #DC2626;
  border-radius: var(--r-lg); padding: 12px 14px;
}
.ds-watch.warn { border-left-color: #F59E0B; }
.ds-watch.info { border-left-color: #6366F1; }
.ds-watch.good { border-left-color: #10B981; }
.ds-watch .lbl { font-size: 10px; font-weight: 800; letter-spacing: 0.6px; text-transform: uppercase; color: var(--ink-soft); }
.ds-watch .head { font-size: 14px; font-weight: 800; color: var(--ink); margin-top: 4px; line-height: 1.3; }
.ds-watch .body { font-size: 12px; color: var(--ink-soft); margin-top: 4px; line-height: 1.5; }

/* Generic content card */
.ds-card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 14px 16px;
}

/* Pills (inline chips on cards / rows). Use kinds for status,
   colors stay consistent — green = good, amber = warn, red =
   bad/inactive, blue = info/upcoming, purple = brand/star,
   gray = neutral. */
.ds-pill {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 10px; font-weight: 800; letter-spacing: 0.3px;
  padding: 2px 8px; border-radius: 999px; text-transform: uppercase;
  white-space: nowrap;
}
.ds-pill.good    { background: rgba(16,185,129,0.15); color: #047857; }
.ds-pill.warn    { background: rgba(245,158,11,0.18); color: #B45309; }
.ds-pill.bad     { background: rgba(220,38,38,0.12); color: #B91C1C; }
.ds-pill.info    { background: rgba(59,130,246,0.15); color: #1E40AF; }
.ds-pill.brand   { background: rgba(167,139,250,0.15); color: #6D28D9; }
.ds-pill.star    { background: rgba(245,158,11,0.18); color: #B45309; }
.ds-pill.neutral { background: rgba(156,163,175,0.18); color: #4B5563; }
.ds-pill.inactive { background: rgba(156,163,175,0.18); color: #6B7280; }

/* Filter chips (faceted filter rail above a list). Same shape as
   scope-chip but in a horizontal rail with a label prefix. */
.ds-filter-bar {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 10px 14px; margin-bottom: 14px; display: flex; flex-direction: column; gap: 10px;
}
.ds-filter-dim { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.ds-filter-dim-label { font-size: 10px; font-weight: 700; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.4px; min-width: 70px; }
.ds-chip {
  appearance: none; border: 1px solid var(--line); background: var(--card);
  color: var(--ink); padding: 4px 10px; border-radius: 999px;
  font-size: 11px; font-weight: 700; cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
}
.ds-chip:hover { border-color: var(--brand); }
.ds-chip.active { border-color: var(--brand); background: rgba(167,139,250,0.15); color: var(--brand); }
.ds-chip .count { opacity: 0.7; font-weight: 600; }

/* Bulk action bar — floats at the BOTTOM of the viewport when rows
   are selected. Dark pill, brand-purple count chip, white-translucent
   buttons. Lifted from bad-debt.html (Ben's reference pattern) so the
   selection UX is identical across every list view in the app.
   Use it for: bulk delete, bulk WhatsApp, bulk mark-paid, bulk archive
   — anywhere multi-select on a list calls for follow-on actions. */
.ds-bulk-bar {
  position: sticky; bottom: 12px; z-index: 50;
  background: var(--ink); color: #fff;
  padding: 10px 16px; border-radius: 999px;
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
  box-shadow: 0 8px 24px rgba(0,0,0,0.25);
  margin: 14px auto; max-width: max-content;
}
.ds-bulk-bar .count {
  background: var(--brand); padding: 2px 10px; border-radius: 999px;
  font-size: 12px; font-weight: 800;
}
.ds-bbtn {
  background: rgba(255,255,255,0.12); color: #fff;
  border: 1px solid rgba(255,255,255,0.25);
  padding: 6px 14px; border-radius: 999px;
  font-size: 12px; font-weight: 700; cursor: pointer; font-family: inherit;
  transition: background 0.12s ease;
}
.ds-bbtn:hover    { background: rgba(255,255,255,0.22); }
.ds-bbtn.success  { background: #16A34A; border-color: #16A34A; }
.ds-bbtn.success:hover { background: #15803D; }
.ds-bbtn.danger   { background: #DC2626; border-color: #DC2626; }
.ds-bbtn.danger:hover  { background: #B91C1C; }
.ds-bbtn.warn     { background: #F59E0B; border-color: #F59E0B; }
.ds-bbtn.warn:hover    { background: #D97706; }
.ds-bulk-bar .ds-bbtn-link {
  background: none; border: none; color: rgba(255,255,255,0.7);
  font-size: 12px; font-weight: 700; cursor: pointer; padding: 6px 10px;
  font-family: inherit;
}
.ds-bulk-bar .ds-bbtn-link:hover { color: #fff; }

/* Empty state */
.ds-empty {
  padding: 28px 22px; text-align: center; color: var(--ink-soft);
  border: 1px dashed var(--line); border-radius: var(--r-lg); background: var(--bg);
  font-size: 13px;
}
.ds-empty strong { color: var(--ink); display: block; margin-bottom: 4px; font-size: 14px; }

/* Banner — info / warn / sg / my. Sg/My pick country tones. */
.ds-banner {
  margin-bottom: 12px; padding: 10px 14px; border-radius: var(--r-lg);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 13px;
  background: rgba(59,130,246,0.08); border: 1px solid rgba(59,130,246,0.25); color: #1E3A8A;
}
.ds-banner.sg { background: rgba(59,130,246,0.08); border-color: rgba(59,130,246,0.25); color: #1E3A8A; }
.ds-banner.my { background: rgba(220,38,38,0.08); border-color: rgba(220,38,38,0.25); color: #991B1B; }
.ds-banner.warn { background: rgba(245,158,11,0.12); border-color: rgba(245,158,11,0.4); color: #92400E; }
.ds-banner.info { background: var(--bg); border-color: var(--line); color: var(--ink-soft); }
.ds-banner .flag { font-size: 18px; line-height: 1; }

/* Inline help (?) icon — `tip()` helper renders this. */
.ds-tip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--bg); color: var(--ink-soft); font-size: 9px; font-weight: 800;
  border: 1px solid var(--line); cursor: help;
  margin-left: 4px; vertical-align: middle;
}

/* Link-style button — flat text in brand colour. */
.ds-link {
  appearance: none; background: none; border: none; font-family: inherit;
  color: var(--brand); font-size: 12px; font-weight: 700; cursor: pointer; padding: 0;
}
.ds-link:hover { text-decoration: underline; }

/* Data table — same look as bad-debt-report .bdr-compare. */
.ds-table {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg);
  overflow: hidden;
}
.ds-table table { width: 100%; border-collapse: collapse; font-size: 12px; }
.ds-table th, .ds-table td { padding: 9px 12px; text-align: left; border-bottom: 1px solid var(--line); }
.ds-table th {
  background: var(--bg); font-size: 10px; font-weight: 800;
  letter-spacing: 0.5px; text-transform: uppercase; color: var(--ink-soft);
}
.ds-table td.num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ink); }
.ds-table tr:last-child td { border-bottom: 0; }
.ds-table tr:hover td { background: var(--bg); }

/* =============================================================
   Liquid Glass — site-wide (excludes chat)
   ============================================================= */
/* Originally Hub-only; lifted off the data-hub-mode scope so every
   page (CRM, bad-debt, petty-cash, campaigns, admin, attendance,
   live, KB, announcement detail, etc.) gets the same frosted-pane
   feel. Chat is excluded via body.chat-body — its WhatsApp-style
   full-bleed layout would fight the gradient, and message bubbles
   are too high-density for backdrop-filter to be cheap.

   Recipe (three pieces):
     1) Page gradient mesh — three radial colour washes layered
        over --bg so glass has varied colour to refract. Intensity
        is set high enough to be visible WITHOUT distracting from
        text legibility.
     2) Glass cards — translucent fill + backdrop blur + saturate
        + inset top + bottom highlight (top catches light, bottom
        is a faint inner glow) + ambient float shadow.
     3) Coloured-gradient cards — keep their fills, inherit the
        inset highlight + deepened shadow so they read as same-
        family but painted in colour. */

html, body {
  /* Patch ZZCR v9 — apply to BOTH html + body. On short pages
     (loading state, login, error screens) the body collapses
     to its content height. With the gradient only on body, the
     area below body's bottom showed plain --bg from the html
     element — visible as a hard horizontal cut-off. Painting
     the gradient on html (which always fills the viewport at
     100% height) AND body (so direct body-styled selectors
     still cascade) keeps the wash seamless on every page state.
     background-attachment:fixed pins both to the viewport so
     they render identically — no visible seam.

     Gradient v4 spec: "tasteful, not loud" — two large soft
     orbs + faint linear base. Applied site-wide including chat
     (Ben's ask). Calm alphas so content cards remain primary. */
  /* Orbs anchored INSIDE the viewport (20%/15% and 80%/85%)
     instead of off-screen corners — so on wide layouts like
     chat the colour reaches the middle of the page. Alphas
     lifted from 0.18/0.14 to 0.26/0.20 so the wash is visible
     without being loud. Comments live OUTSIDE the value because
     some Chrome versions discard a shorthand when comments
     appear between commas inside it. */
  /* Patch ZZCR v8 — Chat looked right at v7 but Hub still too
     coloured. Why: chat masks the body gradient via its 65%
     white shell+sidebar, so the visible gradient is ~35% of
     body's alpha. Hub between cards shows the body gradient at
     full strength. Halving alphas again so Hub-between-cards
     matches chat-through-shell. Full-page coverage geometry
     preserved. */
  background:
    radial-gradient(130vw 130vh at 0% 0%, rgba(124, 92, 201, 0.035), transparent 70%),
    radial-gradient(130vw 130vh at 100% 100%, rgba(71, 190, 219, 0.030), transparent 70%),
    linear-gradient(135deg, rgba(124, 92, 201, 0.012), rgba(71, 190, 219, 0.012)),
    var(--bg);
  background-attachment: fixed, fixed, fixed, fixed;
}
:root[data-theme="dark"] html,
:root[data-theme="dark"] body {
  /* Dark mode keeps a slightly heavier alpha so the orbs
     remain visible against near-black; still calmer than v7.
     Applied to html + body for the same reason as light mode —
     short pages would otherwise show a flat --bg cutoff below
     the body's content area. */
  background:
    radial-gradient(130vw 130vh at 0% 0%, rgba(124, 92, 201, 0.08), transparent 70%),
    radial-gradient(130vw 130vh at 100% 100%, rgba(71, 190, 219, 0.06), transparent 70%),
    linear-gradient(135deg, rgba(124, 92, 201, 0.03), rgba(71, 190, 219, 0.03)),
    var(--bg);
  background-attachment: fixed, fixed, fixed, fixed;
}

/* The big universal glass-card selector list — every card-shaped
   container in the app that should pick up the treatment. Sorted
   by domain so it's easy to add more later. We use a list selector
   (one rule, many comma-separated) instead of a utility class so
   no template changes are needed. Specificity stays low (single
   class) so any inline `style=""` still wins.

   Note: chat is excluded at the body level above, so no need to
   filter individual chat-page selectors here. */
.todays-focus,
.needs-attention,
.followups-card,
.announcement,
.event-card,
.empty-state,
.my-shifts-strip,
.clock-card-skeleton,
.clock-card:not([style*="linear-gradient"]),
/* Generic KPI / settings / quicklinks tiles used across many pages */
.bd-kpi,
.hub-set-card,
.quicklinks,
/* Generic dataset / card cluster wrappers */
.card,
.panel-card {
  background: var(--glass-fill);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-highlight), var(--glass-shadow);
}

/* Patch ZZCR v3 — Modals + drawers get their OWN opacity tier.
   The universal --glass-fill is 32% opaque (fine for cards that
   are background decoration) but way too see-through for modals
   where text underneath bleeds through and hurts readability.
   These rules bump fill to ~92% so modal content is legible,
   while keeping a soft glassy tint and the backdrop blur. */
.modal,
.lead-modal-shell,
.lead-modal-rail,
.lead-modal-actions {
  background: color-mix(in srgb, var(--card) 92%, transparent);
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  backdrop-filter: blur(28px) saturate(180%);
  border: 1px solid var(--glass-border);
  box-shadow: var(--glass-highlight), var(--glass-shadow);
}
:root[data-theme="dark"] .modal,
:root[data-theme="dark"] .lead-modal-shell,
:root[data-theme="dark"] .lead-modal-rail,
:root[data-theme="dark"] .lead-modal-actions {
  background: color-mix(in srgb, var(--card) 88%, transparent);
}

/* Coloured-gradient cards — keep their bold fill, inherit the
   inset highlight + deepened shadow so they live in the same
   family as the glass cards (just painted in colour instead of
   frosted). Selector matches any element with an inline linear-
   gradient background, scoped to known classes so we don't bend
   unrelated coloured cards. */
.clock-card[style*="linear-gradient"],
.face-enrol-banner[style*="linear-gradient"],
.now-block.now-skeleton {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    inset 0 -1px 0 rgba(255, 255, 255, 0.10),
    0 16px 36px rgba(90, 66, 148, 0.28),
    0 4px 10px rgba(15, 15, 26, 0.10);
}

/* Topbar — gets a thinner glass pass: smaller blur (cheap), more
   opaque fill so nav text stays crisp, plus a hairline border at
   the bottom to anchor it. This is the chrome layer, not a card,
   so we don't want full pane drama. */
.topbar {
  background: color-mix(in srgb, var(--card) 78%, transparent);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
}
:root[data-theme="dark"] .topbar {
  background: color-mix(in srgb, var(--card) 70%, transparent);
}

/* Hover lift gets a touch more spring on glass — deepen the
   shadow on cards that already have a hover translate. Listed
   explicitly so we don't accidentally crank shadows on the
   topbar / non-card surfaces. */
.announcement:hover,
.event-card:hover,
.tf-item:hover,
.hub-set-card:hover,
.bd-kpi:hover {
  box-shadow:
    var(--glass-highlight),
    0 22px 50px rgba(15, 15, 26, 0.14),
    0 5px 14px rgba(15, 15, 26, 0.08);
}

/* `tf-item` (nested inside .todays-focus) gets a lighter glass
   treatment so the inner list reads as nested-but-not-noisy.
   Same idea for any "row inside a glass card" pattern. */
.tf-item,
.followup-row {
  background: color-mix(in srgb, var(--glass-fill) 55%, transparent);
  border-color: var(--glass-border);
}

/* Browsers without backdrop-filter (older Firefox / some embedded
   webviews) fall back to a more opaque fill so cards still have
   contrast against the mesh. @supports flips alpha up. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .todays-focus,
  .needs-attention,
  .followups-card,
  .announcement,
  .event-card,
  .empty-state,
  .my-shifts-strip,
  .clock-card-skeleton,
  .clock-card:not([style*="linear-gradient"]),
  .bd-kpi,
  .hub-set-card,
  .quicklinks,
  .modal,
  .lead-modal-shell,
  .card,
  .panel-card,
  .topbar {
    background: var(--card);
  }
}

/* Reduce-motion users: keep glass + gradient (they're static),
   but trim the hover-translate so nothing zips around when they
   move the cursor over a card. */
@media (prefers-reduced-motion: reduce) {
  .announcement:hover,
  .event-card:hover,
  .hub-set-card:hover,
  .bd-kpi:hover { transform: none; }
}
