    @import url('/vendor/brand.css');

    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
    ::-webkit-scrollbar { width: 4px; height: 4px; }
    ::-webkit-scrollbar-track { background: transparent; }
    ::-webkit-scrollbar-thumb { background: var(--purple-200); border-radius: 99px; }
    * { scrollbar-width: thin; scrollbar-color: var(--purple-200) transparent; }

    /* Brand tokens (--purple-*, --orange-*, --gray-*, --brand-gradient) alias
       the canonical values shipped by @myfirstbitcoin/design v1.2.0 (see
       postinstall in package.json — copies node_modules/@myfirstbitcoin/design/
       brand.css into /vendor/brand.css, which the @import above pulls in).
       Local --l1..--l6 level accents and --b4j stay hand-defined here since
       they're CRM-specific, not brand tokens. */
    :root {
      --purple-400: var(--mfb-purple-400); --purple-300: var(--mfb-purple-300); --purple-200: var(--mfb-purple-200);
      --orange-400: var(--mfb-orange-400); --orange-300: var(--mfb-orange-300); --orange-200: var(--mfb-orange-200);
      --white: var(--mfb-white);
      --gray-100: var(--mfb-gray-100); --gray-200: var(--mfb-gray-200); --gray-300: var(--mfb-gray-300);
      --gray-400: var(--mfb-gray-400); --gray-500: var(--mfb-gray-500); --gray-600: var(--mfb-gray-600);
      --gray-700: var(--mfb-gray-700); --gray-800: var(--mfb-gray-800); --gray-900: var(--mfb-gray-900);
      --brand-gradient: var(--mfb-gradient-brand);
      --sidebar-w: 290px;
      --l1: var(--mfb-orange-400); --l2: var(--mfb-orange-300); --l3: var(--mfb-orange-200);
      --l4: var(--mfb-purple-200); --l5: var(--mfb-purple-300); --l6: var(--mfb-purple-400);
      /* B4J (Bitcoin for Juniors) — sky-blue accent, distinct from the
         ITB/BD/ETP orange-purple palette. Not an MFB brand token. */
      --b4j: #0ea5e9;
    }

    html, body { height: 100%; background: var(--gray-100); color: var(--gray-900); font-family: "IBM Plex Sans", "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Twemoji Mozilla", Arial, sans-serif; font-size: 14px; line-height: 1.5; -webkit-font-smoothing: antialiased; }

    /* Login */
    .login-screen { display: flex; align-items: center; justify-content: center; min-height: 100vh; background: var(--purple-300); position: relative; overflow: hidden; }
    .login-card { background: var(--white); border-radius: 16px; padding: 48px 44px; width: 100%; max-width: 420px; text-align: center; position: relative; z-index: 1; box-shadow: 0 24px 64px rgba(0,0,0,.28); border-top: 6px solid var(--orange-300); }
    .login-logo { display: flex; justify-content: center; margin: 0 auto 24px; }
    .login-logo img { height: 56px; width: auto; display: block; }
    .login-card h1 { font-size: 22px; font-weight: 500; color: var(--purple-300); margin-bottom: 4px; }
    .login-card .subtitle { color: var(--gray-700); font-size: 13px; margin-bottom: 32px; }
    .btn-google { display: flex; align-items: center; justify-content: center; gap: 10px; width: 100%; padding: 12px 20px; background: var(--white); color: var(--gray-900); border: 1.5px solid var(--gray-300); border-radius: 8px; font-family: "IBM Plex Sans", Arial, sans-serif; font-size: 14px; font-weight: 500; cursor: pointer; text-decoration: none; transition: border-color .15s, box-shadow .15s; }
    .btn-google:hover { border-color: var(--orange-300); box-shadow: 0 2px 12px rgba(247,148,31,.18); }
    .login-notice { margin-top: 18px; font-size: 12px; color: var(--gray-600); font-family: "IBM Plex Mono", monospace; }
    .login-notice strong { color: var(--orange-300); font-weight: 500; }
    .login-tagline { margin-top: 28px; padding-top: 20px; border-top: 1px solid var(--gray-200); font-size: 11px; color: var(--gray-500); font-style: italic; }
    .login-error { margin-top: 16px; padding: 10px 14px; background: #FEF2F2; border: 1px solid #FCA5A5; border-radius: 8px; color: #DC2626; font-size: 12px; text-align: left; }

    /* App shell */
    .app { display: flex; height: 100vh; overflow: hidden; }
    /* /admin-roles opts into page-level scroll so the long assignment
       matrix scrolls with the page instead of being trapped inside
       its own overflow container. Sidebar/topbar/table-wrap rules
       below scope themselves to this class. */
    .app.page-scroll { height: auto; min-height: 100vh; overflow: visible; align-items: flex-start; }

    /* Dev-bypass banner — shown on every page of an instance running with auth
       switched off (MFB-287). Red is a deliberate non-brand colour here, on the
       same footing as --b4j: MFB purple and orange both read as decoration, and
       this has to read as a warning. Solid fill, not translucent, and sentence
       case, per the brand rules. White on #B91C1C measures 6.47:1, which is AA
       for body text and AAA at this size, in both themes. */
    .dev-bypass-banner { flex-shrink: 0; background: #B91C1C; color: var(--white); padding: 10px 20px; font-size: 13px; line-height: 1.5; }
    .dev-bypass-banner strong { font-weight: 600; }

    /* Sidebar */
    .sidebar { width: var(--sidebar-w); flex-shrink: 0; background: var(--purple-300); display: flex; flex-direction: column; height: 100vh; overflow-y: auto; border-top: 6px solid var(--orange-300); transition: width .18s ease; }
    .app.page-scroll .sidebar { position: sticky; top: 0; align-self: flex-start; }
    .sidebar-header { padding: 18px 16px 16px; border-bottom: 1px solid rgba(255,255,255,.1); flex-shrink: 0; }
    .sidebar-brand { display: flex; align-items: center; gap: 10px; }
    .brand-icon { width: 32px; height: 32px; background: rgba(247,148,31,.2); border-radius: 6px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
    .brand-icon span { color: var(--orange-300); font-size: 16px; font-weight: 600; }
    .brand-text { flex: 1; min-width: 0; }
    .brand-text strong { display: block; font-size: 13px; font-weight: 500; color: var(--white); }
    .brand-text small { font-size: 10px; color: rgba(255,255,255,.5); font-family: "IBM Plex Mono", monospace; letter-spacing: .04em; }
    .sidebar-collapse-btn { background: none; border: none; color: rgba(255,255,255,.45); cursor: pointer; padding: 4px; border-radius: 4px; transition: color .12s, background .12s; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
    .sidebar-collapse-btn:hover { color: var(--white); background: rgba(255,255,255,.08); }
    .sidebar-collapse-btn svg { width: 14px; height: 14px; transition: transform .18s ease; }

    /* Collapsed (icon-only) mode */
    .sidebar.collapsed { width: 60px; }
    .sidebar.collapsed .sidebar-header { padding: 12px 8px; }
    .sidebar.collapsed .sidebar-brand { justify-content: center; gap: 0; }
    .sidebar.collapsed .brand-icon { display: none; }
    .sidebar.collapsed .brand-text { display: none; }
    .sidebar.collapsed .sidebar-collapse-btn { width: 36px; height: 36px; background: rgba(247,148,31,.18); color: var(--orange-300); border-radius: 8px; padding: 0; }
    .sidebar.collapsed .sidebar-collapse-btn:hover { background: rgba(247,148,31,.32); color: var(--white); }
    .sidebar.collapsed .sidebar-collapse-btn svg { width: 18px; height: 18px; transform: rotate(180deg); }
    .sidebar.collapsed .nav-section { display: none; }
    .sidebar.collapsed .nav-sub-items { display: none !important; }
    .sidebar.collapsed .nav-item,
    .sidebar.collapsed .nav-group-header { justify-content: center; gap: 0; padding: 10px 0; position: relative; }
    .sidebar.collapsed .nav-label,
    .sidebar.collapsed .nav-level-label { display: none; }
    .sidebar.collapsed .chevron { display: none; }
    .sidebar.collapsed .nav-dot { width: 10px; height: 10px; }
    .sidebar.collapsed .sidebar-nav { padding: 8px 6px; }
    .sidebar.collapsed .sidebar-user { padding: 12px 8px; }
    .sidebar.collapsed .user-row { justify-content: center; gap: 0; }
    .sidebar.collapsed .user-info,
    .sidebar.collapsed .btn-logout { display: none; }
    .sidebar.collapsed .nav-pulse { display: none; }
    .sidebar-nav { padding: 10px 8px; flex: 1; }
    .nav-section { font-size: 10px; font-weight: 500; letter-spacing: .1em; color: rgba(255,255,255,.4); padding: 12px 10px 4px; font-family: "IBM Plex Mono", monospace; }
    .nav-item { display: flex; align-items: center; gap: 9px; padding: 8px 10px; border-radius: 6px; cursor: pointer; color: rgba(255,255,255,.65); font-size: 13px; font-weight: 400; transition: background .12s, color .12s; user-select: none; margin-bottom: 1px; }
    .nav-item:hover  { background: rgba(255,255,255,.08); color: var(--white); }
    .nav-item.active { background: rgba(247,148,31,.15); color: var(--orange-300); font-weight: 500; }
    .nav-group-header { display: flex; align-items: center; gap: 9px; padding: 8px 10px; border-radius: 6px; cursor: pointer; color: rgba(255,255,255,.65); font-size: 13px; font-weight: 400; transition: background .12s, color .12s; user-select: none; margin-bottom: 1px; }
    .nav-group-header:hover { background: rgba(255,255,255,.08); color: var(--white); }
    .nav-group-header.has-active { color: var(--orange-300); }
    .nav-group-header .chevron { margin-left: auto; width: 13px; height: 13px; transition: transform .2s; opacity: .5; }
    .nav-group-header.open .chevron { transform: rotate(90deg); }
    .nav-sub-items { overflow: hidden; max-height: 0; transition: max-height .22s cubic-bezier(.4,0,.2,1); }
    .nav-sub-items.open { max-height: 300px; }
    .nav-sub-item { display: flex; align-items: center; gap: 8px; padding: 6px 10px 6px 30px; border-radius: 6px; cursor: pointer; color: rgba(255,255,255,.55); font-size: 12px; transition: background .12s, color .12s; user-select: none; margin-bottom: 1px; }
    .nav-sub-item:hover  { background: rgba(255,255,255,.08); color: var(--white); }
    .nav-sub-item.active { color: var(--orange-300); }
    .sidebar-user { padding: 12px 16px; border-top: 1px solid rgba(255,255,255,.1); flex-shrink: 0; }
    .user-row { display: flex; align-items: center; gap: 10px; }
    .user-avatar { width: 32px; height: 32px; border-radius: 50%; background: rgba(247,148,31,.25); display: flex; align-items: center; justify-content: center; flex-shrink: 0; overflow: hidden; }
    .user-avatar img { width: 100%; height: 100%; object-fit: cover; }
    .user-avatar span { font-size: 13px; font-weight: 600; color: var(--orange-300); }
    .user-info { flex: 1; min-width: 0; }
    .user-name { font-size: 12px; font-weight: 500; color: var(--white); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .user-role { font-size: 10px; color: rgba(255,255,255,.5); font-family: "IBM Plex Mono", monospace; letter-spacing: .04em; }
    .btn-logout { background: none; border: none; cursor: pointer; color: rgba(255,255,255,.4); padding: 4px; border-radius: 4px; transition: color .12s; }
    .btn-logout:hover { color: var(--white); }

    /* Main content */
    .main { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
    .app.page-scroll .main { min-width: 0; overflow: visible; }
    .content { flex: 1; overflow-y: auto; padding: 28px 32px; }
    .app.page-scroll .content { overflow-y: visible; }

    /* Page header */
    .page-header { margin-bottom: 24px; }
    .page-header h2 { font-size: 22px; font-weight: 500; color: var(--purple-300); letter-spacing: -.01em; }
    .page-header p  { color: var(--gray-600); font-size: 13px; margin-top: 4px; }

    /* Stat cards (v1 structure: .stat-label, .stat-value, .stat-sub, .stat-dot) */
    .stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; margin-bottom: 28px; }
    /* Person profile two-column layout: main + Comments side panel. */
    .person-profile-grid { display: grid; grid-template-columns: 1fr 320px; gap: 24px; align-items: start; }
    @media (max-width: 1024px) { .person-profile-grid { grid-template-columns: 1fr; } }
    /* Person profile layout: main column (stat row + history) on the left,
       right rail (Actions / Reminders / Notes) aligned with the top of
       the stat row. Single grid so the right rail visually starts at the
       same y as Email/Country/Community. */
    .person-layout-grid { display: grid; grid-template-columns: 2fr 1fr; gap: 24px; align-items: start; }
    @media (max-width: 1024px) { .person-layout-grid { grid-template-columns: 1fr; } }
    /* Top-row stat cards — 3-up (Email / Contact Details / Community). Country
       lives in the flag next to the name. */
    .person-stat-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; margin-bottom: 24px; }
    @media (max-width: 820px) { .person-stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
    @media (max-width: 520px) { .person-stat-grid { grid-template-columns: 1fr; } }
    /* Contact Details card — when only one channel is populated the value is
       shown inline; with two or more, the card shows the channel names and
       reveals the per-channel rows on hover. The popup is a self-contained
       rounded panel that floats below the card (offset gap + full radius). */
    .contact-card { position: relative; }
    .contact-card .contact-popup {
      position: absolute; left: 0; right: 0; top: calc(100% + 6px);
      background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 10px;
      padding: 10px 14px;
      box-shadow: 0 8px 20px rgba(0,0,0,0.10);
      opacity: 0; pointer-events: none; transform: translateY(-4px);
      transition: opacity 120ms ease, transform 120ms ease;
      z-index: 5;
    }
    .contact-card:hover .contact-popup,
    .contact-card:focus-within .contact-popup { opacity: 1; pointer-events: auto; transform: translateY(0); }
    .contact-row { display: flex; align-items: center; gap: 10px; padding: 6px 0; font-size: 13px; font-family: 'IBM Plex Mono', monospace; }
    .contact-row + .contact-row { border-top: 1px solid var(--gray-200); }
    .contact-row .contact-label { font-family: inherit; font-size: 11px; color: var(--gray-500); width: 60px; flex-shrink: 0; }
    .contact-row a { color: inherit; text-decoration: none; word-break: break-all; }
    .contact-row .contact-empty { color: var(--gray-400); font-style: italic; }
    .contact-names { font-size: 13px; line-height: 1.2; color: var(--gray-700); text-transform: lowercase; }
    .contact-names .contact-sep { color: var(--gray-400); margin: 0 4px; }
    /* Right-rail panels on the Person profile (Actions + Notes). Replaces
       the old comments-coming-soon placeholder. Sticky so the panels stay
       in view while the user scrolls through cohort/level history. */
    .person-side-panel { display: flex; flex-direction: column; gap: 14px; position: sticky; top: 18px; align-self: start; }
    .person-side-box   { background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 10px; padding: 16px 18px; }
    .person-side-head  { font-size: 14px; font-weight: 600; color: var(--purple-300); margin-bottom: 12px; display: flex; align-items: center; gap: 8px; }
    .person-side-empty { font-size: 12px; color: var(--gray-500); padding: 12px; background: var(--gray-100); border-radius: 6px; text-align: center; }
    .person-side-err   { font-size: 12px; color: #b91c1c; padding: 6px 10px; background: #fef2f2; border: 1px solid #fecaca; border-radius: 6px; margin-top: 6px; }
    .person-side-status { font-size: 11px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; }
    .person-side-btn   { padding: 7px 14px; background: var(--purple-300); color: var(--white); border: 0; border-radius: 6px; font-size: 13px; font-weight: 500; cursor: pointer; transition: background .12s, opacity .12s; }
    .person-side-btn:hover:not(:disabled) { background: var(--purple-200); }
    .person-side-btn:disabled { opacity: 0.5; cursor: not-allowed; }
    .person-action-form { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; padding-bottom: 12px; border-bottom: 1px solid var(--gray-200); }
    .person-action-select { padding: 7px 10px; border: 1.5px solid var(--gray-300); border-radius: 6px; font-size: 13px; font-family: inherit; background: var(--white); color: var(--gray-900); cursor: pointer; }
    .person-action-note   { width: 100%; padding: 7px 10px; border: 1.5px solid var(--gray-300); border-radius: 6px; font-size: 13px; font-family: inherit; resize: vertical; background: var(--white); box-sizing: border-box; }
    .person-action-list   { display: flex; flex-direction: column; gap: 8px; }
    .person-action-row    { padding: 8px 10px; background: var(--gray-100); border-radius: 6px; border-left: 3px solid var(--purple-300); }
    .person-action-row-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
    .person-action-tag    { font-size: 10px; font-weight: 600; color: var(--purple-300); text-transform: uppercase; letter-spacing: .04em; }
    .person-action-time   { font-size: 10px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; white-space: nowrap; margin-left: auto; }
    .person-action-row-note { font-size: 12px; color: var(--gray-700); margin-top: 4px; line-height: 1.4; white-space: pre-wrap; word-wrap: break-word; }
    /* Share icon on an Action Log card. Always rendered (not hover-only:
       touch devices have no hover), but quiet enough to stay out of the way
       of the note. 24px box keeps it tappable without breaking the dense
       list rhythm. */
    .action-share-btn { flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin: -4px -4px -4px 0; padding: 0; border: 0; border-radius: 5px; background: transparent; color: var(--gray-400); cursor: pointer; transition: color .12s, background .12s; }
    .action-share-btn:hover  { color: var(--purple-300); background: var(--gray-200); }
    .action-share-btn:focus-visible { outline: 2px solid var(--purple-300); outline-offset: 1px; }
    .action-share-btn.copied { color: #16a34a; }
    /* @mention + #hashtag inside person/cohort notes — matches action-item
       note styling: purple, bold, underlined. Hashtag remains a button so
       it stays clickable, but is visually identical to the mention text. */
    .note-mention { color: var(--purple-300); font-weight: 700; text-decoration: underline; }
    .note-url { color: var(--orange-400); text-decoration: underline; word-break: break-word; }
    .note-url:hover { filter: brightness(.85); }
    .note-url::after { content: "↗"; font-size: .85em; margin-left: 2px; opacity: .7; }
    /* MentionTextarea toolbar — sits above the textarea, hosts the Insert
       Link button + the inline label/URL panel that expands when clicked. */
    .mta-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 6px; }
    .mta-tool-btn { display: inline-flex; align-items: center; gap: 4px; padding: 3px 8px; background: var(--white); border: 1px solid var(--gray-300); border-radius: 6px; font: inherit; font-size: 11px; color: var(--gray-700); cursor: pointer; transition: border-color .12s, color .12s; }
    .mta-tool-btn:hover:not(:disabled) { border-color: var(--orange-400); color: var(--orange-400); }
    .mta-tool-btn:disabled { opacity: .5; cursor: not-allowed; }
    .mta-tool-btn-icon { min-width: 26px; height: 24px; padding: 0 6px; justify-content: center; }
    .mta-link-panel { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; padding: 4px 6px; background: var(--gray-100); border: 1px solid var(--gray-300); border-radius: 6px; flex: 1; min-width: 0; }
    .mta-link-input { flex: 1; min-width: 80px; padding: 3px 6px; border: 1px solid var(--gray-300); border-radius: 4px; font-size: 12px; font-family: inherit; background: var(--white); color: var(--gray-900); }
    .mta-link-input:focus { outline: none; border-color: var(--orange-400); }
    .mta-link-btn { padding: 3px 10px; border: 0; border-radius: 4px; font: inherit; font-size: 11px; font-weight: 600; cursor: pointer; background: var(--orange-400); color: var(--white); }
    .mta-link-btn:disabled { opacity: .5; cursor: not-allowed; }
    .mta-link-btn.ghost { background: transparent; color: var(--gray-600); border: 1px solid var(--gray-300); }
    .mta-link-btn.ghost:hover { border-color: var(--gray-500); color: var(--gray-800); }
    .note-hashtag { color: var(--purple-300); font-weight: 700; text-decoration: underline; background: none; border: 0; padding: 0; margin: 0; font: inherit; cursor: pointer; }
    .note-hashtag:hover { text-decoration-thickness: 2px; }
    .person-notes-input { width: 100%; padding: 12px 14px; border: 1.5px solid var(--gray-300); border-left: 3px solid var(--orange-300); border-radius: 6px; font-size: 13px; font-family: inherit; resize: vertical; background: var(--white); color: var(--gray-900); margin-bottom: 10px; box-sizing: border-box; min-height: 110px; line-height: 1.5; }
    .person-notes-input:focus { border-color: var(--purple-300); border-left-color: var(--orange-300); outline: none; box-shadow: 0 0 0 3px rgba(66,44,112,.08); }
    .person-notes-display { padding: 12px 14px; background: var(--gray-100); border-left: 3px solid var(--orange-300); border-radius: 6px; min-height: 64px; margin-bottom: 10px; }
    .person-notes-text { font-size: 13px; color: var(--gray-900); line-height: 1.55; white-space: pre-wrap; word-wrap: break-word; }
    .person-notes-foot { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
    .person-side-btn-ghost { background: transparent; color: var(--gray-700); border: 1.5px solid var(--gray-300); }
    .person-side-btn-ghost:hover:not(:disabled) { background: var(--gray-100); }
    /* Side-panel quicklink rows — icon + label + sublabel + chevron. Used
       by Cohort Quicklinks; tuned to feel like a list item, not a button. */
    .cohort-quicklink-row { display: flex; align-items: center; gap: 12px; padding: 10px 12px; background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 8px; cursor: pointer; font-family: inherit; transition: border-color .12s, background .12s, transform .08s; width: 100%; }
    .cohort-quicklink-row:hover { border-color: var(--purple-300); background: rgba(66,44,112,.04); }
    .cohort-quicklink-row:active { transform: translateY(1px); }
    .cohort-quicklink-row:focus-visible { outline: 2px solid var(--orange-300); outline-offset: 2px; }
    /* Certify-cohort student table — the sticky "Apply to all" bar
       sometimes had rows bleeding through (visible above the bar) on
       scroll. The wrapper is the local stacking context; the table
       explicitly sits below the sticky on the z-axis; the sticky bar
       gets a fully opaque background-clip that masks the rows. */
    /* No `overflow:hidden` on the wrap — it would make this div the scroll
       container, which breaks the sticky bar stickiness to the modal body.
       The wrap is the local stacking context (z-index:0 reset on the table
       keeps rows under the sticky bar's z-index:50). */
    .cert-students-wrap { border: 1px solid var(--gray-200); border-radius: 6px; background: var(--white); }
    .cert-students-sticky { display: flex; justify-content: flex-end; align-items: center; padding: 10px 12px; background: #F3F3FA; border-bottom: 1.5px solid var(--gray-300); border-radius: 5px 5px 0 0; }
    .stat-card { position: relative; background: var(--white); border: 1.5px solid var(--gray-300); border-top: 3px solid var(--gray-300); border-radius: 10px; padding: 18px 20px; transition: border-color .15s, box-shadow .15s; }
    .stat-card:hover { border-color: var(--gray-400); border-top-color: var(--orange-300); box-shadow: 0 2px 12px rgba(0,0,0,.06); }
    /* Pure-stat cards (Network → Communities) — hover lift implied
       interactivity that isn't actually there; suppress on .stat-grid--static. */
    .stat-grid--static .stat-card:hover { border-color: var(--gray-300); border-top-color: var(--gray-300); box-shadow: none; }
    /* Hover popup explaining what's included / excluded in a card's count.
       Positioned just below the card; pointer-events:none so it never
       intercepts clicks. Shown when the card has the .has-info class and
       is hovered. */
    .stat-card-info {
      position: absolute; top: 100%; left: 0; right: 0; margin-top: 6px;
      background: rgba(31,31,46,.96); color: #fff;
      border-radius: 6px; padding: 10px 12px;
      font-size: 12px; line-height: 1.45; font-weight: 400;
      letter-spacing: .01em;
      box-shadow: 0 6px 20px rgba(0,0,0,.18);
      opacity: 0; pointer-events: none; transform: translateY(-4px);
      transition: opacity .12s ease, transform .12s ease;
      z-index: 1001;
    }
    .stat-card-info b { color: var(--orange-300); font-weight: 600; }
    .stat-card-info-row { margin-top: 6px; }
    /* When the info tooltip drops down over a sibling Leaflet map (panes go
       up to z-index 700), the hovered card has to outrank those panes for
       its tooltip to render on top. Lifts only on hover so resting cards
       don't form unnecessary stacking contexts. */
    .stat-card.has-info:hover { z-index: 1001; }
    .stat-card.has-info:hover .stat-card-info { opacity: 1; transform: translateY(0); }
    .stat-card.accent { border-top-color: var(--orange-300); }
    .stat-label { font-size: 11px; font-weight: 500; color: var(--gray-600); letter-spacing: .07em; font-family: "IBM Plex Mono", monospace; margin-bottom: 10px; display: flex; align-items: center; gap: 6px; }
    .stat-dot   { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
    .stat-value { font-size: 28px; font-weight: 500; letter-spacing: -.02em; line-height: 1; color: var(--purple-300); }
    .stat-value.loading { background: linear-gradient(90deg, var(--gray-200) 25%, var(--gray-300) 50%, var(--gray-200) 75%); background-size: 200% 100%; animation: shimmer 1.5s infinite; border-radius: 6px; color: transparent; width: 80px; height: 28px; }
    @keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
    .stat-sub   { margin-top: 4px; font-size: 11px; color: var(--gray-600); }

    /* Legacy stat-card children (val/lbl/delta) — kept for any unrenamed callers */
    .stat-card .val { font-size: 28px; font-weight: 600; color: var(--purple-300); line-height: 1; font-variant-numeric: tabular-nums; }
    .stat-card .lbl { font-size: 11px; color: var(--gray-600); letter-spacing: .08em; margin-top: 5px; }
    .stat-card .delta { font-size: 11px; color: var(--gray-500); margin-top: 3px; font-family: "IBM Plex Mono", monospace; }

    /* Section title */
    .section-title { display: flex; align-items: center; gap: 10px; font-size: 11px; font-weight: 500; color: var(--gray-600); letter-spacing: .09em; font-family: "IBM Plex Mono", monospace; margin-bottom: 12px; }
    .section-title::after { content: ""; flex: 1; height: 1px; background: var(--gray-300); }

    /* Overview hero (Team Dashboard / Network Dashboard top banner) */
    .overview-hero { background: var(--brand-gradient); border-radius: 12px; padding: 28px 32px; margin-bottom: 24px; position: relative; overflow: hidden; color: var(--white); }
    .overview-hero-inner { position: relative; z-index: 1; }
    .overview-hero h3 { font-size: 13px; font-weight: 500; color: rgba(255,255,255,.7); letter-spacing: .1em; font-family: "IBM Plex Mono", monospace; margin-bottom: 6px; }
    .overview-hero-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0; margin-top: 18px; }
    .hero-col       { padding: 0 24px 0 0; }
    .hero-col + .hero-col { padding-left: 24px; border-left: 1px solid rgba(255,255,255,.15); }
    .hero-stat      { font-size: 48px; font-weight: 500; line-height: 1; letter-spacing: -.02em; margin-bottom: 4px; }
    .hero-stat.loading { width: 140px; height: 48px; background: rgba(255,255,255,.1); border-radius: 6px; animation: pulse 1.5s ease-in-out infinite; }
    .hero-stat-green { color: #4ade80; }
    .hero-stat-arrow { font-size: 22px; font-weight: 700; line-height: 1; vertical-align: middle; margin-right: 4px; }
    .hero-col-label { font-size: 11px; color: rgba(255,255,255,.55); letter-spacing: .08em; font-family: "IBM Plex Mono", monospace; margin-top: 4px; }

    /* My Dashboard hero */
    .my-db-hero { background: linear-gradient(135deg, var(--purple-400) 0%, var(--purple-200) 100%); border-radius: 12px; padding: 32px 36px; margin-bottom: 28px; position: relative; overflow: hidden; }
    /* Subtle depth accent on the right — kept as a soft white glow so
       the hero reads as full-purple. Prior version used --orange-300
       which bled a visible orange wash into the corner. */
    /* Slant comes from the brand package, never a literal. Was a hand-typed
       -10deg; canon is a MAGNITUDE of 13deg (--sg-angle-base in
       /vendor/brand.css, generated from tokens.json and imported at the top of
       this file). The sign stays negative because this is a parent-style skew
       on a decorative box: -13deg is correct, and the thing to be suspicious of
       is any magnitude that is not 13. Visually this is a near no-op, a 280px
       corner glow at 6% white that is mostly clipped, which is exactly why it
       is safe to converge. (Quentin, 2026-08-20.) */
    .my-db-hero::after { content: ""; position: absolute; bottom: -60px; right: -60px; width: 280px; height: 280px; background: rgba(255,255,255,.06); transform: skewX(calc(-1 * var(--sg-angle-base))); }
    .my-db-hero-inner { position: relative; z-index: 1; }
    .my-db-welcome { font-size: 26px; font-weight: 500; color: var(--white); letter-spacing: -.01em; margin-bottom: 6px; }
    .my-db-role-badge { display: inline-block; font-size: 10px; font-weight: 600; padding: 3px 10px; border-radius: 99px; letter-spacing: .07em; font-family: "IBM Plex Mono", monospace; }
    .my-db-desc { color: rgba(255,255,255,.78); font-size: 14px; margin-top: 12px; line-height: 1.55; max-width: 720px; }
    .resp-highlight { color: var(--orange-200); font-weight: 600; }
    .resp-highlight.resp-count { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }

    /* My Responsibilities (cards) — 3-col grid on desktop, 1-col on mobile.
       Compact chip proportions matching the CRM's info-dense card language,
       with the stat-card 3px top rule that flips orange on hover. */
    .my-roles-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-bottom: 28px; align-items: stretch; }
    .my-role-card { display: flex; align-items: center; gap: 10px; background: var(--white); border: 1.5px solid var(--gray-300); border-top: 3px solid var(--gray-300); border-radius: 10px; padding: 18px 12px; cursor: pointer; transition: border-color .15s, box-shadow .15s; width: 100%; min-width: 0; min-height: 72px; }
    .my-role-card:hover { border-color: var(--gray-400); border-top-color: var(--orange-300); box-shadow: 0 2px 8px rgba(0,0,0,.06); }
    .my-role-badge { width: 32px; height: 32px; border-radius: 8px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; }
    .my-role-info  { flex: 1; min-width: 0; }
    .my-role-sub   { font-size: 12px; font-weight: 600; color: var(--gray-900); line-height: 1.3; }
    .my-role-level { font-size: 10.5px; color: var(--gray-600); margin-top: 1px; }
    .my-role-desc  { font-size: 10.5px; color: var(--gray-500); margin-top: 3px; font-style: italic; line-height: 1.4; }
    .my-role-count { font-size: 17px; font-weight: 600; color: var(--purple-300); flex-shrink: 0; letter-spacing: -.01em; font-variant-numeric: tabular-nums; }
    @media (max-width: 900px) { .my-roles-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
    @media (max-width: 768px) { .my-roles-grid { grid-template-columns: 1fr; } }
    .quick-links-row { display: flex; flex-wrap: wrap; gap: 6px; }
    .quick-link-card { display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px; background: var(--gray-100); border: 1px solid var(--gray-300); border-radius: 6px; font-size: 11px; color: var(--purple-300); text-decoration: none; transition: background .12s, border-color .12s; }
    .quick-link-card:hover { background: rgba(247,148,31,.1); border-color: var(--orange-300); }

    /* Level cards (Team Dashboard breakdown) */
    .level-grid { display: flex; align-items: stretch; gap: 25px; margin-bottom: 28px; flex-wrap: wrap; max-width: 90%; }
    .level-grid .level-card { flex: 1 1 65px; }
    .level-arrow { display: flex; align-items: center; padding: 0 4px; color: var(--gray-400); font-size: 16px; flex-shrink: 0; align-self: center; }
    @media (max-width: 900px) { .level-arrow { display: none; } .level-grid .level-card { flex: 1 1 28%; } }
    .level-card { background: var(--white); border: 1.5px solid var(--gray-300); border-top: 3px solid var(--gray-400); border-radius: 10px; padding: 14px 7px; text-align: center; cursor: default; }
    .level-card[data-level="1"] { border-top-color: var(--l1); }
    .level-card[data-level="2"] { border-top-color: var(--l2); }
    .level-card[data-level="3"] { border-top-color: var(--l3); }
    .level-card[data-level="4"] { border-top-color: var(--l4); }
    .level-card[data-level="5"] { border-top-color: var(--l5); }
    .level-card[data-level="6"] { border-top-color: var(--l6); }
    .level-num { font-size: 10px; font-weight: 500; letter-spacing: .1em; margin-bottom: 2px; font-family: "IBM Plex Mono", monospace; white-space: nowrap; color: var(--purple-300); }
    .level-card[data-level="4"] .level-num { color: var(--l4); }
    .level-card[data-level="5"] .level-num { color: var(--l5); }
    .level-card[data-level="6"] .level-num { color: var(--l6); }
    .level-subtitle { font-size: 10px; color: var(--gray-600); margin-bottom: 8px; font-family: "IBM Plex Mono", monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; letter-spacing: .04em; }
    .level-count { font-size: 26px; font-weight: 500; color: var(--purple-300); letter-spacing: -.02em; line-height: 1; }
    .level-sub { font-size: 11px; color: var(--gray-600); margin-top: 4px; }
    .level-week { font-size: 10px; margin-top: 3px; font-family: "IBM Plex Mono", monospace; letter-spacing: .02em; }
    .level-week.flat { color: var(--gray-500); }
    .level-week-num.pos { color: #166534; font-weight: 700; }

    /* Distribution bars (Level Distribution chart) */
    .bar-section { background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 10px; padding: 20px 24px; margin-bottom: 28px; }
    .bar-row { display: flex; align-items: center; gap: 14px; margin-bottom: 12px; }
    .bar-row:last-child { margin-bottom: 0; }
    .bar-label { font-size: 11px; color: var(--gray-700); width: 210px; flex-shrink: 0; text-align: right; font-family: "IBM Plex Mono", monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .bar-track { flex: 1; height: 8px; background: var(--gray-200); border-radius: 99px; overflow: hidden; }
    .bar-fill  { height: 100%; border-radius: 99px; transition: width .7s cubic-bezier(.4,0,.2,1); }
    .bar-count { font-size: 12px; color: var(--gray-700); width: 40px; flex-shrink: 0; font-family: "IBM Plex Mono", monospace; }

    /* NocoDB-not-configured notice */
    .config-notice { background: var(--white); border: 1.5px dashed var(--gray-300); border-left: 4px solid var(--orange-300); border-radius: 8px; padding: 14px 18px; display: flex; align-items: flex-start; gap: 12px; margin-bottom: 22px; font-size: 13px; color: var(--gray-700); }
    .config-notice strong { color: var(--orange-400); }
    .config-notice code   { font-family: "IBM Plex Mono", monospace; font-size: 11px; background: var(--gray-100); padding: 1px 6px; border-radius: 4px; color: var(--purple-300); border: 1px solid var(--gray-300); }

    /* Leaderboard pods + table */
    .lb-pods { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; margin-bottom: 28px; }
    @media (max-width: 900px) { .lb-pods { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
    @media (max-width: 600px) { .lb-pods { grid-template-columns: 1fr; } }
    .lb-pod  { background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 10px; overflow: hidden; }
    .lb-pod-header { padding: 10px 14px 8px; border-bottom: 1px solid var(--gray-100); }
    .lb-pod-title  { font-size: 11px; font-weight: 700; letter-spacing: .07em; color: var(--gray-700); }
    .lb-pod-sub    { font-size: 10px; color: var(--gray-400); margin-top: 1px; }
    .lb-pod table  { width: 100%; border-collapse: collapse; }
    .lb-pod td     { padding: 7px 14px; border-bottom: 1px solid var(--gray-100); font-size: 12px; vertical-align: middle; }
    .lb-pod tr:last-child td { border-bottom: none; }
    .lb-pod-rank   { width: 20px; font-weight: 700; font-size: 11px; color: var(--gray-400); }
    .lb-pod-rank.gold   { color: #b8860b; }
    .lb-pod-rank.silver { color: #708090; }
    .lb-pod-rank.bronze { color: #8b4513; }
    .lb-pod-name   { color: var(--gray-800); font-weight: 500; }
    .lb-pod-val    { text-align: right; font-weight: 700; font-family: "IBM Plex Mono", monospace; color: var(--purple-400); white-space: nowrap; }
    .lb-table { width: 100%; border-collapse: collapse; font-size: 13px; }
    .lb-table thead th { font-size: 11px; font-weight: 600; letter-spacing: .06em; color: var(--gray-500); padding: 0 8px 8px; border-bottom: 1px solid var(--gray-200); text-align: left; }
    .lb-table thead th.r { text-align: right; }
    .lb-table tbody tr:hover td { background: var(--gray-100); }
    .lb-table tbody td { padding: 10px 8px; border-bottom: 1px solid var(--gray-100); vertical-align: middle; }
    .lb-table tbody tr:last-child td { border-bottom: none; }
    .lb-pos        { font-size: 12px; font-weight: 700; color: var(--gray-400); width: 28px; }
    .lb-pos.gold   { color: #b8860b; }
    .lb-pos.silver { color: #708090; }
    .lb-pos.bronze { color: #8b4513; }
    .lb-name-btn   { background: none; border: none; padding: 0; cursor: pointer; font-size: 13px; font-weight: 600; color: var(--purple-300); font-family: inherit; text-align: left; text-decoration: underline; text-decoration-color: var(--purple-300); text-underline-offset: 2px; }
    .lb-name-btn:hover { color: var(--orange-400); text-decoration-color: var(--orange-400); }
    .lb-sub-chip   { display: inline-block; padding: 2px 7px; border-radius: 4px; font-size: 10px; font-weight: 500; margin: 0 3px 3px 0; }
    .lb-people     { text-align: right; font-family: "IBM Plex Mono", monospace; font-weight: 700; color: var(--purple-400); }
    .lb-streak     { text-align: right; color: var(--gray-400); font-family: "IBM Plex Mono", monospace; }
    .tc-name-btn   { background: none; border: none; padding: 0; cursor: pointer; font-size: 10px; font-weight: 700; color: var(--purple-300); font-family: inherit; text-align: left; text-decoration: none; }
    .tc-name-btn:hover { color: var(--orange-400); text-decoration: underline; text-underline-offset: 2px; }

    /* Member profile */
    .profile-back { display: inline-flex; align-items: center; gap: 6px; background: none; border: none; cursor: pointer; font-size: 12px; color: var(--gray-500); font-family: inherit; padding: 0; margin-bottom: 18px; transition: color .12s; }
    .profile-back:hover { color: var(--purple-300); }
    .profile-hero { background: linear-gradient(135deg, var(--purple-400) 0%, var(--purple-300) 100%); border-radius: 10px; padding: 28px 32px; margin-bottom: 24px; color: #fff; display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
    .profile-avatar { width: 56px; height: 56px; border-radius: 50%; background: rgba(255,255,255,.15); display: flex; align-items: center; justify-content: center; font-size: 24px; font-weight: 700; color: #fff; flex-shrink: 0; border: 2px solid rgba(255,255,255,.3); }
    .profile-hero-info { flex: 1; min-width: 160px; }
    .profile-hero-name { font-size: 22px; font-weight: 700; letter-spacing: -.01em; }
    .profile-role-badge { display: inline-block; font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 4px; letter-spacing: .06em; margin-top: 8px; }
    .profile-stats     { display: flex; gap: 28px; margin-left: auto; }
    .profile-stat-col  { text-align: center; }
    .profile-stat-val  { font-size: 28px; font-weight: 700; font-family: "IBM Plex Mono", monospace; }
    .profile-stat-lbl  { font-size: 10px; color: rgba(255,255,255,.6); letter-spacing: .07em; margin-top: 3px; }
    .profile-streak-box  { display: flex; align-items: flex-start; gap: 16px; background: var(--gray-100); border-radius: 10px; padding: 18px 22px; margin-bottom: 24px; }
    .profile-streak-icon { font-size: 30px; line-height: 1; flex-shrink: 0; }
    .profile-streak-val  { font-size: 18px; font-weight: 700; color: var(--gray-700); }
    .profile-streak-lbl  { font-size: 12px; color: var(--gray-500); margin-top: 2px; }
    .profile-streak-note { font-size: 11px; color: var(--gray-400); font-style: italic; margin-top: 5px; }
    .profile-sub-grid { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 28px; }
    .profile-sub-card { flex: 1; min-width: 130px; max-width: 180px; border-radius: 8px; padding: 14px 16px; cursor: pointer; transition: box-shadow .15s, transform .1s; border: 1.5px solid transparent; background: var(--white); }
    .profile-sub-card:hover { box-shadow: 0 4px 14px rgba(0,0,0,.1); transform: translateY(-2px); }
    .profile-sub-level-badge { font-size: 9px; font-weight: 700; letter-spacing: .07em; opacity: .75; margin-bottom: 3px; }
    .profile-sub-label { font-size: 11px; font-weight: 600; }
    .profile-sub-count { font-size: 28px; font-weight: 700; font-family: "IBM Plex Mono", monospace; margin-top: 8px; line-height: 1; }
    .profile-sub-people { font-size: 10px; opacity: .5; margin-top: 3px; }

    /* Network Dashboard period bar + tables */
    .chart-filter-btn { padding: 5px 13px; background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 99px; font-family: "IBM Plex Mono", monospace; font-size: 11px; font-weight: 500; color: var(--gray-600); cursor: pointer; transition: background .12s, border-color .12s, color .12s; }
    .chart-filter-btn:hover  { background: var(--gray-100); color: var(--gray-800); }
    .chart-filter-btn.active { background: var(--purple-300); border-color: var(--purple-300); color: #fff; }
    .chart-filter-btn.mode-toggle.active { background: var(--orange-300); border-color: var(--orange-300); color: #fff; }
    .chart-filter-btn.compact { padding: 3px 10px; font-size: 10px; }
    .network-tables-row    { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin-bottom: 28px; }
    .network-table-section { }
    .network-table-title   { font-size: 12px; font-weight: 600; color: var(--gray-700); margin-bottom: 10px; display: flex; align-items: center; gap: 8px; }
    .nt-badge { display: inline-block; padding: 2px 7px; background: var(--purple-300); color: #fff; font-size: 9px; font-weight: 700; letter-spacing: .04em; border-radius: 3px; font-family: "IBM Plex Mono", monospace; }

    /* Loading text used inside async sections */
    .events-loading { padding: 32px; text-align: center; color: var(--gray-500); font-size: 13px; }

    /* Level page header */
    .level-header { background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 10px; padding: 24px 28px; margin-bottom: 24px; display: flex; align-items: center; gap: 18px; position: relative; overflow: hidden; border-top-width: 3px; }
    .level-badge  { width: 52px; height: 52px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 22px; font-weight: 500; flex-shrink: 0; font-family: "IBM Plex Sans", Arial, sans-serif; }
    .level-header-info h2 { font-size: 20px; font-weight: 500; color: var(--purple-300); letter-spacing: -.01em; }
    .level-header-info p  { color: var(--gray-600); font-size: 13px; margin-top: 3px; }

    /* Sublevel page layout */
    .sublevel-stat-row { display: grid; grid-template-columns: 25% 1fr 25%; gap: 16px; margin-bottom: 16px; align-items: stretch; }
    .sublevel-stat-row .stat-card { margin: 0; }
    .sublevel-people-center { text-align: center; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 12px 0; }
    .sublevel-people-num { font-size: 64px; font-weight: 800; line-height: 1; letter-spacing: -2px; }
    .sublevel-people-lbl { font-size: 15px; color: var(--gray-500); margin-top: 6px; font-weight: 500; }
    .sublevel-info-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 28px; align-items: stretch; }
    @media (max-width: 900px) {
      .sublevel-stat-row { grid-template-columns: 1fr 1fr; }
      .sublevel-stat-row .sublevel-people-center { grid-column: 1 / -1; order: -1; padding: 8px 0; }
      .sublevel-info-row { grid-template-columns: repeat(2, 1fr); }
    }
    @media (max-width: 560px) {
      .sublevel-stat-row { grid-template-columns: 1fr; }
      .sublevel-info-row { grid-template-columns: 1fr; }
    }

    /* Handoff bar (Input from … Responsible … Passing on to …) */
    .handoff-bar    { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
    .handoff-item   { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--gray-600); flex: 1; }
    .handoff-to     { display: flex; justify-content: flex-end; }
    .handoff-center { flex: 1; display: flex; justify-content: center; align-items: center; gap: 6px; flex-wrap: wrap; text-align: center; }
    .handoff-arrow  { color: var(--gray-400); font-size: 13px; }
    .handoff-label  { color: var(--gray-500); }
    .handoff-name   { font-weight: 600; color: var(--gray-800); background: var(--gray-100); border: 1px solid var(--gray-200); border-radius: 12px; padding: 1px 8px; font-size: 12px; }
    .handoff-unassigned { color: var(--gray-400); font-style: italic; }

    /* Sublevel info boxes (Goals / Tasks / Latest Entries) */
    .sublevel-info-box { background: var(--white); border: 1.5px solid var(--gray-300); border-top: 3px solid var(--gray-300); border-radius: 10px; padding: 18px 20px; transition: border-color .15s, box-shadow .15s; }
    .sublevel-info-box-title { font-size: 11px; font-weight: 500; color: var(--gray-600); letter-spacing: .07em; font-family: "IBM Plex Mono", monospace; margin-bottom: 10px; }
    .sublevel-info-empty { font-size: 12px; color: var(--gray-400); }

    /* Inline cohort cards inside Level History — neutral grey nest, no
       colored left border (the parent Level card already owns the level
       color; reusing it on the child reads as a sibling not a child).
       Status is communicated via the colored sublevel pill on the right. */
    .cohort-inline-wrap   { margin-top: 10px; padding: 10px 12px 12px; background: var(--gray-50); border-radius: 6px; display: flex; flex-direction: column; gap: 8px; border: 1px solid var(--gray-200); }
    .cohort-inline-label  { font-size: 10px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; letter-spacing: .06em; text-transform: uppercase; }
    .cohort-inline-card   { background: var(--white); border: 1px solid var(--gray-200); border-radius: 6px; padding: 10px 14px; transition: background .12s, border-color .12s; }
    .cohort-inline-card-click { cursor: pointer; }
    .cohort-inline-card-click:hover { background: var(--gray-100); border-color: var(--gray-300); }

    /* Exit Survey — tiny spinner inside the active language pill */
    .lang-spinner { width: 11px; height: 11px; border: 1.5px solid currentColor; border-right-color: transparent; border-radius: 50%; display: inline-block; animation: lang-spin .7s linear infinite; }
    @keyframes lang-spin { to { transform: rotate(360deg); } }

    /* Exit Survey — clickable card rows */
    .es-row { border: 1px solid var(--gray-200); border-radius: 8px; padding: 10px 12px; transition: background .12s, border-color .12s; background: var(--white); }
    .es-row:hover { background: var(--gray-50); border-color: var(--gray-300); }
    .es-row-open { background: var(--gray-50); border-color: var(--gray-300); }
    .es-row-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; cursor: pointer; }
    .es-caret { color: var(--gray-400); font-size: 11px; width: 10px; display: inline-block; }
    .es-name { font-size: 13px; font-weight: 600; color: var(--gray-800); }
    .es-name-link { background: none; border: 0; padding: 0; font-size: 13px; font-weight: 600; color: var(--purple-300); cursor: pointer; font-family: inherit; }
    .es-name-link:hover { text-decoration: underline; }
    .es-cohort { font-size: 11px; color: var(--gray-600); background: var(--gray-100); padding: 2px 7px; border-radius: 99px; }
    .es-followup { font-size: 11px; color: #15803d; font-weight: 600; }
    .es-time { font-size: 11px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; margin-left: auto; }
    .es-preview { margin-top: 6px; padding-left: 20px; font-size: 12px; color: var(--gray-600); line-height: 1.45; }
    .es-body { margin-top: 12px; padding: 12px 4px 4px 20px; border-top: 1px dashed var(--gray-200); }
    .es-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 14px 22px; }

    /* Exit Survey — ratings strip inside expanded card */
    .es-ratings { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; margin-bottom: 16px; }
    .es-rating-cell { background: var(--white); border: 1px solid var(--gray-200); border-radius: 6px; padding: 8px 10px; text-align: center; }
    .es-rating-label { font-size: 10px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; letter-spacing: .05em; text-transform: uppercase; margin-bottom: 4px; min-height: 22px; display: flex; align-items: center; justify-content: center; line-height: 1.1; }
    .es-rating-value { font-size: 20px; font-weight: 700; line-height: 1; }
    .es-rating-max { font-size: 11px; color: var(--gray-400); font-weight: 500; margin-left: 2px; }

    /* Exit Survey — chip rows (most valuable day, community, topics) */
    .es-chips-row { display: flex; flex-wrap: wrap; gap: 18px 28px; margin-bottom: 16px; }
    .es-chip-group { display: flex; flex-direction: column; gap: 4px; }
    .es-chip-label { font-size: 10px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; letter-spacing: .06em; text-transform: uppercase; }
    .es-chip { display: inline-block; background: var(--gray-100); color: var(--gray-800); padding: 3px 9px; border-radius: 99px; font-size: 12px; font-weight: 500; }
    .es-copy-btn { background: var(--white); border: 1px solid var(--gray-300); color: var(--gray-700); font-family: "IBM Plex Mono", monospace; font-size: 10px; letter-spacing: .06em; text-transform: uppercase; padding: 2px 8px; border-radius: 99px; cursor: pointer; transition: background .12s, border-color .12s, color .12s; }
    .es-copy-btn:hover { background: var(--gray-100); border-color: var(--gray-400); color: var(--gray-900); }

    /* MFB-223 — the inline copy affordance (CopyButton). Icon-only and quiet:
       it sits beside a value someone is reading, so it must not compete with
       it. 28px square keeps it clear of the 44px minimum only because it is a
       convenience duplicate of text that is already selectable; the mailto:
       link next to it is the primary target. */
    .copy-inline-btn { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 6px; vertical-align: middle; padding: 0; border: 1px solid var(--gray-300); border-radius: 6px; background: var(--white); color: var(--gray-600); cursor: pointer; transition: background .12s, border-color .12s, color .12s; }
    .copy-inline-btn:hover { background: var(--gray-100); border-color: var(--gray-400); color: var(--gray-900); }
    .copy-inline-btn:focus-visible { outline: 2px solid var(--purple-200); outline-offset: 1px; }
    [data-theme="dark"] .copy-inline-btn { background: transparent; border-color: var(--gray-700); color: var(--gray-400); }
    [data-theme="dark"] .copy-inline-btn:hover { background: rgba(255,255,255,.06); border-color: var(--gray-600); color: var(--gray-200); }
    /* The address wraps on a narrow column; the button must not be dragged
       away from the last line, so the row is a flex box with the icon pinned.
       Type, wrapping and size live here rather than inline, because the
       primary and secondary addresses have to stay identical. 12px keeps a
       typical address on two lines in a ~180px column: it used to be 14px,
       which stranded the last character of ".com" on a line of its own.
       `overflow-wrap: anywhere` is the last resort only; the preferred break
       is the <wbr> the view puts before the "@". */
    .person-email-row { display: flex; align-items: flex-start; gap: 0;
      font-size: 12px; line-height: 1.3; font-family: "IBM Plex Mono", monospace;
      overflow-wrap: anywhere; }
    .person-email-row > a { flex: 1 1 auto; min-width: 0; }
    .person-email-row .copy-inline-btn { flex: 0 0 auto; }

    /* Exit Survey — tool matrix (per-tool Likert) */
    .es-tools { margin-bottom: 16px; }
    .es-section-label { font-size: 10px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; letter-spacing: .06em; text-transform: uppercase; margin-bottom: 6px; }
    .es-tool-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 6px 14px; }
    .es-tool-row { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 5px 0; border-bottom: 1px dotted var(--gray-200); }
    .es-tool-name { font-size: 12.5px; color: var(--gray-800); }
    .es-tool-pill { font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 99px; white-space: nowrap; }
    .es-tool-strong { background: #16a34a22; color: #15803d; }
    .es-tool-mid    { background: #0369a122; color: #0369a1; }
    .es-tool-weak   { background: #6b728022; color: #4b5563; }

    /* Exit Survey — expanded card footer */
    .es-foot { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-top: 14px; padding-top: 12px; border-top: 1px dashed var(--gray-200); }
    .es-foot-time { font-size: 11px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; }
    .sublevel-info-link { display: block; width: 100%; margin-top: 12px; padding: 8px 0 0; background: none; border: 0; border-top: 1px solid var(--gray-200); font-family: "IBM Plex Mono", monospace; font-size: 11px; color: var(--gray-500); cursor: pointer; text-align: right; letter-spacing: .02em; transition: color .15s; }
    .sublevel-info-link:hover { color: var(--orange-400); }

    /* Latest Entries: full-width, column-fill flow (down, then next column) */
    .latest-entries-grid { columns: 2 auto; column-gap: 24px; }
    @media (max-width: 540px) { .latest-entries-grid { columns: 1; } }
    .latest-entry-community { color: var(--gray-500); font-size: 11px; margin-left: 4px; }
    .latest-entry-row { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; font-size: 12px; color: var(--gray-700); min-width: 0; padding: 7px 0; break-inside: avoid; -webkit-column-break-inside: avoid; border-bottom: 1px solid var(--gray-100); }
    .latest-entry-row:last-child { border-bottom: 0; }
    .latest-entry-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
    .latest-entry-time { font-size: 10px; color: var(--gray-400); font-family: "IBM Plex Mono", monospace; white-space: nowrap; flex-shrink: 0; }
    /* Stage 2 panels: shared by the Filter modal and the Update Mentorship
       modal, so the two read as one thing.
       They started as .apg-toggle chips in a wrapping flex row, which looked a
       mess for a concrete reason: .apg-toggle carries `flex: 1`, so the chips on
       every line stretch to fill that line and no two lines share a width, and
       a three-word option in a narrow chip breaks onto three lines.
       This is a fixed 2-column grid of panels, and inside each panel one option
       per line: box, label, then a count or nothing. Everything lines up because
       everything sits on the same grid, not because the strings happen to be a
       similar length. A round box means "pick one" (Update), a square one means
       "tick any" (Filter). */
    .s2p-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
    .s2p-panel { border: 1px solid var(--gray-200); border-radius: 8px; padding: 10px 12px; display: flex; flex-direction: column; align-content: start; }
    .s2p-panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
    .s2p-panel-label { font-size: 11px; color: var(--gray-600); }
    .s2p-panel-n { font-size: 10px; font-weight: 600; color: var(--purple-300); }
    .s2p-opt { display: grid; grid-template-columns: 15px minmax(0, 1fr) auto; align-items: center; gap: 8px; width: 100%; padding: 5px 6px; border: 0; border-radius: 6px; background: transparent; font-family: inherit; font-size: 12px; color: var(--gray-800); text-align: left; cursor: pointer; }
    .s2p-opt:hover { background: var(--gray-100); }
    .s2p-opt.on { background: rgba(66,44,112,.10); color: var(--purple-300); font-weight: 600; }
    .s2p-box { width: 15px; height: 15px; border-radius: 4px; border: 1.5px solid var(--gray-400); display: inline-flex; align-items: center; justify-content: center; font-size: 10px; line-height: 1; color: transparent; }
    .s2p-opt.on .s2p-box { border-color: var(--purple-300); background: var(--purple-300); color: var(--white); }
    .s2p-label { overflow: hidden; text-overflow: ellipsis; }
    /* Per-option glyph on Mentorship status and Direction. Fixed width so the
       labels still line up on the rows that have no emoji. */
    .s2p-emoji { display: inline-block; width: 1.25em; margin-right: 4px; font-size: 12px; line-height: 1; }
    /* Teaching status, drawn like phone reception: bars rising left to right,
       aligned on their BASE, so the run reads as a level and not as a wave. */
    .s2p-bars { display: inline-flex; align-items: flex-end; gap: 2px; height: 13px; margin-right: 6px; vertical-align: -2px; opacity: .5; }
    .s2p-opt:hover .s2p-bars, .s2p-opt.on .s2p-bars { opacity: 1; }
    .s2p-bar { width: 3px; border-radius: 1px; }
    /* Tabular figures so the counts form a straight right edge. */
    .s2p-count { font-size: 10px; color: var(--gray-500); font-variant-numeric: tabular-nums; font-family: "IBM Plex Mono", monospace; }
    .s2p-opt.on .s2p-count { color: var(--purple-300); }
    .s2p-count.zero { color: var(--gray-300); }
    .s2p-box.radio { border-radius: 50%; }
    .s2p-panel.wide { grid-column: 1 / -1; }
    .s2p-person { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 12px; border: 1px solid var(--gray-200); border-radius: 8px; margin-bottom: 12px; }
    .s2p-note { font-size: 11px; color: var(--gray-500); margin-top: 6px; line-height: 1.4; }
    @media (max-width: 620px) { .s2p-grid { grid-template-columns: 1fr; } }

    /* Level 4.4 (Mentorship) Latest Entries: a table, one row per person, with
       the Stage 2 selects editable in place, a header line naming the columns
       and a + to log an action. Deliberately NOT .latest-entries-grid: that is
       `columns: 2`, which leaves no room for controls.

       Header and rows share one grid template so the columns line up. The
       template is driven by --s2-cols, which the view sets from however many
       fields the server sent, so a sixth Stage 2 column would not need a CSS
       edit. */
    .s2-table { display: flex; flex-direction: column; }
    .s2-head, .s2-entry-row {
      display: grid;
      grid-template-columns: minmax(120px, 1.6fr) repeat(var(--s2-cols, 5), minmax(88px, 1fr)) 30px;
      gap: 8px;
      align-items: center;
    }
    .s2-head { padding: 0 0 6px; border-bottom: 1px solid var(--gray-200); }
    .s2-head span { font-size: 10px; color: var(--gray-500); letter-spacing: .02em; line-height: 1.2; }
    .s2-entry-row { padding: 7px 0; border-bottom: 1px solid var(--gray-100); font-size: 12px; color: var(--gray-700); }
    .s2-entry-row:last-child { border-bottom: 0; }
    .s2-entry-head { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
    .s2-entry-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; cursor: pointer; }
    .s2-entry-name:hover { color: var(--orange-400); }
    .s2-select { width: 100%; font-size: 11px; padding: 4px 6px; border: 1.5px solid var(--gray-300); border-radius: 6px; background: var(--white); color: var(--gray-500); font-family: inherit; cursor: pointer; min-width: 0; }
    .s2-select.is-set { border-color: var(--purple-300); color: var(--purple-300); font-weight: 600; }
    .s2-select:disabled { opacity: .55; cursor: progress; }
    /* Pastel colour coding for a set answer (data/stage-two-colors.js picks the
       class by the option's POSITION in its list, never by its name). Solid
       fills, deliberately low chroma: the point is to group a column at a
       glance, not to shout. Eight of them, cycled, because the five questions
       carry between four and six options each. */
    .s2-select.s2-c0, .s2-sw.s2-c0 { background: #E4F3EA; border-color: #BFE3CD; color: #1F5134; }
    .s2-select.s2-c1, .s2-sw.s2-c1 { background: #E3EFF8; border-color: #C2DCEE; color: #1E4A6B; }
    .s2-select.s2-c2, .s2-sw.s2-c2 { background: #EDE8F7; border-color: #D6CCEC; color: #40306B; }
    .s2-select.s2-c3, .s2-sw.s2-c3 { background: #FBEBE0; border-color: #F0D3BE; color: #6B4224; }
    .s2-select.s2-c4, .s2-sw.s2-c4 { background: #F8F1DA; border-color: #EDE0B7; color: #63501C; }
    .s2-select.s2-c5, .s2-sw.s2-c5 { background: #F9E7EB; border-color: #EFCBD4; color: #6B2C3A; }
    .s2-select.s2-c6, .s2-sw.s2-c6 { background: #EAF0E2; border-color: #D3E0C4; color: #3E4F2A; }
    .s2-select.s2-c7, .s2-sw.s2-c7 { background: #E8EAEE; border-color: #CFD4DC; color: #38404D; }
    /* The legend swatch in the Filter modal: same eight, as a small square. */
    .s2-sw { display: inline-block; width: 9px; height: 9px; border-radius: 3px; border: 1px solid transparent; margin-right: 7px; vertical-align: 0; flex-shrink: 0; }
    /* Dark mode inverts the relationship: the pastel becomes the TEXT and a
       deep muted version becomes the fill, or eight light blocks would glare
       out of a dark row. */
    [data-theme="dark"] .s2-select.s2-c0, [data-theme="dark"] .s2-sw.s2-c0 { background: #1E3328; border-color: #2C4A38; color: #A9DCC0; }
    [data-theme="dark"] .s2-select.s2-c1, [data-theme="dark"] .s2-sw.s2-c1 { background: #1B2E3E; border-color: #274257; color: #A8CDE6; }
    [data-theme="dark"] .s2-select.s2-c2, [data-theme="dark"] .s2-sw.s2-c2 { background: #2A2440; border-color: #3C345A; color: #C6B6EA; }
    [data-theme="dark"] .s2-select.s2-c3, [data-theme="dark"] .s2-sw.s2-c3 { background: #3A2A1E; border-color: #513C2C; color: #EAC4A4; }
    [data-theme="dark"] .s2-select.s2-c4, [data-theme="dark"] .s2-sw.s2-c4 { background: #332E19; border-color: #494226; color: #E3D19A; }
    [data-theme="dark"] .s2-select.s2-c5, [data-theme="dark"] .s2-sw.s2-c5 { background: #3A222A; border-color: #52313C; color: #EBB6C3; }
    [data-theme="dark"] .s2-select.s2-c6, [data-theme="dark"] .s2-sw.s2-c6 { background: #26301F; border-color: #37442E; color: #C3D6AC; }
    [data-theme="dark"] .s2-select.s2-c7, [data-theme="dark"] .s2-sw.s2-c7 { background: #262A31; border-color: #363C46; color: #C3CAD5; }
    .s2-log-btn { width: 26px; height: 26px; border-radius: 6px; border: 1.5px solid var(--gray-300); background: var(--white); color: var(--gray-600); font-size: 15px; line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; }
    .s2-log-btn:hover { border-color: var(--orange-400); color: var(--orange-400); }
    /* Below the table breakpoint the row stops being a table: the header hides
       and each person becomes name-then-wrapped-controls, which is the only
       shape that fits five dropdowns on a phone. */
    @media (max-width: 900px) {
      .s2-head { display: none; }
      .s2-entry-row { grid-template-columns: 1fr; gap: 6px; }
      .s2-select { max-width: 190px; }
      .s2-entry-controls { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
    }
    @media (min-width: 901px) { .s2-entry-controls { display: contents; } }
    @media (max-width: 768px) { .s2-log-btn { width: 44px; height: 44px; font-size: 20px; } }
    .kw-icon { cursor: help; font-size: 12px; margin-left: 4px; opacity: 0.65; transition: opacity .15s; }
    .kw-icon:hover { opacity: 1; }
    @keyframes spin { to { transform: rotate(360deg); } }

    /* Styled hover tooltip for ETP exit-survey keywords — used on the
       certify-cohort modal student rows. The native `title=` tooltip is
       OS-styled and too dim to read; this gives it a proper card look. */
    .kw-tooltip { position: relative; display: inline-block; cursor: help; }
    .kw-tooltip .kw-icon-glyph { font-size: 12px; margin-left: 4px; opacity: 0.65; transition: opacity .15s; }
    .kw-tooltip:hover .kw-icon-glyph { opacity: 1; }
    .kw-tooltip .kw-tooltip-body {
      position: absolute;
      bottom: calc(100% + 8px);
      right: 0;
      background: #1f2937;
      color: #fff;
      padding: 9px 12px;
      border-radius: 7px;
      font-size: 11.5px;
      line-height: 1.5;
      font-weight: 400;
      white-space: pre-wrap;
      word-break: break-word;
      max-width: 320px;
      width: max-content;
      pointer-events: none;
      opacity: 0;
      visibility: hidden;
      transform: translateY(2px);
      transition: opacity .14s ease, transform .14s ease, visibility .14s;
      z-index: 30;
      box-shadow: 0 6px 18px rgba(15, 23, 42, .22);
      text-align: left;
    }
    .kw-tooltip .kw-tooltip-body::before {
      content: 'Exit survey keywords';
      display: block;
      font-size: 9.5px;
      font-weight: 700;
      text-transform: uppercase;
      letter-spacing: .06em;
      color: rgba(255,255,255,.55);
      margin-bottom: 4px;
    }
    .kw-tooltip .kw-tooltip-body::after {
      content: '';
      position: absolute;
      top: 100%;
      right: 8px;
      border: 6px solid transparent;
      border-top-color: #1f2937;
    }
    .kw-tooltip:hover .kw-tooltip-body,
    .kw-tooltip:focus-within .kw-tooltip-body {
      opacity: 1;
      visibility: visible;
      transform: translateY(0);
    }

    /* Placeholder panel & column chips (used on Level page) */
    .placeholder-panel { background: var(--white); border: 1.5px dashed var(--gray-300); border-radius: 10px; padding: 52px 32px; text-align: center; }
    .placeholder-columns { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 20px; }
    .col-chip { padding: 4px 12px; background: var(--gray-100); border: 1px solid var(--gray-300); border-radius: 99px; font-size: 11px; color: var(--gray-700); font-family: "IBM Plex Mono", monospace; }

    /* Quick-link button row (Sublevel page tools row) */
    .ql-list   { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
    .ql-button { background: none; border: none; padding: 0; cursor: pointer; font-size: 12px; color: var(--purple-300); font-family: inherit; text-align: left; }
    .ql-button:hover { color: var(--orange-400); }
    .ql-link   { font-size: 12px; color: var(--purple-300); text-decoration: none; }
    .ql-link:hover { color: var(--orange-400); }

    /* Admin: member list (Team page) */
    .admin-section       { background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 10px; padding: 22px 24px; margin-bottom: 22px; }
    .member-list         { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
    .member-row          { display: flex; align-items: center; gap: 14px; padding: 10px 12px; border: 1px solid var(--gray-200); border-radius: 8px; background: var(--gray-100); }
    .member-row-avatar   { width: 36px; height: 36px; border-radius: 50%; background: var(--purple-300); color: var(--white); display: flex; align-items: center; justify-content: center; font-size: 14px; font-weight: 600; flex-shrink: 0; overflow: hidden; }
    .member-row-avatar img { width: 100%; height: 100%; object-fit: cover; }
    .member-row-info     { flex: 1; min-width: 0; }
    .member-row-name     { font-size: 13px; font-weight: 600; color: var(--gray-900); }
    .member-row-email    { font-size: 11px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; }
    .member-role-btns    { display: flex; gap: 4px; flex-wrap: wrap; }
    .role-btn            { font-size: 11px; padding: 4px 10px; border: 1.5px solid var(--gray-300); background: var(--white); color: var(--gray-700); border-radius: 6px; cursor: pointer; font-family: inherit; font-weight: 500; transition: border-color .12s, color .12s; }
    .role-btn:hover      { border-color: var(--gray-500); }
    .role-btn:disabled   { opacity: .5; cursor: not-allowed; }
    .member-remove-btn   { background: none; border: none; color: var(--gray-400); font-size: 18px; cursor: pointer; padding: 0 6px; transition: color .12s; }
    .member-remove-btn:hover:not(:disabled) { color: #ef4444; }
    .member-remove-btn:disabled { opacity: .3; cursor: not-allowed; }
    .add-member-row      { display: flex; gap: 10px; align-items: center; padding-top: 8px; border-top: 1px solid var(--gray-200); margin-bottom: 14px; padding-top: 14px; }
    .form-input          { padding: 8px 12px; border: 1.5px solid var(--gray-300); border-radius: 6px; font-size: 13px; font-family: inherit; }
    .role-legend         { display: flex; flex-wrap: wrap; gap: 18px 24px; padding-top: 14px; border-top: 1px solid var(--gray-200); }
    .role-legend-item    { font-size: 11px; color: var(--gray-600); display: flex; align-items: center; gap: 7px; }
    .role-legend-dot     { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }

    /* Admin: assignment matrix (Roles page) */
    .admin-section-group-title { font-size: 14px; font-weight: 600; color: var(--purple-300); margin-bottom: 6px; }
    .admin-section-group-desc  { font-size: 12px; color: var(--gray-600); margin-bottom: 16px; }
    /* The table grows naturally; the page scrolls. overflow-x:auto
       stays so a wide member list still horizontal-scrolls inside
       the card on narrow screens without breaking the layout. */
    .assign-table-wrap   { background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 10px; overflow: auto; padding: 4px; }
    /* On admin-roles the page uses body-scroll mode, so give the table its own
       scroll container capped to the viewport. That lets the sticky thead pin
       at the top of the wrap so member names stay visible on long tables. */
    .app.page-scroll .assign-table-wrap { max-height: calc(100vh - 140px); }
    .assign-table        { border-collapse: separate; border-spacing: 0; font-size: 12px; }
    .assign-table th, .assign-table td { padding: 6px 8px; }
    .assign-table thead th { position: sticky; top: 0; z-index: 5; background: var(--white); box-shadow: 0 1px 0 var(--gray-200); }
    /* Section-heading rows (Mattermost Setup / Level N / Pages / Campaigns)
       are sticky too, so when a section scrolls past the top the current
       section's title tucks under the header row instead of vanishing. */
    .assign-table-frozen tbody td.at-level-row-frozen { position: sticky; top: 96px; z-index: 4; background: var(--white); }
    [data-theme="dark"] .assign-table-frozen tbody td.at-level-row-frozen { background: var(--gray-900, #0f172a); }
    .at-name-head        { writing-mode: vertical-rl; transform: rotate(180deg); font-size: 11px; font-weight: 600; color: var(--gray-700); padding: 8px 0; min-height: 80px; }
    .at-level-row        { background: var(--gray-100); font-size: 11px; font-weight: 600; color: var(--gray-700); border-left: 3px solid var(--gray-400); padding: 8px 12px !important; }
    .at-sub-label        { font-size: 11px; color: var(--gray-700); padding-left: 14px !important; white-space: nowrap; }
    .at-sub-num          { font-family: "IBM Plex Mono", monospace; font-size: 10px; opacity: .55; margin-right: 6px; }
    .assign-cb           { width: 18px; height: 18px; border: 1.5px solid var(--gray-300); border-radius: 4px; cursor: pointer; transition: background .12s, border-color .12s; margin: 0 auto; }
    .assign-cb:hover     { border-color: var(--purple-300); }
    .assign-cb.checked   { background: var(--purple-300); border-color: var(--purple-300); position: relative; }
    .assign-cb.checked::after { content: "✓"; color: #fff; font-size: 12px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
    /* Unsaved cells get an amber outline so it's obvious what's
       pending. The colour is the brand orange-300 alpha so it sits
       in the brand family while reading as "attention" vs the
       purple checked state. */
    .assign-cb.dirty           { outline: 2px solid rgba(247,148,31,.9); outline-offset: 2px; }
    .assign-cb.dirty.checked   { outline-color: rgba(247,148,31,1); }

    /* Group-heading rows sit one level under a section heading, mirroring the
       sidebar's collapsible groups (Team Tools, Level N, Campaigns, Admin).
       Deliberately NOT sticky: only one sticky tier fits under the frozen
       thead, and the section heading is the more useful thing to keep. */
    .at-group-row        { background: var(--white); font-size: 11px; font-weight: 600; color: var(--gray-600); padding: 7px 12px 5px 22px !important; border-left: 3px solid transparent; }
    [data-theme="dark"] .at-group-row { background: transparent; }
    .at-group-icon       { display: inline-flex; vertical-align: -2px; margin-right: 6px; opacity: .8; }
    .at-group-lbl        { letter-spacing: .02em; }
    .at-group-note       { margin-left: 8px; font-weight: 400; font-style: italic; color: var(--gray-500); }
    /* Rows inside a named group are indented past the group label, so the tree
       reads the same way the sidebar does. Rows in an unnamed group (Community,
       Settings) sit at the section indent, exactly as they do in the menu. */
    .at-sub-label.at-sub-indent { padding-left: 32px !important; }
    .at-row-icon         { display: inline-flex; vertical-align: -2px; margin-right: 6px; opacity: .75; }

    /* A member whose ROLE already grants access (owner / admin / department_head
       short-circuit every assignment check) gets a greyed cell, so it is visible
       at a glance that the tick changes nothing for them today. Still clickable:
       the assignment is stored, and it goes live if they are moved down to
       team_member. Distinct from .assign-cb-locked, which is genuinely inert. */
    .assign-cb-byrole            { border-style: dashed; border-color: var(--gray-300); background: var(--gray-100); }
    .assign-cb-byrole:hover      { border-color: var(--gray-400); }
    .assign-cb-byrole.checked    { background: var(--gray-300); border-color: var(--gray-400); border-style: dashed; }
    .assign-cb-byrole.checked::after { color: var(--gray-600); }
    /* Admin pages are role-gated, so their cells show as inert rather than as
       unticked boxes an admin might try to tick. */
    .assign-cb-locked    { cursor: not-allowed; background: repeating-linear-gradient(45deg, var(--gray-100), var(--gray-100) 3px, var(--gray-200) 3px, var(--gray-200) 6px); border-color: var(--gray-200); }
    .assign-cb-locked:hover { border-color: var(--gray-200); }

    /* Sticky save bar for /admin-roles. Bottom-right floats above the
       table so the user can keep clicking and the bar follows. The
       bar only renders when there are pending changes or a status
       message; see AdminRolesView. */
    .admin-save-bar {
      position: fixed;
      bottom: 18px;
      right: 24px;
      z-index: 900;
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 10px 14px;
      background: var(--white);
      border: 1.5px solid var(--orange-300);
      border-radius: 10px;
      box-shadow: 0 12px 32px rgba(66, 44, 112, 0.18);
      font-size: 13px;
      color: var(--gray-900);
      transition: border-color .15s, box-shadow .15s;
    }
    /* Clean state: nothing pending. Bar stays visible (so the
       affordance is obvious from the moment the page loads) but
       reads as muted so it doesn't shout for attention. */
    .admin-save-bar.clean { border-color: var(--gray-300); box-shadow: 0 6px 18px rgba(0,0,0,.08); }
    .admin-save-bar-info { font-size: 13px; color: var(--gray-700); }
    .admin-save-bar-info strong { color: var(--orange-300); font-weight: 600; font-variant-numeric: tabular-nums; }
    /* Save receipt. Reuses the purple that already means "on" in this table
       rather than introducing a success colour: no brand value is invented
       here, and any new one belongs in @myfirstbitcoin/design. */
    .admin-save-bar-ok { color: var(--purple-300); font-weight: 600; }

    /* ── Network → Languages directory ──────────────────────────────────────
       A compact grid of 91 languages. The selected card spans the whole row
       (grid-column: 1/-1) so its detail panel has width to read in, which is
       what makes an in-place expand work in a grid at all. */
    .lang-dir-head       { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin-bottom: 14px; }
    .lang-dir-search     { width: 100%; max-width: 420px; padding: 9px 12px; border: 1.5px solid var(--gray-300); border-radius: 6px; font-size: 14px; font-family: inherit; color: var(--gray-900); background: var(--white); }
    .lang-dir-meta       { font-size: 11.5px; color: var(--gray-500); }
    .lang-grid           { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 5px; padding-bottom: 24px; }
    .lang-card           { border: 1px solid var(--gray-300); border-radius: 6px; background: var(--white); min-width: 0; }
    .lang-card-open      { grid-column: 1 / -1; border-color: var(--purple-300); box-shadow: 0 1px 4px rgba(66,44,112,.08); }
    .lang-card-empty     { opacity: .55; }
    .lang-card-btn       { display: flex; align-items: center; gap: 8px; width: 100%; background: none; border: 0; padding: 7px 10px; font: inherit; font-size: 13px; color: var(--gray-900); cursor: pointer; text-align: left; border-radius: 6px; }
    .lang-card-btn:hover { background: var(--gray-100); }
    .lang-card-name      { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .lang-card-count     { font-family: "IBM Plex Mono", monospace; font-size: 10.5px; color: var(--gray-500); flex-shrink: 0; font-variant-numeric: tabular-nums; }
    .lang-card-chev      { flex-shrink: 0; font-size: 9px; color: var(--gray-400); transition: transform .12s; }
    .lang-card-chev.open { transform: rotate(180deg); color: var(--purple-300); }
    .lang-card-panel     { display: flex; flex-wrap: wrap; gap: 10px 28px; padding: 4px 12px 12px; border-top: 1px solid var(--gray-200); }
    .lang-stat           { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
    .lang-stat-k         { font-size: 10.5px; color: var(--gray-500); }
    .lang-stat-v         { font-size: 17px; font-weight: 600; color: var(--gray-900); font-variant-numeric: tabular-nums; line-height: 1.1; }
    .lang-stat-sub       { font-size: 11px; color: var(--gray-600); overflow-wrap: anywhere; }
    .lang-stat-none      { font-size: 11.5px; color: var(--gray-500); font-style: italic; align-self: center; }
    @media (max-width: 768px) {
      .lang-grid         { grid-template-columns: 1fr; }
      .lang-dir-search   { font-size: 16px; }
    }
    .admin-save-bar-btn {
      border: 1.5px solid var(--gray-300);
      background: var(--white);
      color: var(--gray-700);
      padding: 7px 12px;
      border-radius: 6px;
      font: inherit;
      font-size: 12.5px;
      cursor: pointer;
      transition: background .12s, border-color .12s, color .12s;
    }
    .admin-save-bar-btn:hover:not(:disabled) { border-color: var(--purple-300); color: var(--purple-300); }
    .admin-save-bar-btn:disabled { opacity: .55; cursor: not-allowed; }
    .admin-save-bar-save {
      background: var(--orange-300);
      border-color: var(--orange-300);
      color: var(--white);
      font-weight: 500;
    }
    .admin-save-bar-save:hover:not(:disabled) { background: var(--orange-400); border-color: var(--orange-400); color: var(--white); }
    @media (max-width: 600px) {
      .admin-save-bar { left: 12px; right: 12px; bottom: 12px; flex-wrap: wrap; }
      .admin-save-bar-save { flex: 1; }
    }

    /* ── Perks matrix (/perks-matrix) ────────────────────────────────────
       Column headers are emoji only — 30 columns leave no room for a title —
       so the name has to arrive on hover. A native `title` tooltip is slow,
       unstyled and truncates, hence this hover card. It is absolutely
       positioned inside the th, which works only while no ancestor clips
       overflow: the matrix table deliberately has no overflow container. */
    .perk-th { position: relative; }
    .perk-tip {
      position: absolute;
      top: calc(100% + 6px);
      z-index: 60;
      width: max-content;
      max-width: 260px;
      padding: 9px 11px;
      background: var(--gray-900, #1f2430);
      color: #fff;
      border-radius: 8px;
      box-shadow: 0 10px 28px rgba(66, 44, 112, .28);
      text-align: left;
      font-weight: 400;
      opacity: 0;
      visibility: hidden;
      transform: translateY(-3px);
      transition: opacity .12s ease, transform .12s ease, visibility .12s;
      pointer-events: none;
    }
    .perk-th:hover .perk-tip, .perk-th:focus-within .perk-tip {
      opacity: 1; visibility: visible; transform: translateY(0);
    }
    /* Columns near either edge would push a centred card off-screen and make
       the page scroll sideways, which the matrix exists to avoid. */
    .perk-tip-mid   { left: 50%; transform: translate(-50%, -3px); }
    .perk-th:hover .perk-tip-mid, .perk-th:focus-within .perk-tip-mid { transform: translate(-50%, 0); }
    .perk-tip-start { left: 0; }
    .perk-tip-end   { right: 0; }
    .perk-tip-title { font-size: 13px; font-weight: 600; line-height: 1.35; margin-bottom: 3px; }
    .perk-tip-meta  { font-size: 11px; color: rgba(255,255,255,.72); font-family: 'IBM Plex Mono', monospace; }
    .perk-tip-soon  {
      display: inline-block; margin-top: 6px; padding: 1px 6px; border-radius: 999px;
      background: rgba(255,255,255,.14); color: rgba(255,255,255,.9);
      font-size: 10px; letter-spacing: .04em;
    }

    /* Below the perk's score threshold. Deliberately loud: the whole point of
       the grid is spotting who has earned what, so "not there yet" must read
       at a glance and not just on close inspection. Still awardable. */
    .perk-cell-ineligible {
      background:
        repeating-linear-gradient(45deg,
          rgba(94, 55, 142, .07) 0 5px,
          rgba(94, 55, 142, .015) 5px 10px);
      box-shadow: inset 0 0 0 1px rgba(94, 55, 142, .08);
    }
    /* Coming-soon perks cannot be delivered yet, so their column is not
       clickable at all — greyed, cursor not-allowed, no hover affordance. */
    .perk-cell-soon { background: repeating-linear-gradient(45deg, rgba(120,120,120,.05) 0 5px, transparent 5px 10px); }
    .perk-cell-btn:not(:disabled):hover .perk-box { border-color: var(--purple-300); background: rgba(94, 55, 142, .07); }
    .perk-box-pending { box-shadow: 0 0 0 2px rgba(247, 148, 31, .55); }

    /* Admin: data source diagnostic */
    .ds-meta       { display: flex; flex-wrap: wrap; gap: 24px; padding: 14px 18px; background: var(--gray-100); border: 1px solid var(--gray-200); border-radius: 8px; margin-bottom: 18px; font-size: 12px; }
    .ds-meta-item  { display: flex; align-items: center; gap: 8px; color: var(--gray-700); }
    .ds-meta-key   { color: var(--gray-500); letter-spacing: .06em; font-family: "IBM Plex Mono", monospace; font-size: 10px; }
    .ds-meta-item code { font-family: "IBM Plex Mono", monospace; background: var(--white); padding: 2px 8px; border-radius: 4px; border: 1px solid var(--gray-200); color: var(--purple-300); font-size: 11px; }
    .ds-bar-wrap   { background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 10px; padding: 18px 22px; margin-bottom: 28px; }
    .ds-bar        { display: flex; height: 16px; border-radius: 8px; overflow: hidden; background: var(--gray-200); margin-bottom: 12px; }
    .ds-bar-seg    { transition: width .4s; }
    .ds-bar-legend { display: flex; flex-wrap: wrap; gap: 22px; font-size: 12px; color: var(--gray-700); }
    .ds-bar-legend > span { display: inline-flex; align-items: center; gap: 6px; }
    .ds-bar-dot    { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }

    /* Admin: page header with action button */
    .admin-page-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 22px; gap: 16px; }
    .admin-page-header h2 { font-size: 20px; font-weight: 500; color: var(--purple-300); letter-spacing: -.01em; }
    .admin-page-header p  { color: var(--gray-600); font-size: 13px; margin-top: 4px; }
    /* Impact Bridge admin page sections — match the rest of the CRM card style. */
    .ib-section { background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 10px; padding: 18px 20px; margin-bottom: 16px; border-top: 3px solid var(--orange-400); }
    .ib-section h3 { font-size: 13px; font-weight: 600; color: var(--gray-800); margin: 0 0 12px; letter-spacing: .005em; }
    .ib-grid { display: grid; grid-template-columns: 1fr; gap: 10px; }
    @media (min-width: 720px) { .ib-grid { grid-template-columns: repeat(2, 1fr); } }
    .ib-meta { display: flex; align-items: baseline; gap: 10px; padding: 6px 0; border-bottom: 1px solid var(--gray-100); font-size: 12.5px; color: var(--gray-800); }
    .ib-meta:last-child { border-bottom: 0; }
    .ib-meta-lbl { flex-shrink: 0; min-width: 130px; font-size: 10px; color: var(--gray-500); font-family: 'IBM Plex Mono', monospace; letter-spacing: .06em; text-transform: uppercase; }
    .ib-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
    .ib-table thead th { text-align: left; padding: 8px 10px; font-size: 10px; font-family: 'IBM Plex Mono', monospace; color: var(--gray-500); letter-spacing: .06em; text-transform: uppercase; font-weight: 600; border-bottom: 1.5px solid var(--gray-200); }
    .ib-table tbody td { padding: 9px 10px; border-bottom: 1px solid var(--gray-100); vertical-align: top; color: var(--gray-700); line-height: 1.4; }
    .ib-table tbody tr:last-child td { border-bottom: 0; }
    .ib-table code { font-family: 'IBM Plex Mono', monospace; font-size: 11.5px; color: var(--purple-300); background: rgba(66,44,112,.06); padding: 1px 6px; border-radius: 4px; }
    /* Live values cell — was white-space:nowrap, which let long object/array
       values blow out the column and squeeze the description column to a
       sliver. Now wraps + caps at 320px so primitives stay compact and
       complex values fold onto a few lines without dominating the row. */
    .ib-table .ib-val { font-family: 'IBM Plex Mono', monospace; font-variant-numeric: tabular-nums; color: var(--gray-900); word-break: break-word; min-width: 220px; max-width: 480px; }
    .ib-type { font-family: 'IBM Plex Mono', monospace; font-size: 10.5px; color: var(--gray-600); background: var(--gray-100); padding: 2px 6px; border-radius: 4px; }

    /* Admin: Build on NocoDB (the handbook page). Prose-first, so the type is a
       little larger and the measure a little narrower than the rest of Admin:
       this page is meant to be read end to end, not scanned. No uppercase
       micro-labels here (Brand Rule 1) — the legacy ones elsewhere in this file
       are drift we are not propagating. */
    .ng-actions      { display: flex; gap: 8px; flex-shrink: 0; }
    .ng-intro        { max-width: 74ch; margin-bottom: 20px; }
    .ng-intro p      { font-size: 13.5px; line-height: 1.65; color: var(--gray-700); margin: 0 0 10px; }
    .ng-draft        { border-left: 3px solid var(--orange-400); padding-left: 12px; color: var(--gray-600) !important; }
    .ng-toolbar      { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; flex-wrap: wrap; }
    .ng-search       { flex: 1 1 320px; max-width: 460px; padding: 8px 12px; font-size: 13px; font-family: inherit;
                       border: 1.5px solid var(--gray-300); border-radius: 8px; background: var(--white); color: var(--gray-900); }
    .ng-search:focus { outline: none; border-color: var(--purple-300); }
    .ng-count        { font-size: 12px; color: var(--gray-600); font-variant-numeric: tabular-nums; }
    .ng-clear        { background: none; border: 0; padding: 0; font-size: 12px; color: var(--purple-300); cursor: pointer; font-family: inherit; }
    .ng-toc          { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 22px; }
    .ng-toc-link     { display: inline-flex; align-items: center; gap: 7px; padding: 5px 11px; border-radius: 999px;
                       background: var(--white); border: 1px solid var(--gray-300); font-size: 12.5px;
                       color: var(--gray-800); text-decoration: none; }
    .ng-toc-link:hover { border-color: var(--purple-300); color: var(--purple-300); }
    .ng-toc-n        { font-size: 11px; color: var(--gray-500); font-variant-numeric: tabular-nums; }
    .ng-chapter      { background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 10px;
                       border-top: 3px solid var(--orange-400); padding: 18px 22px 6px; margin-bottom: 16px; }
    .ng-chapter-warn { border-top-color: var(--purple-300); }
    .ng-chapter h3   { font-size: 15px; font-weight: 600; color: var(--purple-300); margin: 0 0 8px; letter-spacing: -.005em; }
    .ng-lede         { font-size: 13px; line-height: 1.6; color: var(--gray-600); margin: 0 0 14px; max-width: 74ch; }
    .ng-items        { list-style: none; margin: 0; padding: 0; }
    .ng-item         { padding: 14px 0 15px; border-top: 1px solid var(--gray-200); }
    .ng-item-head    { display: flex; align-items: baseline; gap: 9px; margin-bottom: 6px; }
    .ng-item-head h4 { font-size: 13.5px; font-weight: 600; color: var(--gray-900); margin: 0; line-height: 1.4; }
    .ng-kind         { flex-shrink: 0; font-size: 10.5px; padding: 2px 8px; border-radius: 999px; font-weight: 600; }
    .ng-kind-rule    { background: rgba(66,44,112,.09); color: var(--purple-300); }
    .ng-kind-trap    { background: rgba(247,148,31,.16); color: #9a5b06; }
    .ng-body         { font-size: 13px; line-height: 1.65; color: var(--gray-700); margin: 0; max-width: 78ch; }
    .ng-note, .ng-cost { font-size: 12.5px; line-height: 1.6; color: var(--gray-700); margin: 8px 0 0; max-width: 78ch; }
    .ng-cost         { color: var(--gray-600); }
    .ng-note-lbl     { display: inline-block; margin-right: 7px; font-size: 11px; font-weight: 600; color: var(--gray-500); }
    .ng-see          { font-size: 11.5px; color: var(--gray-500); margin: 8px 0 0; }
    .ng-item code, .ng-body code, .ng-note code, .ng-cost code, .ng-see code, .ng-div code {
                       font-family: 'IBM Plex Mono', monospace; font-size: 11.5px; color: var(--purple-300);
                       background: rgba(66,44,112,.06); padding: 1px 5px; border-radius: 4px; word-break: break-word; }
    .ng-div          { padding: 12px 0 4px; border-top: 1px solid var(--gray-200); }
    .ng-div h4       { font-size: 13px; font-weight: 600; color: var(--gray-900); margin: 0 0 7px; }
    .ng-div p        { font-size: 12.5px; line-height: 1.6; color: var(--gray-700); margin: 0 0 6px; max-width: 78ch; }
    @media (max-width: 768px) {
      .ng-actions    { width: 100%; }
      .ng-chapter    { padding: 16px 15px 6px; }
    }
    .ib-raw { background: var(--gray-100); border: 1px solid var(--gray-200); border-radius: 6px; padding: 12px; font-size: 11px; font-family: 'IBM Plex Mono', monospace; color: var(--gray-800); max-height: 480px; overflow: auto; margin-top: 10px; line-height: 1.5; }
    .ib-hint pre { background: var(--gray-100); border: 1px solid var(--gray-200); border-radius: 6px; padding: 10px 14px; font-size: 12px; font-family: 'IBM Plex Mono', monospace; color: var(--gray-800); overflow-x: auto; margin: 0; }

    /* Events / Donors page header (with action button) */
    .events-header-row { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 22px; gap: 16px; }
    .events-header-row h2 { font-size: 20px; font-weight: 500; color: var(--purple-300); letter-spacing: -.01em; }
    .events-header-row p  { color: var(--gray-600); font-size: 13px; margin-top: 3px; }

    /* Modal */
    .modal-backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.5); display: flex; align-items: center; justify-content: center; z-index: 1000; padding: 24px 24px calc(24px + env(safe-area-inset-bottom)) 24px; }
    .modal-card { background: var(--white); border-radius: 12px; width: 100%; max-width: 640px; max-height: min(calc(100dvh - 48px), calc(100vh - 48px)); overflow-y: auto; box-shadow: 0 32px 80px rgba(0,0,0,.4); }
    /* Add Team Member — create-new form. Tight grid, no inline styles per
       field so the form reads consistently and fits without scroll on
       average screens. */
    .add-person-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 10px; }
    .apg-field       { display: flex; flex-direction: column; min-width: 0; }
    /* .apg-grid was used by the Edit cohort and Create cohort modals for two
       years with NO RULE BEHIND IT (found 2026-08-31): every field fell into
       one full-width column and `.apg-full` did nothing, which is what made
       those forms feel like a list rather than a form. Same two columns as
       .add-person-grid, and a little more air between rows because these
       fields carry helper text under them. */
    .apg-grid        { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 12px; align-items: start; }
    @media (max-width: 600px) { .apg-grid { grid-template-columns: 1fr; } }
    .apg-full        { grid-column: 1/-1; }
    .apg-lbl         { font-size: 11px; color: var(--gray-700); font-weight: 600; margin-bottom: 3px; }
    .apg-req         { color: #b91c1c; margin-left: 3px; }
    .apg-input       { width: 100%; padding: 6px 9px; border: 1px solid var(--gray-300); border-radius: 6px; font-size: 13px; font-family: inherit; box-sizing: border-box; background: var(--white); }
    .apg-input:focus { outline: none; border-color: var(--purple-300); box-shadow: 0 0 0 3px rgba(66,44,112,.10); }
    .apg-toggle      { flex: 1; padding: 6px 10px; border-radius: 6px; font-size: 13px; font-weight: 600; font-family: inherit; cursor: pointer; border: 1.5px solid var(--gray-300); background: var(--white); color: var(--gray-700); transition: border-color .12s, background .12s, color .12s; }
    .apg-toggle:hover { border-color: var(--purple-300); color: var(--purple-300); }
    .apg-toggle.on   { border-color: var(--purple-300); background: rgba(66,44,112,.10); color: var(--purple-300); }
    /* SearchableCombobox — typeahead picker for People-link fields */
    .sc-root         { position: relative; }
    .sc-control      { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-height: 36px; padding: 4px 6px; border: 1px solid var(--gray-300); border-radius: 6px; background: var(--white); cursor: text; }
    .sc-control.focus { border-color: var(--purple-300); box-shadow: 0 0 0 3px rgba(66,44,112,.10); }
    .sc-chip         { display: inline-flex; align-items: center; gap: 4px; background: rgba(66,44,112,.10); color: var(--purple-300); font-size: 12px; font-weight: 600; padding: 2px 4px 2px 8px; border-radius: 99px; }
    .sc-chip-x       { background: none; border: 0; cursor: pointer; color: var(--purple-300); font-size: 14px; line-height: 1; padding: 0 4px; }
    .sc-input        { flex: 1; min-width: 80px; border: 0; outline: none; padding: 4px 6px; font-size: 13px; font-family: inherit; background: transparent; }
    .sc-pop          { position: absolute; top: calc(100% + 4px); left: 0; right: 0; max-height: 220px; overflow-y: auto; background: var(--white); border: 1px solid var(--gray-300); border-radius: 6px; box-shadow: 0 6px 24px rgba(0,0,0,.12); z-index: 1300; }
    .sc-opt          { padding: 7px 10px; font-size: 13px; cursor: pointer; color: var(--gray-900); }
    .sc-opt:hover, .sc-opt.hl { background: rgba(66,44,112,.08); }
    .sc-opt.sel      { font-weight: 600; color: var(--purple-300); }
    .sc-msg          { padding: 8px 10px; font-size: 12px; color: var(--gray-500); font-style: italic; }
    .modal-header { padding: 20px 24px; border-bottom: 1px solid var(--gray-200); display: flex; justify-content: space-between; align-items: center; }
    .modal-header h3 { font-size: 16px; font-weight: 500; color: var(--purple-300); }
    .modal-close { background: none; border: none; cursor: pointer; color: var(--gray-500); padding: 4px; font-size: 20px; line-height: 1; transition: color .12s; }
    .modal-close:hover { color: var(--gray-900); }
    .modal-body { padding: 22px 24px; }
    .modal-footer { padding: 16px 24px; border-top: 1px solid var(--gray-200); display: flex; gap: 10px; justify-content: flex-end; align-items: center; }
    .form-row { margin-bottom: 16px; }
    .form-label { display: block; font-size: 12px; font-weight: 500; color: var(--gray-700); margin-bottom: 6px; letter-spacing: .05em; font-family: "IBM Plex Mono", monospace; }
    .form-input-full { width: 100%; padding: 9px 12px; border: 1.5px solid var(--gray-300); border-radius: 6px; font-size: 13px; font-family: inherit; }
    .form-input-full:focus { outline: none; border-color: var(--purple-300); }
    .form-help { font-size: 11px; color: var(--gray-500); margin-top: 4px; }

    /* CSV preview table */
    .csv-preview-wrap { background: var(--gray-100); border: 1px solid var(--gray-200); border-radius: 6px; max-height: 220px; overflow: auto; margin-top: 4px; }
    .csv-preview-wrap table { width: 100%; border-collapse: collapse; font-size: 11px; font-family: "IBM Plex Mono", monospace; }
    .csv-preview-wrap th { background: var(--white); padding: 6px 10px; text-align: left; font-weight: 600; color: var(--gray-700); border-bottom: 1px solid var(--gray-200); position: sticky; top: 0; }
    .csv-preview-wrap td { padding: 4px 10px; border-bottom: 1px solid var(--gray-200); color: var(--gray-700); white-space: nowrap; max-width: 140px; overflow: hidden; text-overflow: ellipsis; }
    .csv-count-badge  { display: inline-block; font-size: 11px; padding: 3px 8px; background: var(--orange-300); color: var(--white); border-radius: 99px; font-weight: 600; margin-left: 8px; }

    /* Submit progress */
    .submit-progress { display: flex; flex-direction: column; gap: 6px; margin: 16px 0; padding: 14px; background: var(--gray-100); border-radius: 8px; }
    .submit-step { display: flex; align-items: center; gap: 10px; font-size: 12px; color: var(--gray-500); }
    .submit-step.active { color: var(--purple-300); }
    .submit-step.done   { color: #22c55e; }
    .submit-step::before { content: "○"; font-size: 14px; }
    .submit-step.active::before { content: "⏵"; }
    .submit-step.done::before   { content: "✓"; }
    .submit-error   { padding: 10px 14px; background: #FEF2F2; border: 1px solid #FCA5A5; border-radius: 6px; color: #DC2626; font-size: 12px; }
    .submit-success { padding: 10px 14px; background: #F0FDF4; border: 1px solid #86EFAC; border-radius: 6px; color: #16A34A; font-size: 12px; }

    .file-drop { border: 2px dashed var(--purple-300); border-radius: 10px; padding: 28px 20px; text-align: center; background: var(--white); cursor: pointer; transition: border-color .12s, background .12s, transform .12s; display: flex; flex-direction: column; align-items: center; gap: 4px; }
    .file-drop:hover { border-color: var(--orange-300); background: rgba(247,148,31,.05); }
    .file-drop input[type=file] { display: none; }
    .file-drop-icon { font-size: 28px; line-height: 1; margin-bottom: 4px; opacity: .9; }
    .file-drop p    { margin: 0; font-size: 14px; font-weight: 600; color: var(--gray-800); }
    .file-drop small { display: block; margin-top: 4px; color: var(--gray-600); font-size: 11px; }

    .link-button { background: none; border: none; padding: 0; color: var(--purple-300); font-family: inherit; font-size: 12px; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
    .link-button:hover { color: var(--orange-400); }

    /* Sublevel tool pages (people list / cohort / cert / lead / etp / etc.) */
    .tool-back            { background: none; border: none; cursor: pointer; font-size: 13px; color: var(--purple-300); display: inline-flex; align-items: center; gap: 6px; padding: 0 0 18px; font-family: inherit; }
    .tool-back:hover      { color: var(--orange-400); }
    .tool-title           { font-size: 20px; font-weight: 700; color: var(--gray-900); margin-bottom: 4px; }
    .tool-sub             { font-size: 13px; color: var(--gray-500); margin-bottom: 20px; }
    .tool-placeholder     { text-align: center; padding: 48px 24px; color: var(--gray-500); }
    .tool-placeholder-icon{ font-size: 36px; margin-bottom: 12px; }
    .tool-placeholder h3  { font-size: 16px; font-weight: 600; color: var(--gray-700); margin: 0 0 8px; }
    .tool-placeholder p   { font-size: 13px; margin: 0; }
    .people-list-item     { padding: 9px 2px; border-bottom: 1px solid var(--gray-100); font-size: 13px; color: var(--gray-800); }
    .people-list-item:last-child { border-bottom: none; }
    .tool-page-btn        { background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 6px; padding: 5px 14px; font-size: 12px; cursor: pointer; color: var(--gray-700); }
    .tool-page-btn:hover  { background: var(--gray-100); }

    /* Sublevel page chart section (Entries over time) */
    .chart-section        { background: var(--white); border: 1px solid var(--gray-300); border-radius: 12px; padding: 20px 24px 16px; margin-top: 20px; margin-bottom: 24px; }
    .chart-section-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 16px; }
    .chart-section-title  { font-weight: 600; font-size: 15px; color: var(--gray-900); margin-right: 8px; }
    .chart-section-note   { font-size: 12px; color: var(--gray-500); display: block; margin-top: 2px; }
    .chart-filters        { display: flex; gap: 4px; flex-shrink: 0; }
    .chart-stats-row      { display: flex; gap: 24px; margin-bottom: 14px; flex-wrap: wrap; }
    .chart-stat           { display: flex; flex-direction: column; }
    .chart-stat-val       { font-size: 22px; font-weight: 700; color: var(--gray-900); line-height: 1.1; font-family: "IBM Plex Mono", monospace; }
    .chart-stat-lbl       { font-size: 11px; color: var(--gray-500); letter-spacing: .04em; margin-top: 2px; }
    .chart-wrap           { position: relative; height: 180px; }
    /* The weekly comms chart carries six series, two axes and a dot per send, so
       180px squeezes it (Arnold, 2026-08-27: "feel free to make the Weekly
       Activity chart more height"). A modifier rather than a change to the shared
       height, which four other charts read. */
    .chart-wrap.tall      { height: 340px; }
    @media (max-width: 768px) { .chart-wrap.tall { height: 260px; } }
    .chart-loading        { color: var(--gray-500); font-size: 13px; padding: 40px 0; text-align: center; }

    /* Conversion-rate table (sublevel pages) */
    .conv-table { width: 100%; border-collapse: collapse; font-size: 12px; }
    .conv-table thead th { padding: 0 8px 8px; border-bottom: 1px solid var(--gray-200); text-align: left; font-size: 11px; font-weight: 600; letter-spacing: .06em; color: var(--gray-500); }
    .conv-table thead th.r { text-align: right; }
    .conv-table thead th.rate-col { text-align: right; color: var(--gray-400); font-style: italic; font-weight: 500; letter-spacing: 0; text-transform: none; font-size: 11px; }
    .conv-table tbody tr:hover td { background: var(--gray-100); }
    .conv-table tbody td { padding: 7px 8px; border-bottom: 1px solid var(--gray-100); vertical-align: middle; white-space: nowrap; }
    .conv-table tbody tr:last-child td { border-bottom: none; }
    .conv-table .conv-week { font-family: "IBM Plex Mono", monospace; font-size: 11px; color: var(--gray-500); }
    .conv-table .conv-num  { text-align: right; font-family: "IBM Plex Mono", monospace; font-weight: 600; color: var(--gray-800); }
    .conv-table .conv-num.zero { color: var(--gray-300); }
    .conv-table .conv-rate { text-align: right; font-size: 11px; }
    .conv-table .conv-rate span { display: inline-block; padding: 1px 5px; border-radius: 3px; font-family: "IBM Plex Mono", monospace; }
    .conv-table .conv-rate .rate-hi  { background: #f0fdf4; color: #15803d; }
    .conv-table .conv-rate .rate-mid { background: #fffbeb; color: #b45309; }
    .conv-table .conv-rate .rate-lo  { background: var(--gray-100); color: var(--gray-500); }
    .conv-table .conv-total-row td { background: var(--gray-100); font-weight: 700; border-top: 2px solid var(--gray-200); }
    .conv-table .conv-total-row .conv-week { color: var(--gray-700); font-weight: 700; font-family: inherit; }

    /* Multi-Level Enrollment row (StudentFlow) */
    .mle-row { cursor: pointer; }
    .mle-row:hover .mle-bar { filter: brightness(.88); transition: filter .1s; }

    /* Tables */
    .data-table { width: 100%; border-collapse: collapse; background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 10px; overflow: hidden; }
    /* People list: fixed column widths so filter typing doesn't reflow the layout. */
    .data-table.fixed-layout { table-layout: fixed; }
    .data-table.fixed-layout td, .data-table.fixed-layout th { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    /* Color chip for ContactPerson — distinct hue per unique value. */
    .contact-chip { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 500; line-height: 1.5; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: middle; }
    /* Primary-contact badge — small orange pill in the same family as
       .badge-new, so it reads as part of the CRM's existing chip system
       rather than a free-floating yellow star. */
    .primary-badge {
      display: inline-flex;
      align-items: center;
      gap: 3px;
      padding: 1px 7px 1px 6px;
      margin-right: 6px;
      border-radius: 99px;
      background: rgba(247, 148, 31, .14);
      color: var(--orange-400);
      font-family: "IBM Plex Mono", monospace;
      font-size: 9px;
      font-weight: 600;
      letter-spacing: .06em;
      text-transform: uppercase;
      vertical-align: 1px;
      line-height: 1.4;
      white-space: nowrap;
    }
    .primary-badge svg { display: block; }
    .primary-star {
      display: inline-flex;
      align-items: center;
      margin-left: 6px;
      color: var(--orange-400);
      vertical-align: 1px;
    }
    .primary-star svg { display: block; }
    .data-table th { padding: 8px 14px; text-align: left; font-size: 11px; letter-spacing: .06em; color: var(--gray-600); background: var(--gray-100); border-bottom: 1.5px solid var(--gray-200); }
    .data-table td { padding: 10px 14px; border-bottom: 1px solid var(--gray-200); font-size: 13px; }
    .data-table tr:last-child td { border-bottom: none; }
    .data-table tbody tr:nth-child(even) td { background: rgba(0,0,0,.015); }
    .data-table tr:hover td { background: var(--gray-100); }

    /* Supporters: small variations on .data-table — accent strip + chips */
    .sup-table-wrap { border-radius: 10px; overflow: hidden; box-shadow: 0 1px 0 rgba(0,0,0,.02); }
    .sup-table-wrap > .data-table { border-radius: 0; border-top: none; }
    .sup-chip { display: inline-block; font-size: 11px; padding: 2px 7px; border-radius: 999px; background: var(--gray-100); color: var(--gray-800); border: 1px solid var(--gray-200); margin: 1px 3px 1px 0; }
    .sup-tg { display: inline-block; font-family: 'IBM Plex Mono', monospace; font-size: 11px; padding: 2px 7px; border-radius: 4px; background: rgba(14,165,233,.10); color: #0369a1; }
    .sup-row { cursor: pointer; transition: background .12s; }
    .sup-row:hover { background: var(--gray-100); }
    .sup-row:focus-visible { outline: 2px solid var(--purple-300); outline-offset: -2px; }
    .sup-row .sup-name { color: var(--purple-300); font-weight: 500; }
    .sup-row:hover .sup-name { color: var(--purple-400); text-decoration: underline; }

    /* Level bar */
    .level-bar-wrap { margin-bottom: 10px; }
    .level-bar-header { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 5px; font-size: 12px; }
    .level-bar-title { font-weight: 500; color: var(--gray-800); }
    .level-bar-count { color: var(--gray-600); font-variant-numeric: tabular-nums; }
    .level-bar-track { height: 6px; background: var(--gray-200); border-radius: 99px; overflow: hidden; }
    .level-bar-fill  { height: 100%; border-radius: 99px; transition: width .4s; }

    /* Buttons */
    .btn { display: inline-flex; align-items: center; gap: 6px; padding: 7px 16px; border-radius: 6px; font-size: 13px; font-weight: 500; cursor: pointer; border: none; font-family: inherit; transition: background .12s; }
    /* The transparent border is load-bearing, not decoration. `.btn` sets
       `border: none`, while `.btn-secondary` and `.btn-danger` both add a
       1.5px one, so a primary button rendered 2px SHORTER than any secondary
       button standing next to it. Measured on the agenda toolbar 2026-08-11:
       primary 31px, secondary and the select both 33px. Matching the border
       width here fixes the mismatch everywhere rather than per-toolbar. */
    .btn-primary { background: var(--purple-300); color: var(--white); border: 1.5px solid transparent; }
    .btn-primary:hover { background: var(--purple-400); }
    .btn-secondary { background: var(--white); color: var(--gray-800); border: 1.5px solid var(--gray-300); }
    .btn-secondary:hover { background: var(--gray-100); }

    /* Badge */
    .badge { display: inline-block; padding: 2px 8px; border-radius: 99px; font-size: 11px; font-weight: 500; }
    .badge-new { background: rgba(247,148,31,.15); color: var(--orange-400); }
    .badge-role { background: var(--gray-200); color: var(--gray-700); }

    /* Loading */
    .loading-dots { display: flex; gap: 4px; align-items: center; color: var(--gray-500); font-size: 13px; }
    .loading-dots::after { content: ""; display: inline-block; width: 6px; height: 6px; background: var(--gray-400); border-radius: 50%; animation: pulse 1.2s infinite; }
    @keyframes pulse { 0%,100%{opacity:.4} 50%{opacity:1} }
    /* Sidebar nav pulse — indicates fresh activity in a section. Brand orange. */
    .nav-pulse { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: rgba(255,255,255,.55); margin-left: auto; flex-shrink: 0; box-shadow: 0 0 0 0 rgba(255,255,255,.4); animation: nav-pulse-ring 1.6s infinite; }
    @keyframes nav-pulse-ring { 0% { box-shadow: 0 0 0 0 rgba(255,255,255,.4); } 70% { box-shadow: 0 0 0 8px rgba(255,255,255,0); } 100% { box-shadow: 0 0 0 0 rgba(255,255,255,0); } }
    /* Report page (printable admin overview) */
    .report-page         { max-width: 1100px; }
    .report-cover        { border-bottom: 2px solid var(--purple-300); padding-bottom: 14px; margin-bottom: 24px; }
    .report-cover h1     { font-size: 26px; font-weight: 600; color: var(--purple-300); letter-spacing: -.01em; margin-bottom: 4px; }
    .report-cover-meta   { font-size: 12px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; }
    .report-section      { background: var(--white); border: 1px solid var(--gray-300); border-radius: 10px; padding: 18px 22px; margin-bottom: 18px; page-break-inside: avoid; }
    .report-section-h    { font-size: 13px; font-weight: 600; color: var(--purple-300); letter-spacing: .07em; font-family: "IBM Plex Mono", monospace; margin-bottom: 14px; }
    .report-grid         { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
    .report-kv           { background: var(--gray-100); border: 1px solid var(--gray-200); border-radius: 8px; padding: 10px 14px; }
    .report-kv-label     { font-size: 10px; font-weight: 600; color: var(--gray-600); letter-spacing: .05em; font-family: "IBM Plex Mono", monospace; }
    .report-kv-val       { font-size: 22px; font-weight: 600; color: var(--purple-300); margin-top: 4px; line-height: 1.1; }
    .report-kv-sub       { font-size: 11px; color: var(--gray-600); margin-top: 2px; }
    .report-table        { width: 100%; border-collapse: collapse; font-size: 12px; }
    .report-table th, .report-table td { padding: 6px 10px; text-align: left; border-bottom: 1px solid var(--gray-200); }
    .report-table th     { font-size: 10px; letter-spacing: .05em; color: var(--gray-600); font-weight: 600; background: var(--gray-100); }
    .report-table tr:last-child td { border-bottom: none; }
    .report-table td.r, .report-table th.r { text-align: right; font-family: "IBM Plex Mono", monospace; }
    .report-footer       { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--gray-200); }
    @media print {
      .sidebar, .topbar, .no-print { display: none !important; }
      .app, .main { display: block !important; width: 100% !important; }
      .content { padding: 0 !important; }
      body, html, .app, .main, .content { background: white !important; }
      .report-page { max-width: none !important; }
      .report-section { background: transparent !important; border: none !important; padding: 0 !important; margin-bottom: 18px !important; page-break-inside: avoid; }
      .report-section-h { border-bottom: 1px solid var(--gray-300); padding-bottom: 4px; }
      .report-cover { page-break-after: avoid; }
      a { text-decoration: none !important; color: inherit !important; }
      @page { margin: 14mm 12mm; }
    }

    /* ── Mobile shell (≤768px) ───────────────────────────────────────────────
       CRM is used on phones during events. Default desktop layout (flex row,
       100vh, 290px sidebar) gets unusable: the sidebar eats most of the
       viewport and wide tables overflow without a way to scroll them.
       This block stacks the layout vertically, shrinks the sidebar to a
       slim top strip (header only — sidebar nav collapses), and turns
       .content into a horizontal-scroll container so wide tables remain
       readable via side-scroll instead of being clipped. Behavior on
       desktop is unaffected; print mode keeps its own override above. */
    @media (max-width: 768px) {
      .app { display: block; height: auto; overflow: visible; }
      /* Sidebar becomes an off-canvas drawer on mobile — slides in when
         .app.sidebar-open is set, backdrop closes it on tap. */
      .sidebar {
        position: fixed !important;
        top: 0; left: 0;
        width: 280px !important;
        height: 100dvh;
        max-height: 100dvh;
        overflow-y: auto;
        z-index: 60;
        transform: translateX(-100%);
        transition: transform .2s ease;
        flex-direction: column !important;
        border-top-width: 0;
      }
      .app.sidebar-open .sidebar { transform: translateX(0); }
      .sidebar-header { flex: none; padding: 14px 16px; border-bottom: 1px solid var(--gray-200); }
      .sidebar > .nav-section,
      .sidebar > .sidebar-footer { display: block; }
      .app.sidebar-open .sidebar-backdrop {
        display: block; position: fixed; inset: 0;
        background: rgba(0,0,0,.4); z-index: 55;
      }
      .main { width: 100%; height: auto; overflow: visible; }
      .topbar-hamburger {
        display: inline-flex; align-items: center; justify-content: center;
        min-width: 44px; min-height: 44px; padding: 8px 10px;
        background: none; border: none; cursor: pointer;
        color: var(--gray-700); flex-shrink: 0;
      }
      .topbar { padding: 8px 10px; gap: 8px; flex-wrap: wrap; }
      .topbar-search { flex: 1 1 100%; order: 99; }
      .content { padding: 12px 10px; overflow-x: auto; -webkit-overflow-scrolling: touch; }
      /* Tables: keep desktop structure, just let .content scroll horizontally
         when a wide row would clip. min-width nudges narrow tables to fill,
         max-width:none lets wide ones extend past the viewport. */
      .data-table { font-size: 12px; }
      .data-table td, .data-table th { padding: 8px 10px; }
      /* Grids that were 3-col on desktop drop to 1-col. Most stat-grids
         already wrap; this catches the few that hard-code grid-template. */
      .stat-grid, .stat-grid--static { grid-template-columns: 1fr !important; }
      .events-header-row { flex-wrap: wrap; gap: 8px; }
      .modal-card { width: 95vw !important; max-width: 95vw !important; padding-bottom: env(safe-area-inset-bottom); }
      /* FIX 1 — iOS Safari auto-zooms on focus for inputs < 16px.
         Bumping to 16px on mobile removes the jump. */
      input, textarea, select,
      .form-input, .form-input-full,
      .msghub-input, .msghub-select, .msghub-textarea,
      .topbar-search input { font-size: 16px !important; }
      /* FIX 4 — comfortable touch targets. */
      .btn { min-height: 44px; padding: 10px 18px; font-size: 14px; }
      .btn-small { min-height: 36px; padding: 8px 14px; font-size: 13px; }
      .modal-close { width: 44px; height: 44px; font-size: 24px; padding: 0; display: inline-flex; align-items: center; justify-content: center; }
      /* FIX 10 — bump micro-typography just enough for outdoor legibility. */
      .stat-label, .cohort-type-chip, .cohort-program-chip,
      .contact-chip, .primary-badge, .sup-chip, .sup-tg { font-size: 12px; }
      .data-table { font-size: 13px; }
      .data-table th { font-size: 12px; }
      /* Keep the first column visible while the row scrolls sideways —
         users can't otherwise tell which row they're reading. */
      .data-table td:first-child,
      .data-table th:first-child {
        position: sticky; left: 0; z-index: 1;
        background: var(--white);
        box-shadow: 2px 0 0 var(--gray-200);
      }
      /* FIX 3 — Cohort Builder 3-col grid collapses. */
      .cohort-builder-grid { grid-template-columns: 1fr !important; }
      .cohort-builder-grid > div { height: auto !important; max-height: 60vh !important; min-height: 240px !important; }
      /* FIX 5 — AddInvitees bucket grid collapses. */
      .add-invitees-buckets { grid-template-columns: 1fr !important; }
      /* Generic 2-col helper — for edit-form field pairs across the CRM. */
      .grid-2col { grid-template-columns: 1fr !important; }
    }
    /* Extracted grid classes so future features have a mobile-safe default
       instead of inline grid-template-columns. See feedback_crm_mobile_friendliness. */
    .cohort-builder-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 16px; align-items: start; }
    @media (max-width: 900px) {
      .cohort-builder-grid { grid-template-columns: 1fr; }
      .cohort-builder-grid > div { height: auto !important; max-height: 60vh !important; min-height: 260px !important; }
    }
    .add-invitees-buckets { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; padding: 2px; align-items: start; }
    @media (max-width: 720px) { .add-invitees-buckets { grid-template-columns: 1fr; } }
    /* Registrations ETP modal — always-expanded applicant cards side by side. */
    /* Masonry via CSS columns, not Grid. Grid rows are as tall as their
       tallest cell, so one applicant with a long answer left a gap under every
       short card beside it and the raggedness propagated down the whole modal
       (Arnold, 2026-08-10). `align-items:start` stopped the short cards
       STRETCHING but could not close the gap — that is the row model itself.
       Columns pack each card directly under the one above it.
       Trade-off, accepted: reading order becomes column-major (down the first
       column, then the second) rather than left-to-right. Fine for a review
       queue where the cards are independent; it would be wrong for a ranked
       list. `break-inside:avoid` is what stops a card being split across a
       column boundary. */
    .applicants-grid { column-width: 300px; column-gap: 10px; padding: 2px; }
    .applicants-grid > * { break-inside: avoid; -webkit-column-break-inside: avoid; page-break-inside: avoid; width: 100%; margin-bottom: 10px; }
    @media (max-width: 640px) { .applicants-grid { column-width: auto; column-count: 1; } }
    .grid-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
    @media (max-width: 600px) { .grid-2col { grid-template-columns: 1fr; } }
    .survey-ratings-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 6px; }
    @media (max-width: 900px) { .survey-ratings-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
    @media (max-width: 500px) { .survey-ratings-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
    /* Network Dashboard tabs (People / Communities) */
    .network-tabs        { display: flex; gap: 0; border-bottom: 1.5px solid var(--gray-300); margin-bottom: 22px; }
    .network-tab         { padding: 10px 22px; cursor: pointer; background: none; border: none; border-bottom: 2px solid transparent; margin-bottom: -1.5px; font-family: inherit; font-size: 13px; font-weight: 500; color: var(--gray-600); transition: color .12s, border-color .12s; }
    .network-tab:hover   { color: var(--gray-900); }
    .network-tab.active  { color: var(--purple-300); border-bottom-color: var(--purple-300); font-weight: 600; }

    /* Site-wide filter bar (mounted below Topbar on filter-aware pages) */
    .global-filter-bar    { display: flex; align-items: center; gap: 44px; flex-wrap: wrap; padding: 10px 32px; background: var(--white); border-bottom: 1px solid var(--gray-300); flex-shrink: 0; }
    .impact-toolbar-group { display: flex; align-items: center; gap: 6px; }
    .impact-toolbar-label { font-size: 10px; font-weight: 700; color: var(--gray-900); letter-spacing: .07em; font-family: "IBM Plex Mono", monospace; margin-right: 8px; }

    /* Latest Cohorts table + Top Countries/Languages + Cohort Detail */
    .row-click            { cursor: pointer; transition: background .12s; }
    .row-click:hover      { background: var(--gray-100); }
    .cohort-type-chip     { display: inline-block; font-size: 10px; padding: 2px 8px; background: var(--gray-100); border: 1px solid var(--gray-300); border-radius: 99px; font-family: "IBM Plex Mono", monospace; color: var(--gray-700); white-space: nowrap; font-weight: 500; letter-spacing: .03em; }
    .cohort-type-chip[data-type="Online"]     { background: rgba(14,165,233,.10);  color: #0369a1; border-color: rgba(14,165,233,.30); }
    .cohort-type-chip[data-type="In-person"]  { background: rgba(34,197,94,.10);   color: #15803d; border-color: rgba(34,197,94,.30); }
    .cohort-type-chip[data-type="Self-Paced"] { background: rgba(168,85,247,.10);  color: #7e22ce; border-color: rgba(168,85,247,.30); }
    /* Program tag — ITB / BD / ETP get level-palette tints. */
    .cohort-program-chip { display: inline-block; font-size: 10px; font-weight: 600; padding: 2px 8px; border-radius: 99px; font-family: "IBM Plex Mono", monospace; letter-spacing: .04em; white-space: nowrap; border: 1px solid; }
    .cohort-program-chip[data-program="ITB"] { background: rgba(247,148,31,.12); color: #c2570a; border-color: rgba(247,148,31,.40); }
    .cohort-program-chip[data-program="BD"]  { background: rgba(251,176,64,.14); color: #b45309; border-color: rgba(251,176,64,.45); }
    .cohort-program-chip[data-program="ETP"] { background: rgba(94,55,142,.12);  color: var(--l4); border-color: rgba(94,55,142,.35); }
    .cohort-program-chip[data-program="B4J"] { background: rgba(14,165,233,.12);  color: #0369a1; border-color: rgba(14,165,233,.40); }
    /* Testimonial accordion list — one row per submission, click-to-expand. */
    .testimonial-row { background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 10px; overflow: hidden; transition: border-color .12s, box-shadow .12s; }
    .testimonial-row:hover { border-color: var(--gray-300); }
    .testimonial-row.open { border-color: var(--purple-300); box-shadow: 0 2px 10px rgba(66,44,112,.08); }
    .testimonial-row-summary { width: 100%; display: flex; align-items: center; gap: 14px; padding: 12px 16px; background: transparent; border: 0; cursor: pointer; font-family: inherit; transition: background .12s; }
    .testimonial-row-summary:hover { background: var(--gray-100); }
    .testimonial-row.open .testimonial-row-summary { background: rgba(66,44,112,.04); border-bottom: 1px solid var(--gray-200); }
    .testimonial-row-summary:focus-visible { outline: 2px solid var(--orange-300); outline-offset: -2px; }
    .testimonial-chev { color: var(--gray-500); font-size: 12px; line-height: 1; flex-shrink: 0; transition: transform .15s, color .12s; }
    .testimonial-row.open .testimonial-chev { transform: rotate(180deg); color: var(--purple-300); }
    .testimonial-row-detail { padding: 18px 22px 22px; }
    /* Two-column grid: left = full photo + CTA, right = metadata + quotes.
       Collapses to single column on narrow screens. */
    .testimonial-detail-grid { display: grid; grid-template-columns: 220px 1fr; gap: 24px; align-items: start; }
    @media (max-width: 720px) { .testimonial-detail-grid { grid-template-columns: 1fr; gap: 18px; } }
    .testimonial-detail-aside { display: flex; flex-direction: column; }
    .testimonial-detail-photo { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 10px; border: 1.5px solid var(--gray-200); display: block; }
    .testimonial-detail-photo-empty { background: linear-gradient(135deg, var(--orange-300), var(--orange-400)); display: flex; align-items: center; justify-content: center; }
    .testimonial-detail-main { min-width: 0; }
    /* Cohort title cell — no truncation; the row's full natural width. */
    .cohort-title-cell    { white-space: nowrap; font-weight: 600; padding-right: 18px; }
    /* Educator cell — wider min-width than other text columns. */
    .cohort-educator-cell { white-space: nowrap; min-width: 200px; font-size: 12px; color: var(--gray-700); }
    .td-twin              { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; align-items: start; margin-bottom: 28px; }
    @media (max-width: 900px) { .td-twin { grid-template-columns: 1fr; } }
    .td-twin-col          { min-width: 0; }
    .top-list td          { padding: 8px 14px !important; vertical-align: middle; }
    .top-list .top-list-row { display: flex; align-items: center; gap: 12px; min-width: 0; }
    .top-list-name        { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 0 0 150px; }
    .top-list-bar-wrap    { flex: 1; min-width: 24px; height: 6px; background: rgba(94,55,142,.08); border-radius: 3px; overflow: hidden; }
    .top-list .top-list-bar { display: block; height: 100%; background: var(--purple-200); border-radius: 3px; opacity: .55; }
    .cohort-edu-chip      { display: inline-flex; align-items: center; gap: 4px; padding: 5px 12px; background: rgba(239,123,0,.1); color: #EF7B00; border: 1px solid rgba(239,123,0,.25); border-radius: 99px; font-size: 12px; font-weight: 600; }
    .cohort-status-block  { background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 10px; padding: 14px 18px; margin-bottom: 12px; }
    .cohort-status-head   { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; color: var(--gray-800); margin-bottom: 10px; }
    .cohort-status-dot    { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
    .cohort-status-count  { margin-left: auto; font-family: "IBM Plex Mono", monospace; font-size: 12px; color: var(--gray-600); }
    .cohort-copy-emails   { display: inline-flex; align-items: center; gap: 4px; margin-left: 6px; color: var(--gray-400); cursor: pointer; vertical-align: middle; transition: color .12s; }
    .cohort-copy-emails:hover { color: var(--orange-400); }
    .cohort-copy-done     { font-size: 11px; font-weight: 600; color: #15803d; font-family: "IBM Plex Mono", monospace; }
    .cohort-copy-empty    { font-size: 11px; font-weight: 500; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; }
    .cohort-status-empty  { font-size: 12px; color: var(--gray-400); font-style: italic; }
    .cohort-status-list   { display: flex; flex-wrap: wrap; gap: 6px; }
    .cohort-student-chip  { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; background: var(--gray-100); border: 1px solid var(--gray-200); border-radius: 6px; font-size: 12px; color: var(--gray-800); }
    .cohort-student-list  { display: flex; flex-direction: column; gap: 4px; }
    .cohort-student-row   { padding: 6px 10px; background: var(--gray-100); border: 1px solid var(--gray-200); border-radius: 6px; font-size: 13px; color: var(--gray-800); }

    /* Community profile — header (logo + title), split (cards | map), trio cards */
    .comm-header     { display: flex; align-items: center; gap: 16px; margin-bottom: 22px; }
    .comm-logo       { width: 76px; height: 76px; border-radius: 12px; object-fit: cover; border: 1.5px solid var(--gray-200); flex-shrink: 0; }
    .comm-logo-placeholder { display: flex; align-items: center; justify-content: center; background: var(--purple-300); color: #fff; font-size: 24px; font-weight: 700; }
    /* Person-detail avatar — same rounded-square shape as .comm-logo.
       Wrapped in an anchor (target=_blank) so team members can open the
       full-size image to investigate. */
    .person-avatar        { width: 56px; height: 56px; border-radius: 12px; object-fit: cover; border: 1.5px solid var(--gray-200); flex-shrink: 0; display: block; }
    .person-avatar-btn    { padding: 0; border: 0; background: none; cursor: zoom-in; flex-shrink: 0; display: inline-flex; }
    .person-avatar-btn:hover .person-avatar { border-color: var(--purple-300); }
    /* Initial-letter placeholder when a Person has no ProfilePicture on
       file — mirrors .comm-logo-placeholder used on Community Detail. */
    .person-avatar-placeholder { display: flex; align-items: center; justify-content: center; background: var(--purple-300); color: #fff; font-size: 20px; font-weight: 700; font-family: 'IBM Plex Mono', monospace; letter-spacing: 0; }
    /* Sub-line under the person's name — mirrors .comm-header-sub for
       occupation / secondary identity chips. */
    .person-header-sub    { font-size: 13px; color: var(--gray-600); margin-top: 4px; line-height: 1.3; }
    .comm-header-info { min-width: 0; display: flex; flex-direction: column; justify-content: center; }
    .comm-header-name { font-size: 24px; font-weight: 700; color: var(--gray-900); letter-spacing: -0.01em; line-height: 1.2; margin: 0; }
    .comm-header-sub  { font-size: 14px; color: var(--gray-600); margin-top: 6px; line-height: 1.3; }
    .comm-split      { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; align-items: start; margin-bottom: 28px; }
    @media (max-width: 980px) { .comm-split { grid-template-columns: 1fr; } }
    .comm-split-left { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
    .comm-split-right { min-width: 0; display: flex; flex-direction: column; gap: 14px; }
    /* Leaflet sets z-index up to 1000 on its tile/control panes, which would
       otherwise paint on top of the topbar's search dropdown and notification
       popover (both at z-index 100/1200). `isolation: isolate` makes the map
       its own stacking context so Leaflet's z-indexes can't escape this box. */
    .comm-map        { width: 100%; height: 200px; border-radius: 10px; overflow: hidden; border: 1.5px solid var(--gray-200); isolation: isolate; }
    .comm-map-empty  { display: flex; align-items: center; justify-content: center; color: var(--gray-400); font-style: italic; font-size: 13px; background: var(--gray-100); }
    .comm-trio-card  { background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 10px; padding: 16px 18px; min-width: 0; display: flex; flex-direction: column; }
    /* Title-bar social icons — icon-only, leaderboard style: muted glyph that
       brightens to brand purple on hover. */
    .comm-social-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
    .comm-social-ico { display: inline-flex; align-items: center; justify-content: center; color: var(--gray-500); transition: color .12s, transform .12s; }
    .comm-social-ico:hover { color: var(--purple-300); transform: translateY(-1px); }
    /* Action Items page — threads (person/cohort/community) + their logs. */
    .ai-page { max-width: 920px; }
    .ai-intro { font-size: 13px; color: var(--gray-600); margin-bottom: 20px; }
    /* Action Items tabs reuse the app's .notif-tab look; .ai-tab only adds the
       inline layout for the count chip. Collapsible cards below. */
    .ai-tab { display: inline-flex; align-items: center; gap: 7px; }
    .ai-tab-count { font-size: 10px; font-weight: 700; background: var(--gray-200); color: var(--gray-600); border-radius: 99px; padding: 1px 6px; }
    .notif-tab.active .ai-tab-count { background: rgba(66,44,112,.12); color: var(--purple-300); }
    .ai-card { background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 10px; margin-bottom: 8px; overflow: hidden; }
    .ai-card.open { border-color: var(--gray-300); }
    /* "Coverage" community — the person is in charge of this community per
       ContactPerson, but no action items are logged for it yet. Dashed
       border + faint tint so the eye reads it as "still to do" without
       blending into the page background (which is also gray-100). */
    .ai-card.empty { background: rgba(234, 234, 244, .55); border: 1.5px dashed var(--gray-300); }
    .ai-card.empty .ai-card-head { cursor: default; }
    .ai-card.empty .ai-card-head:hover { background: transparent; }
    .ai-card.empty .ai-card-name { color: var(--gray-600); }
    .ai-card.empty .ai-card-caret { visibility: hidden; }
    /* Color legend at the bottom of the Action Items page. */
    .ai-legend { margin-top: 28px; padding: 14px 16px; background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 10px; }
    .ai-legend-title { font-size: 11px; font-weight: 700; color: var(--gray-700); letter-spacing: .07em; font-family: "IBM Plex Mono", monospace; margin-bottom: 10px; text-transform: uppercase; }
    .ai-legend-grid { display: flex; flex-wrap: wrap; gap: 10px 18px; }
    .ai-legend-item { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--gray-700); }
    .ai-legend-swatch { width: 14px; height: 14px; border-radius: 4px; border: 1.5px solid var(--gray-200); display: inline-block; }
    .ai-card-head { width: 100%; appearance: none; background: none; border: 0; display: flex; align-items: center; gap: 10px; padding: 12px 14px; cursor: pointer; font-family: inherit; text-align: left; }
    .ai-card-head:hover { background: var(--gray-100); }
    .ai-card-caret { color: var(--gray-400); font-size: 11px; width: 12px; flex-shrink: 0; }
    .ai-card-name { font-weight: 600; font-size: 13px; color: var(--gray-900); }
    .ai-card-tags { display: inline-flex; gap: 4px; flex-wrap: wrap; }
    .ai-card.open .ai-card-name { color: var(--purple-300); }
    .ai-card-body { border-top: 1px solid var(--gray-100); }
    .ai-goto-btn { display: inline-flex; align-items: center; gap: 6px; margin: 10px 14px 12px; padding: 6px 12px; font-size: 12px; font-weight: 600; color: var(--purple-300); background: rgba(66,44,112,.06); border: 1.5px solid var(--gray-300); border-radius: 6px; cursor: pointer; font-family: inherit; transition: border-color .12s, background .12s; }
    .ai-goto-btn:hover { border-color: var(--purple-300); background: rgba(66,44,112,.12); }
    .ai-section { margin-bottom: 28px; }
    .ai-empty { font-size: 13px; color: var(--gray-400); font-style: italic; padding: 6px 0; }
    .ai-filter-row { margin: -2px 0 12px; }
    .ai-filter { font-size: 12px; color: var(--gray-600); display: inline-flex; align-items: center; gap: 8px; }
    .ai-filter select { font-size: 12px; padding: 4px 8px; border: 1.5px solid var(--gray-300); border-radius: 6px; background: var(--white); font-family: inherit; }
    .ai-add-lead-btn { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; font-size: 12px; font-weight: 600; color: var(--white); background: var(--orange-400); border: 1.5px solid var(--orange-400); border-radius: 99px; cursor: pointer; font-family: inherit; transition: filter .12s, box-shadow .12s; flex-shrink: 0; }
    .ai-add-lead-btn:hover { filter: brightness(1.05); box-shadow: 0 1px 4px rgba(247,148,31,.3); }
    /* Sort: segmented two-button control, MFB conventions — uppercase mono label + a unified pill split into two halves with a divider between them. Active half = purple-300 fill, inactive = white. */
    .ai-sort-group { margin-left: auto; display: inline-flex; align-items: center; gap: 8px; padding-bottom: 6px; }
    .ai-sort-label { font-size: 10px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; letter-spacing: .08em; }
    .ai-sort-seg { display: inline-flex; border: 1.5px solid var(--gray-300); border-radius: 99px; overflow: hidden; background: var(--white); }
    .ai-sort-btn { background: none; border: 0; cursor: pointer; font-family: inherit; font-size: 12px; font-weight: 600; padding: 5px 12px; color: var(--gray-600); transition: background .12s, color .12s; }
    .ai-sort-btn + .ai-sort-btn { border-left: 1.5px solid var(--gray-300); }
    .ai-sort-btn:hover:not(.on) { background: var(--gray-100); color: var(--gray-800); }
    .ai-sort-btn.on { background: var(--purple-300); color: var(--white); }
    /* Skeleton loader — mirrors the filter row + card layout so the page
       doesn't jump when data lands. shimmer = background-position animation
       on a 3-stop linear gradient (gray-100 → gray-200 → gray-100). */
    @keyframes ai-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
    .ai-skeleton-filter { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
    .ai-skeleton-lbl,
    .ai-skeleton-pill,
    .ai-skeleton-caret,
    .ai-skeleton-count,
    .ai-skeleton-name,
    .ai-skeleton-date {
      background: linear-gradient(90deg, var(--gray-100) 0%, var(--gray-200) 50%, var(--gray-100) 100%);
      background-size: 200% 100%;
      animation: ai-shimmer 1.4s linear infinite;
      border-radius: 6px;
    }
    .ai-skeleton-lbl   { width: 110px; height: 12px; }
    .ai-skeleton-pill  { width: 64px;  height: 26px; border-radius: 99px; }
    .ai-skeleton-card  { display: flex; align-items: center; gap: 10px; padding: 12px 14px; background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 10px; margin-bottom: 8px; }
    .ai-skeleton-caret { width: 8px;   height: 8px;  border-radius: 50%; }
    .ai-skeleton-count { width: 24px;  height: 18px; border-radius: 99px; }
    .ai-skeleton-name  { height: 14px; flex: 1; }
    .ai-skeleton-name.w0 { max-width: 220px; }
    .ai-skeleton-name.w1 { max-width: 180px; }
    .ai-skeleton-name.w2 { max-width: 260px; }
    .ai-skeleton-name.w3 { max-width: 200px; }
    .ai-skeleton-date  { width: 72px;  height: 12px; }
    .ai-thread { background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 10px; margin-bottom: 10px; overflow: hidden; }
    .ai-thread-head { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-bottom: 1px solid var(--gray-100); font-weight: 600; font-size: 13px; color: var(--gray-900); }
    .ai-thread-head.row-click { cursor: pointer; }
    .ai-thread-head.row-click:hover { background: var(--gray-100); }
    .ai-thread-name { color: var(--purple-300); }
    .ai-thread-tags { font-size: 10px; font-weight: 500; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; text-transform: uppercase; letter-spacing: .04em; }
    .ai-thread-count { margin-left: auto; font-size: 11px; font-weight: 700; color: var(--gray-600); background: var(--gray-200); border-radius: 99px; padding: 1px 8px; font-family: "IBM Plex Mono", monospace; }
    .ai-thread-log { display: flex; flex-direction: column; gap: 8px; padding: 10px 14px; }
    .ai-note-toggle { font: inherit; color: var(--purple-300); background: none; border: 0; padding: 0; margin: 0; cursor: pointer; text-decoration: underline; font-weight: 600; }
    .ai-note-toggle:hover { color: var(--orange-300); }
    .comm-trio-title { font-size: 11px; font-weight: 700; color: var(--gray-700); letter-spacing: .07em; font-family: "IBM Plex Mono", monospace; margin-bottom: 12px; }
    .comm-trio-more  { margin-top: 8px; padding: 0; background: none; border: none; color: var(--purple-300); cursor: pointer; font-family: inherit; font-size: 12px; font-weight: 600; text-align: left; align-self: flex-start; }
    .comm-trio-more:hover { color: var(--orange-400); text-decoration: underline; }

    .loading-hero { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; min-height: 65vh; padding: 48px 20px; text-align: center; }
    .loading-hero-spinner { width: 52px; height: 52px; border: 4px solid var(--gray-200); border-top-color: var(--purple-300); border-radius: 50%; animation: loading-hero-spin 0.9s linear infinite; }
    .loading-hero-title { font-size: 18px; font-weight: 600; color: var(--gray-700); letter-spacing: -0.01em; }
    .loading-hero-sub { font-size: 13px; color: var(--gray-500); max-width: 360px; line-height: 1.5; }
    @keyframes loading-hero-spin { to { transform: rotate(360deg); } }

    /* Map containers — the Communities tab stacks a pin map (top) and a
       graduates choropleth (bottom). Both fixed-height; Leaflet handles
       resize via invalidateSize when the tab becomes visible. */
    #community-map, #graduates-map { height: 420px; border-radius: 10px; overflow: hidden; border: 1.5px solid var(--gray-200); }
    .map-caption { font-size: 11px; font-weight: 500; color: var(--gray-600); font-family: "IBM Plex Mono", monospace; letter-spacing: .06em; text-transform: uppercase; margin-bottom: 8px; }

    /* Choropleth legend + tooltip — drawn on the community map by Leaflet. */
    .choro-legend     { background: rgba(255,255,255,.95); border: 1px solid var(--gray-300); border-radius: 6px; padding: 8px 10px; font-family: inherit; font-size: 11px; color: var(--gray-800); box-shadow: 0 2px 8px rgba(0,0,0,.08); line-height: 1.4; }
    .choro-legend-title { font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--gray-600); font-family: "IBM Plex Mono", monospace; margin-bottom: 6px; }
    .choro-legend-row { display: flex; align-items: center; gap: 6px; }
    .choro-swatch     { display: inline-block; width: 14px; height: 12px; border-radius: 2px; border: 1px solid rgba(0,0,0,.08); flex-shrink: 0; }
    .choro-tooltip    { font-family: inherit; font-size: 12px; color: var(--gray-900); padding: 8px 10px; min-width: 180px; max-width: 260px; }
    .choro-tooltip-name { font-weight: 600; color: var(--purple-300); margin-bottom: 4px; font-size: 13px; }
    .choro-tooltip-total { font-family: "IBM Plex Mono", monospace; font-size: 11px; color: var(--gray-700); margin-bottom: 6px; }
    .choro-tooltip-line  { font-size: 11px; color: var(--gray-700); display: flex; justify-content: space-between; gap: 12px; }
    .choro-tooltip-line .val { font-variant-numeric: tabular-nums; color: var(--gray-900); font-weight: 500; }
    .choro-tooltip-sub   { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--gray-200); font-size: 11px; color: var(--gray-600); }
    .choro-tooltip-empty { color: var(--gray-500); font-style: italic; font-size: 11px; }

    /* People list */
    .people-list { display: flex; flex-direction: column; gap: 6px; }
    .person-row { display: flex; align-items: center; gap: 10px; padding: 8px 12px; background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 8px; font-size: 13px; }
    .person-row .name { flex: 1; }
    .page-controls { display: flex; align-items: center; justify-content: center; gap: 14px; margin: 22px auto 4px; padding: 8px 0; max-width: 480px; }
    .page-btn { padding: 7px 16px; border: 1.5px solid var(--gray-300); border-radius: 6px; background: var(--white); cursor: pointer; font-size: 12px; font-family: inherit; color: var(--gray-700); transition: border-color .12s, color .12s, background .12s; }
    .page-btn:hover:not(:disabled) { border-color: var(--purple-300); color: var(--purple-300); background: rgba(66,44,112,.04); }
    .page-btn:disabled { opacity: .35; cursor: not-allowed; }
    .page-info { font-size: 12px; color: var(--gray-600); font-family: "IBM Plex Mono", monospace; min-width: 120px; text-align: center; }

    /* Empty state */
    .empty-state { text-align: center; padding: 48px 0; color: var(--gray-500); font-size: 13px; }

    /* ── v1 nav extras (Phase 1) ───────────────────────────────────────── */
    .nav-dot         { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
    .nav-level-label { flex: 1; }
    .sublevel-num    { font-family: "IBM Plex Mono", monospace; font-size: 10px; opacity: .55; min-width: 22px; }
    .sublevel-lbl    { flex: 1; }
    .nav-badge       { font-family: "IBM Plex Mono", monospace; font-size: 10px; opacity: .55; min-width: 18px; text-align: right; }

    /* ── Topbar (page title + breadcrumb) ─────────────────────────────── */
    .topbar          { display: flex; align-items: center; padding: 16px 32px; border-bottom: 1px solid var(--gray-200); background: var(--white); flex-shrink: 0; }
    .app.page-scroll .topbar { position: sticky; top: 0; z-index: 50; }
    .topbar-back     { background: none; border: none; cursor: pointer; color: var(--purple-300); display: inline-flex; align-items: center; padding: 0; margin-right: 10px; font-family: inherit; }
    .topbar-back:hover { color: var(--orange-400); }
    /* Hidden on desktop; overridden to inline-flex in the mobile block. */
    .topbar-hamburger { display: none; }
    .sidebar-backdrop { display: none; }
    .topbar-title    { font-size: 15px; font-weight: 500; color: var(--purple-300); }
    .topbar-crumb    { margin-left: 14px; padding-left: 14px; border-left: 1px solid var(--gray-300); font-size: 11px; color: var(--gray-600); font-family: "IBM Plex Mono", monospace; letter-spacing: .04em; }
    .topbar-refresh  { margin-left: 8px; display: inline-flex; align-items: center; gap: 6px; background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 6px; padding: 6px 12px; font-size: 12px; font-family: inherit; color: var(--gray-700); cursor: pointer; transition: border-color .12s, color .12s; }
    .topbar-refresh:hover { border-color: var(--purple-300); color: var(--purple-300); }

    /* ── Global search (top bar) ─────────────────────────────────────────── */
    /* .topbar-search carries the margin-left:auto that used to live on the
       bell, so the search box anchors the right-aligned [search][bell][refresh]
       group. */
    .topbar-search { position: relative; margin-left: auto; display: inline-flex; align-items: center; }
    .topbar-search input { width: 210px; height: 32px; padding: 0 10px 0 32px; background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 6px; font-family: inherit; font-size: 13px; color: var(--gray-800); transition: border-color .12s, width .15s; }
    .topbar-search input:focus { outline: none; border-color: var(--purple-300); width: 280px; }
    .topbar-search input::placeholder { color: var(--gray-500); }
    .topbar-search input { padding-right: 28px; }
    .topbar-search .ts-icon { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); color: var(--gray-500); pointer-events: none; display: inline-flex; }
    .topbar-search .ts-clear { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); width: 20px; height: 20px; border: 0; background: transparent; color: var(--gray-500); cursor: pointer; border-radius: 4px; display: inline-flex; align-items: center; justify-content: center; font-size: 16px; line-height: 1; padding: 0; }
    .topbar-search .ts-clear:hover { color: var(--gray-900); background: var(--gray-100); }
    .gs-pop { max-height: 420px; overflow-y: auto; background: var(--white); border: 1px solid var(--gray-300); border-radius: 8px; box-shadow: 0 6px 24px rgba(0,0,0,.12); padding: 4px 0; font-size: 13px; }
    .gs-section-label { padding: 8px 12px 4px; font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--gray-500); font-weight: 600; }
    .gs-row { display: flex; flex-direction: column; gap: 1px; padding: 6px 12px; cursor: pointer; }
    .gs-row.hl { background: var(--gray-100); }
    .gs-row .gs-name { color: var(--purple-300); line-height: 1.25; }
    .gs-row .gs-sub  { font-size: 11px; color: var(--gray-600); font-family: "IBM Plex Mono", monospace; }
    .gs-msg { padding: 10px 12px; font-size: 12px; color: var(--gray-500); }

    /* ── Bell + notifications popover ────────────────────────────────────── */
    .topbar-bell, .topbar-action-items, .topbar-quick-add { position: relative; margin-left: 10px; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 6px; color: var(--gray-700); cursor: pointer; transition: border-color .12s, color .12s; }
    .topbar-bell:hover, .topbar-action-items:hover, .topbar-quick-add:hover { border-color: var(--purple-300); color: var(--purple-300); }
    .topbar-bell.has-unread { color: var(--purple-300); border-color: var(--purple-300); }

    /* ── Quick-Add modal tabs ────────────────────────────────────────────── */
    .quick-add-tabs { display: flex; gap: 4px; padding: 10px 16px 0; background: var(--white); border-bottom: 1px solid var(--gray-200); }
    .quick-add-tab { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px; padding: 10px 14px; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--gray-600); font-family: inherit; font-size: 13px; font-weight: 500; cursor: pointer; transition: color .12s, border-color .12s; }
    .quick-add-tab:hover { color: var(--purple-300); }
    .quick-add-tab.active { color: var(--purple-300); border-bottom-color: var(--purple-300); font-weight: 600; }
    .quick-add-tab .qa-emoji { font-size: 15px; line-height: 1; }
    [data-theme="dark"] .quick-add-tabs { background: transparent; }
    .bell-badge { position: absolute; top: -5px; right: -5px; min-width: 18px; height: 18px; padding: 0 5px; background: #dc2626; color: #fff; font-size: 11px; font-weight: 700; border-radius: 99px; display: inline-flex; align-items: center; justify-content: center; box-shadow: 0 0 0 2px var(--white), 0 0 0 3px rgba(220,38,38,.35); font-family: "IBM Plex Mono", monospace; }
    .notif-popover-backdrop { position: fixed; inset: 0; z-index: 1190; }
    .notif-popover { position: absolute; top: 48px; right: 18px; width: 360px; max-height: 480px; background: var(--white); border: 1px solid var(--gray-300); border-radius: 8px; box-shadow: 0 6px 24px rgba(0,0,0,.12); z-index: 1200; display: flex; flex-direction: column; }
    .notif-pop-head { display: flex; align-items: center; padding: 12px 14px; border-bottom: 1px solid var(--gray-200); }
    .notif-pop-head .ttl { font-size: 13px; font-weight: 600; color: var(--purple-300); }
    .notif-pop-head .actions { margin-left: auto; display: inline-flex; gap: 8px; }
    .notif-pop-head .actions button { background: none; border: none; cursor: pointer; color: var(--gray-600); font-size: 11px; font-family: inherit; padding: 2px 4px; }
    .notif-pop-head .actions button:hover { color: var(--purple-300); }
    .notif-pop-list { overflow-y: auto; flex: 1; }
    .notif-row { display: flex; flex-direction: column; gap: 4px; padding: 10px 14px; border-bottom: 1px solid var(--gray-100); font-size: 12px; cursor: default; }
    .notif-row.unread { background: rgba(239,123,0,.06); }
    .notif-row .row-top { display: flex; align-items: center; gap: 6px; }
    .notif-row .type-pill { display: inline-block; padding: 1px 6px; border-radius: 99px; background: var(--gray-200); color: var(--gray-700); font-size: 9px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; font-family: "IBM Plex Mono", monospace; }
    .notif-row .type-pill.reminder         { background: rgba(239,123,0,.15); color: var(--orange-400); }
    .notif-row .type-pill.mention          { background: rgba(99,102,241,.15); color: #6366f1; }
    .notif-row .type-pill.system           { background: rgba(34,197,94,.15);  color: #16a34a; }
    .notif-row .type-pill.test             { background: var(--gray-200); color: var(--gray-700); }
    .notif-row .type-pill.cohort-certified { background: rgba(34,197,94,.15);  color: #15803d; }
    .notif-row .type-pill.cohort-created   { background: rgba(168,85,247,.15); color: #7e22ce; }
    .notif-row .type-pill.reminder-overdue { background: rgba(239,68,68,.15);  color: #b91c1c; }
    .notif-row .type-pill.weekly-digest    { background: rgba(14,165,233,.15); color: #0369a1; }
    .notif-row .type-pill.etp-waitlist     { background: rgba(239,123,0,.15);  color: var(--orange-400); }
    .notif-row .type-pill.etp-exit-survey  { background: rgba(20,184,166,.15); color: #0f766e; }
    .notif-row .type-pill.release-notes    { background: rgba(236,72,153,.15); color: #be185d; }
    /* Notifications PAGE list — uses the MFB card shell shared with Action
       Items, Donors, Events, etc. (1.5px gray-300 border, 10px radius,
       12-14px padding). Unread keeps the orange accent via a 3px top-rule
       and faint background tint — same pattern as the Hero-stat cards. */
    .notif-list .notif-row {
      background: var(--white);
      border: 1.5px solid var(--gray-300);
      border-radius: 10px;
      padding: 12px 14px;
      gap: 6px;
      margin-bottom: 10px;
      transition: border-color .12s, background .12s, box-shadow .12s;
    }
    .notif-list .notif-row:last-child   { margin-bottom: 0; }
    .notif-list .notif-row:hover        { border-color: var(--purple-300); background: var(--gray-100); }
    .notif-list .notif-row.unread       {
      border-color: var(--gray-300);
      border-top: 3px solid var(--orange-400);
      background: rgba(247,148,31,.06);
      padding-top: 10px;
    }
    .notif-list .notif-row.unread:hover { border-color: var(--orange-400); background: rgba(247,148,31,.10); }
    /* Page-list cards lay out as two columns: title/body on the left,
       pill stacked over the action buttons on the right. Keeps the type
       label and its row's destructive controls visually attached. */
    .notif-list .notif-row { margin-bottom: 12px; flex-direction: row; align-items: flex-start; gap: 14px; }
    .notif-list .notif-row.clickable { cursor: pointer; }
    .notif-list .notif-row.clickable:hover { border-color: var(--orange-300); background: rgba(247,148,31,.04); }
    .notif-list .notif-row.unread.clickable:hover { border-color: var(--orange-400); background: rgba(247,148,31,.10); }
    .notif-list .notif-row .notif-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
    .notif-list .notif-row .notif-title-line { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
    .notif-list .notif-row .notif-side { display: flex; flex-direction: row; align-items: center; gap: 6px; flex-shrink: 0; }
    .notif-list .notif-row .ttl  { font-size: 13px;   color: var(--gray-900); font-weight: 600; line-height: 1.35; }
    .notif-list .notif-row .ttl-date { color: var(--gray-500); font-weight: 400; font-size: 12px; font-family: "IBM Plex Mono", monospace; letter-spacing: .02em; white-space: nowrap; }
    .notif-list .notif-row .body { font-size: 12px;   color: var(--gray-700); line-height: 1.45; margin-top: 2px; white-space: pre-wrap; }
    .notif-list .notif-row .type-pill { font-size: 9px; padding: 2px 8px; }
    .notif-list .notif-row .notif-side .btn { padding: 4px 10px; font-size: 11px; }
    /* Day-group header inside the notifications list — matches the
       "BY COUNTRY" / "PERSON IN CHARGE" label treatment used elsewhere.
       Top margin combines with the previous card's 12px bottom-margin to
       match the 24px gap below the header — so the header sits visually
       centered between groups. */
    .notif-day-h { font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .08em; color: var(--gray-500); margin: 12px 0 24px 0; font-family: "IBM Plex Mono", monospace; }
    .notif-day-h:first-child { margin-top: 4px; }
    /* iOS-style toggle for the Preferences tab. Replaces the native checkbox
       so a 7-row preferences list isn't a wall of tiny tick-boxes. */
    .mfb-toggle { position: relative; display: inline-block; width: 38px; height: 22px; flex-shrink: 0; }
    .mfb-toggle input { opacity: 0; width: 0; height: 0; }
    .mfb-toggle .slider { position: absolute; cursor: pointer; inset: 0; background: var(--gray-300); border-radius: 22px; transition: background .15s; }
    .mfb-toggle .slider::before { content: ''; position: absolute; height: 16px; width: 16px; left: 3px; top: 3px; background: white; border-radius: 50%; transition: transform .15s; box-shadow: 0 1px 2px rgba(0,0,0,.18); }
    .mfb-toggle input:checked + .slider { background: var(--orange-300); }
    .mfb-toggle input:checked + .slider::before { transform: translateX(16px); }
    .mfb-toggle input:disabled + .slider { opacity: .5; cursor: not-allowed; }
    /* Sticky save bar that appears only when the form is dirty. */
    .prefs-save-bar { position: sticky; bottom: 0; background: var(--white); border-top: 1px solid var(--gray-200); margin: 18px -8px -8px; padding: 12px 14px; display: flex; align-items: center; gap: 12px; z-index: 5; }
    .prefs-save-bar .dirty-note { font-size: 12px; color: var(--gray-700); }
    .notif-row .age  { font-size: 10px; color: var(--gray-500); font-family: "IBM Plex Mono", monospace; white-space: nowrap; margin-left: auto; }
    /* Title and body each get their own row, starting at the row's left edge.
       Avoids the "wrapped lines indent under the pill" look when titles are long.
       Title clamps to 3 lines so long subjects don't crowd out the body; body
       is unclamped so the user can read the full message in the bell popover
       without bouncing to the full Notifications page. Bodies are already
       capped at 280 chars at create time, so this stays compact. */
    .notif-popover .notif-row .ttl  { font-weight: 600; color: var(--gray-800); font-size: 12px; line-height: 1.4; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; word-break: break-word; }
    .notif-popover .notif-row .body { color: var(--gray-700); font-size: 11px; line-height: 1.45; white-space: pre-wrap; word-break: break-word; }
    .notif-popover .notif-row .body a { color: var(--orange-400); text-decoration: underline; text-underline-offset: 2px; }
    .notif-popover .notif-row { cursor: pointer; }
    .notif-popover .notif-row:hover { background: var(--gray-100); }
    .notif-popover .notif-row.unread:hover { background: rgba(239,123,0,.12); }
    /* Notifications PAGE cards only (scoped to .notif-list, not the bell
       popover): the type-pill label sits top-right on a single line; the title
       takes the rest of the row and wraps onto new lines only when it needs the
       room. */
    .notif-list .notif-row .row-top { align-items: flex-start; gap: 8px; }
    .notif-list .notif-row .row-top .ttl { flex: 1; min-width: 0; display: block; -webkit-line-clamp: unset; }
    .notif-list .notif-row .row-top .type-pill { margin-left: auto; flex-shrink: 0; white-space: nowrap; }
    /* Inbox-column notifications: stack date + action buttons onto their own
       row so the type-pill, title, date and buttons aren't crammed on one
       line inside the narrow (~⅓-width) shared-col. */
    .notif-row .notif-row-actions { display: flex; align-items: center; gap: 6px; margin-top: 8px; }
    .notif-row .notif-row-actions .age { margin-left: 0; }
    .notif-row .notif-row-actions .btn-group { margin-left: auto; display: inline-flex; gap: 6px; }
    .notif-pop-foot { padding: 8px 14px; border-top: 1px solid var(--gray-200); display: flex; align-items: center; justify-content: space-between; gap: 12px; }
    .notif-pop-foot a { color: var(--purple-300); font-size: 12px; cursor: pointer; }
    .notif-pop-foot a:hover { text-decoration: underline; }
    .notif-empty { padding: 28px 14px; text-align: center; color: var(--gray-500); font-size: 12px; }

    /* ── Notifications page ──────────────────────────────────────────────── */
    .notif-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--gray-200); margin-bottom: 18px; }
    .notif-tab  { padding: 10px 16px; background: none; border: none; cursor: pointer; font-size: 13px; font-family: inherit; color: var(--gray-600); border-bottom: 2px solid transparent; margin-bottom: -1px; }
    .notif-tab:hover { color: var(--purple-300); }
    .notif-tab.active { color: var(--purple-300); border-bottom-color: var(--purple-300); font-weight: 600; }
    .notif-form { display: grid; gap: 10px; max-width: 480px; margin-bottom: 24px; padding: 16px; background: var(--white); border: 1px solid var(--gray-200); border-radius: 8px; }
    .notif-form label { font-size: 11px; font-weight: 600; color: var(--gray-700); display: block; margin-bottom: 4px; }
    .notif-form input, .notif-form textarea, .notif-form select { width: 100%; padding: 8px 10px; border: 1.5px solid var(--gray-300); border-radius: 6px; font-family: inherit; font-size: 13px; box-sizing: border-box; }
    .notif-form .row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
    .notif-list { max-width: 720px; }

    /* Notifications page — Inbox view layout. Notifications + Reminders +
       Preferences sit side by side as three columns on wide viewports; the
       Configuration tab (Mattermost webhook) remains its own pane. */
    .notif-shared { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; align-items: start; }
    @media (max-width: 1240px) { .notif-shared { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
    @media (max-width: 880px)  { .notif-shared { grid-template-columns: 1fr; } }
    .notif-shared-col { background: var(--white); border: 1px solid var(--gray-200); border-radius: 10px; padding: 16px 18px; min-width: 0; }
    .notif-shared-h   { font-size: 13px; font-weight: 600; color: var(--purple-300); margin-bottom: 12px; display: flex; align-items: center; gap: 8px; letter-spacing: .02em; }
    .notif-shared-h svg { width: 14px; height: 14px; color: var(--purple-300); }
    /* When the Reminders + Notifications tabs render inside a shared-col,
       drop their card chrome so we don't double-card. */
    .notif-shared-col .notif-form { background: transparent; border: 0; padding: 0; margin-bottom: 14px; }
    .notif-shared-col .notif-list { max-width: none; }
    /* Inline tab-icon button content (gear + label). */
    .notif-tab-icon { display: inline-flex; align-items: center; gap: 7px; }
    .notif-tab-icon svg { width: 13px; height: 13px; }
    .notif-list .reminder-row { display: flex; align-items: center; gap: 12px; padding: 12px 14px; background: var(--white); border: 1px solid var(--gray-200); border-radius: 6px; margin-bottom: 8px; font-size: 13px; }
    .notif-list .reminder-row .due { font-family: "IBM Plex Mono", monospace; font-size: 11px; color: var(--gray-600); white-space: nowrap; }
    .notif-list .reminder-row .ttl { font-weight: 600; flex: 1; }
    .notif-list .reminder-row .rep { font-size: 10px; padding: 2px 6px; background: var(--gray-200); border-radius: 99px; }
    .notif-list .reminder-row button { background: none; border: 1px solid var(--gray-300); color: var(--gray-600); border-radius: 4px; padding: 4px 8px; font-size: 11px; cursor: pointer; }
    .notif-list .reminder-row button:hover { border-color: #ef4444; color: #ef4444; }

    /* Compact reminder row — used inside the Inbox Reminders column where
       the 33% width can't accommodate the full date + Cancel button layout. */
    .reminder-row-compact { display: flex; flex-direction: column; gap: 3px; padding: 8px 10px; background: var(--white); border: 1px solid var(--gray-200); border-radius: 6px; margin-bottom: 6px; }
    .reminder-row-compact .top { display: flex; align-items: flex-start; gap: 6px; }
    .reminder-row-compact .ttl { flex: 1; font-size: 12px; font-weight: 600; color: var(--gray-900); line-height: 1.35; overflow-wrap: anywhere; }
    .reminder-row-compact .x   { background: none; border: 0; color: var(--gray-400); cursor: pointer; font-size: 16px; line-height: 1; padding: 0 2px; flex-shrink: 0; }
    .reminder-row-compact .x:hover { color: #ef4444; }
    .reminder-row-compact .meta { display: flex; align-items: center; gap: 6px; font-family: "IBM Plex Mono", monospace; font-size: 10px; color: var(--gray-500); }
    .reminder-row-compact .meta .rep { font-size: 9px; padding: 1px 5px; background: rgba(239,123,0,.15); color: var(--orange-400); border-radius: 99px; text-transform: uppercase; letter-spacing: .04em; font-weight: 700; }

    /* Reminders tab — two-column layout: schedule-form card on the left,
       active reminders list on the right. Stacks below 880px. */
    .reminders-grid { display: grid; grid-template-columns: minmax(0, 480px) minmax(0, 1fr); gap: 24px; align-items: start; }
    @media (max-width: 880px) { .reminders-grid { grid-template-columns: 1fr; } }
    .reminders-grid .notif-form { margin-bottom: 0; max-width: none; }
    .webhook-status { display: inline-block; padding: 2px 8px; border-radius: 99px; font-size: 10px; font-weight: 600; font-family: "IBM Plex Mono", monospace; margin-left: 8px; }
    .webhook-status.set   { background: rgba(34,197,94,.15);  color: #16a34a; }
    .webhook-status.unset { background: rgba(239,68,68,.15);  color: #ef4444; }

    /* ── Locked page (v1 parity) ──────────────────────────────────────── */
    .placeholder-panel { background: var(--white); border: 1.5px solid var(--gray-200); border-radius: 12px; padding: 56px 40px; text-align: center; max-width: 540px; margin: 24px auto; }
    .placeholder-icon  { font-size: 36px; margin-bottom: 14px; }
    .placeholder-panel h3 { font-size: 16px; font-weight: 500; color: var(--purple-300); margin-bottom: 8px; }
    .placeholder-panel p  { color: var(--gray-600); font-size: 13px; line-height: 1.55; }
    .locked-name       { color: var(--orange-400); font-weight: 500; }
    .locked-contact    { margin-top: 14px; }

    /* ── Stub view (Phase 1 placeholder until phase 2-5 fills it) ─────── */
    .stub-banner       { background: rgba(247,148,31,.08); border: 1px dashed var(--orange-300); border-radius: 8px; padding: 14px 18px; color: var(--gray-700); font-size: 12px; font-family: "IBM Plex Mono", monospace; margin-top: 16px; }

    /* ─────────────────────────────────────────────────────────────────────
       Dark mode — invert the gray/white scale and lift purple-300/200 so
       they read as accents against dark surfaces. Sidebar keeps purple-400
       (which we override below) so the brand chrome stays dark.
       ───────────────────────────────────────────────────────────────────── */
    [data-theme="dark"] {
      --white:    #1F2027;
      --gray-100: #15161B;
      --gray-200: #262731;
      --gray-300: #363742;
      --gray-400: #4A4B58;
      --gray-500: #7A7B86;
      --gray-600: #9A9BA6;
      --gray-700: #BFBFC8;
      --gray-800: #DCDCE2;
      --gray-900: #ECECF2;
      --purple-400: #1A0F36;
      --purple-300: #B89BE8;
      --purple-200: #D2BEF7;
      --brand-gradient: linear-gradient(135deg, #1A0F36 0%, #3D2660 100%);
    }
    [data-theme="dark"] .sidebar       { background: #13141A; border-right: 1px solid var(--gray-200); }
    [data-theme="dark"] .sidebar-header { border-bottom-color: var(--gray-200); }
    [data-theme="dark"] .login-screen  { background: #13141A; }
    [data-theme="dark"] .login-card    { background: var(--white); box-shadow: 0 24px 64px rgba(0,0,0,.6); }
    [data-theme="dark"] .login-logo img { filter: brightness(0) invert(1) sepia(.4) saturate(8) hue-rotate(230deg); }
    [data-theme="dark"] ::-webkit-scrollbar-thumb { background: var(--gray-400); }
    [data-theme="dark"] * { scrollbar-color: var(--gray-400) transparent; }
    [data-theme="dark"] .stat-card:hover,
    [data-theme="dark"] .my-role-card:hover,
    [data-theme="dark"] .cohort-quicklink-row:hover { box-shadow: 0 2px 12px rgba(0,0,0,.4); }
    /* Leaflet tiles stay readable on dark; just darken the container. */
    [data-theme="dark"] .leaflet-container { background: #1F2027; }
    /* Soft pastel chips read better with slightly more saturation on dark. */
    [data-theme="dark"] .gs-row.hl { background: var(--gray-200); }
    /* Topbar theme toggle */
    .topbar-theme {
      margin-left: 8px; display: inline-flex; align-items: center; justify-content: center;
      background: var(--white); border: 1.5px solid var(--gray-300); border-radius: 6px;
      width: 32px; height: 32px; padding: 0; color: var(--gray-700); cursor: pointer;
      transition: border-color .12s, color .12s;
    }
    .topbar-theme:hover { border-color: var(--purple-300); color: var(--purple-300); }
    .topbar-theme .sun-icon  { display: inline-flex; }
    .topbar-theme .moon-icon { display: none; }
    [data-theme="dark"] .topbar-theme .sun-icon  { display: none; }
    [data-theme="dark"] .topbar-theme .moon-icon { display: inline-flex; }

    /* ── Dark-mode legibility fixes ─────────────────────────────────────────
       --white serves two purposes in this codebase: surface bg (cards, top-
       bar, inputs) AND "true white text" on branded/colored backgrounds
       (sidebar nav, hero gradients, purple/orange buttons). Inverting it
       for dark mode breaks the second use — the text goes dark on dark.
       Restore true white text for the elements that need it. */
    [data-theme="dark"] .sidebar,
    [data-theme="dark"] .sidebar .brand-text strong,
    [data-theme="dark"] .sidebar .nav-item,
    [data-theme="dark"] .sidebar .nav-group-header,
    [data-theme="dark"] .sidebar .nav-sub-item,
    [data-theme="dark"] .sidebar .nav-item:hover,
    [data-theme="dark"] .sidebar .nav-group-header:hover,
    [data-theme="dark"] .sidebar .nav-sub-item:hover,
    [data-theme="dark"] .sidebar .user-name,
    [data-theme="dark"] .sidebar-collapse-btn:hover,
    [data-theme="dark"] .btn-logout:hover,
    [data-theme="dark"] .overview-hero,
    [data-theme="dark"] .overview-hero *,
    [data-theme="dark"] .my-db-hero,
    [data-theme="dark"] .my-db-hero *,
    [data-theme="dark"] .my-db-welcome,
    [data-theme="dark"] .profile-hero,
    [data-theme="dark"] .profile-hero *,
    [data-theme="dark"] .profile-avatar,
    [data-theme="dark"] .btn-primary,
    [data-theme="dark"] .person-side-btn:not(.person-side-btn-ghost),
    [data-theme="dark"] .member-row-avatar,
    [data-theme="dark"] .comm-logo-placeholder,
    [data-theme="dark"] .csv-count-badge,
    [data-theme="dark"] .nt-badge,
    [data-theme="dark"] .chart-filter-btn.active,
    [data-theme="dark"] .chart-filter-btn.mode-toggle.active,
    [data-theme="dark"] .bell-badge {
      color: #fff;
    }
    /* Inputs INSIDE branded surfaces (e.g. sidebar search) shouldn't go
       white — restore their normal foreground. */
    [data-theme="dark"] .sidebar input,
    [data-theme="dark"] .sidebar select,
    [data-theme="dark"] .sidebar textarea {
      color: var(--gray-900);
    }
    /* Hero subtitles / muted descenders inside hero gradients should be
       semi-transparent white, not fully muted gray. */
    [data-theme="dark"] .overview-hero p,
    [data-theme="dark"] .my-db-hero p { color: rgba(255,255,255,.85); }

    /* Selected-row backgrounds: a few inline `#fff...` peaches/yellows
       persist where they were hardcoded outside CSS classes. Catch the
       remaining ones with a translucent overlay so the underlying dark
       surface still reads through. */
    [data-theme="dark"] tr[style*="background:#fff7ed"],
    [data-theme="dark"] tr[style*="background: #fff7ed"] { background: rgba(247,148,31,.18) !important; }

    /* ─── Message Hub ─── */
    .msghub-preview-banner { background: rgba(247,148,31,.10); border: 1px solid rgba(247,148,31,.35); color: #7a4b12; padding: 10px 14px; border-radius: 8px; font-size: 12.5px; line-height: 1.55; margin-bottom: 16px; }
    [data-theme="dark"] .msghub-preview-banner { background: rgba(247,148,31,.10); color: #f7ba7d; border-color: rgba(247,148,31,.35); }

    /* The healthy state gets a chip, not the banner above. It answers one
       question, which host am I on, and it answers it in the width of a pill
       instead of a paragraph the reader learns to skip. Green rather than the
       banner's amber: amber is for "this will not do what you think". The full
       explanation the paragraph carried is on its title attribute. */
    /* The one banner state that is a fault rather than a limitation. Red, so it
       does not read as the amber "this host is deliberately quiet". */
    .msghub-banner-broken { background: rgba(185,28,28,.08) !important; border-color: rgba(185,28,28,.35) !important; color: #991b1b !important; }
    [data-theme="dark"] .msghub-banner-broken { background: rgba(248,113,113,.10) !important; border-color: rgba(248,113,113,.35) !important; color: #fca5a5 !important; }

    .msghub-host-chip {
      display: inline-flex; align-items: center; gap: 7px;
      /* No bottom margin: the chip now lives in the Message panel's head row,
         level with Save as draft, not standing alone above the grid. */
      padding: 4px 11px; border-radius: 999px;
      font-size: 11.5px; font-weight: 500; letter-spacing: .01em;
      cursor: help;
    }
    .msghub-host-chip.live { background: rgba(22,163,74,.10); border: 1px solid rgba(22,163,74,.35); color: #166534; }
    .msghub-host-dot { width: 7px; height: 7px; border-radius: 50%; background: #16a34a; flex: none; }
    [data-theme="dark"] .msghub-host-chip.live { background: rgba(34,197,94,.12); border-color: rgba(34,197,94,.35); color: #86efac; }
    [data-theme="dark"] .msghub-host-dot { background: #22c55e; }
    .msghub-optin-warn { margin-top: 10px; padding: 8px 12px; background: rgba(220,38,38,.08); border: 1px solid rgba(220,38,38,.25); color: #7c1d1d; border-radius: 6px; font-size: 12px; line-height: 1.5; }
    [data-theme="dark"] .msghub-optin-warn { background: rgba(220,38,38,.12); color: #fca5a5; border-color: rgba(220,38,38,.35); }
    .msghub-grid { display: grid; grid-template-columns: minmax(280px, 360px) 1fr; gap: 20px; align-items: start; }
    @media (max-width: 900px) { .msghub-grid { grid-template-columns: 1fr; } }
    .msghub-panel { background: var(--white); border: 1px solid var(--gray-200); border-radius: 12px; padding: 20px; }
    .msghub-h { font-size: 13px; font-weight: 600; color: var(--purple-300); margin: 0 0 14px; letter-spacing: .02em; text-transform: uppercase; }

    /* ── The unified Sends & analytics page ──────────────────────────────
       Title Case rather than the uppercase .msghub-h above. Brand rule 1 is
       "no ALL-CAPS, ever"; the CRM's uppercase micro-labels are a deviation
       Arnold accepted on 2026-08-05 and did NOT want re-cased wholesale, so
       this class is scoped to the Campaigns pages he asked to be brand-correct
       (Sends & analytics 2026-08-18, Audience Overview 2026-08-19, MFB-310)
       instead of changing .msghub-h under every other view.

       Slightly larger and less letter-spaced than .msghub-h because Title
       Case does not need the tracking that all-caps does to stay legible. */
    .comms-h { font-size: 14px; font-weight: 600; color: var(--purple-300); margin: 0 0 14px; letter-spacing: 0; text-transform: none; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
    /* The at-a-glance counts beside the heading: secondary to it, but still
       body copy someone reads. gray-700, NOT the gray-600 this started as —
       measured, gray-600 is 3.47:1 on white and WCAG AA wants 4.5:1 for text
       this size. gray-700 is 5.15:1 and reads just as quiet. */
    .comms-h-count { font-size: 12px; font-weight: 400; color: var(--gray-700); letter-spacing: 0; }

    /* Stage: how far a send got. SOLID fills, not translucent — brand rule 2
       forbids translucent fills on brand shapes, and the scale progression is
       what carries the difference instead. Sentence case for the same reason
       the heading is. */
    .comms-stage { display: inline-block; padding: 2px 9px; border-radius: 99px; font-size: 11px; font-weight: 600; letter-spacing: .01em; white-space: nowrap; }
    .comms-stage-test { background: var(--orange-200); color: var(--purple-400); }
    .comms-stage-sent { background: var(--purple-200); color: var(--white); }

    /* The All sends table. It carries 14 numeric columns plus the identity of
       the send, so it will always be wider than the panel on a laptop. It
       scrolls INSIDE this box: the page body must never scroll sideways
       (CLAUDE.md mobile rule 8), and before this the right-hand columns simply
       fell off the viewport. */
    .sends-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

    /* ALL SENDS, AS CARDS. This list used to be a 15-column table, which meant
       the only way to read a send was to scroll sideways past the columns you
       did not want (Arnold, 2026-08-27). One card per mailing instead: the head
       carries what identifies it, and unfolding it shows the send's own facts,
       including the ones the table had no room for at all (when it finished,
       who fired it, how many batches, what the numbers were counted from). */
    .sends-cards { display: flex; flex-direction: column; gap: 8px; }
    .sends-card { border: 1px solid var(--gray-200); border-radius: 10px; background: var(--white); overflow: hidden; }
    .sends-card.open { border-color: var(--gray-300); }
    /* The head IS the button, so the whole strip is the hit target and it keeps
       a 44px height for a thumb. Reset the UA button styling that comes with
       that: this has to read as a row, not as a control. */
    .sends-card-head {
      display: grid; grid-template-columns: 16px 1fr auto auto; align-items: center; gap: 12px;
      width: 100%; min-height: 44px; padding: 10px 14px; margin: 0;
      background: none; border: 0; font: inherit; color: inherit; text-align: left; cursor: pointer;
    }
    .sends-card-head:hover { background: var(--gray-100); }
    .sends-card.open .sends-card-head { border-bottom: 1px solid var(--gray-200); }
    .sends-card-chev { font-size: 11px; color: var(--gray-600); }
    /* One line now that the date/address sub-line is gone: a column flex with a
       single child is just a longer way of writing a block, and the subject
       needs to truncate rather than wrap the row to two lines. */
    .sends-card-main { min-width: 0; display: flex; align-items: center; }
    .sends-card-subject { font-weight: 500; color: var(--gray-900); line-height: 1.35; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .sends-card-pills { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; justify-content: flex-end; }
    /* One line: number then unit, baseline-aligned (Arnold, 2026-08-28). It was
       stacked, which made the head two lines tall for a single number. */
    .sends-card-headline { display: flex; flex-direction: row; align-items: baseline; gap: 4px; justify-content: flex-end; min-width: 72px; white-space: nowrap; }
    .sends-card-headline-n { font-size: 15px; font-weight: 600; color: var(--gray-900); font-variant-numeric: tabular-nums; }
    .sends-card-headline-l { font-size: 10px; color: var(--gray-600); }
    .sends-card-body { padding: 12px 14px 14px; }
    /* Two columns of label/value on a laptop, one on a phone. A definition list
       because that is what this is: a term and its value, not a table of rows
       that line up with each other. */
    /* AS MANY FACTS PER ROW AS FIT, each one label-over-value (Arnold,
       2026-08-28: "things like Body, Channels, From, Finished can be on the same
       line with their item below it"). Two fixed columns made a nine-fact card
       five rows tall; auto-fit gets the same facts into two or three. */
    .sends-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px 18px; margin: 0; }
    .sends-fact { min-width: 0; }
    .sends-fact dt { font-size: 10px; text-transform: uppercase; letter-spacing: .04em; color: var(--gray-600); margin-bottom: 1px; }
    .sends-fact dd { margin: 0; font-size: 13px; color: var(--gray-900); line-height: 1.45; word-break: break-word; }
    .sends-card-actions { margin-top: 12px; display: flex; flex-wrap: wrap; gap: 6px; }

    [data-theme="dark"] .sends-card        { background: rgba(255,255,255,.03); border-color: var(--gray-700); }
    [data-theme="dark"] .sends-card.open   { border-color: var(--gray-600); }
    [data-theme="dark"] .sends-card-head:hover { background: rgba(255,255,255,.05); }
    [data-theme="dark"] .sends-card.open .sends-card-head { border-bottom-color: var(--gray-700); }
    [data-theme="dark"] .sends-card-subject,
    [data-theme="dark"] .sends-card-headline-n,
    [data-theme="dark"] .sends-fact dd     { color: var(--gray-100); }

    @media (max-width: 768px) {
      /* The pills and the headline number stop competing with the subject for a
         narrow row: everything stacks under it. */
      .sends-card-head { grid-template-columns: 16px 1fr; row-gap: 6px; }
      .sends-card-pills, .sends-card-headline { grid-column: 2; align-items: flex-start; justify-content: flex-start; }
      .sends-card-headline { flex-direction: row; gap: 4px; align-items: baseline; }
      /* auto-fit already collapses to one column below ~330px; this keeps the
         narrow phone case at a readable two-up rather than forcing a single. */
      .sends-facts { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
    }

    /* Subject is the column someone actually reads, so it gets the room and is
       the one allowed to wrap. Everything else stays on one line. */
    .stats-links-table.analytics-jobs .sends-subject-h { min-width: 260px; }
    .stats-links-table.analytics-jobs .sends-subject   { min-width: 260px; max-width: 420px; white-space: normal; }
    .sends-subject-t   { font-weight: 500; color: var(--gray-900); line-height: 1.35; }
    /* Audience and sender moved UNDER the subject rather than each taking a
       column of their own. That is what fixes "audience font is too big": at
       11px they read as the caption they are, not as a peer of the subject. */
    .sends-subject-sub { font-size: 11px; color: var(--gray-700); margin-top: 2px; line-height: 1.4; }

    /* Date over time. One "8/19/2026, 1:04:13 AM" on a single line was forcing
       this column wide enough to push the numbers off the right. */
    .stats-links-table.analytics-jobs .sends-when   { white-space: nowrap; font-size: 12px; color: var(--gray-700); }
    .stats-links-table.analytics-jobs .sends-when-h { min-width: 92px; }
    .sends-time { font-size: 11px; color: var(--gray-600); margin-top: 1px; }

    /* Title Case headers on this table too, for the same reason .comms-h is
       Title Case: Arnold asked for THIS page to follow brand rule 1. Scoped to
       .analytics-jobs so the shared .stats-links-table stays as it is. */
    .stats-links-table.analytics-jobs th { text-transform: none; letter-spacing: 0; font-size: 11.5px; }
    .msghub-field { margin-bottom: 16px; }
    .msghub-label { display: block; font-size: 12px; font-weight: 500; color: var(--gray-700); margin-bottom: 6px; }
    .msghub-radios { display: flex; flex-direction: column; gap: 6px; }
    .msghub-radio { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border: 1px solid var(--gray-200); border-radius: 8px; cursor: pointer; font-size: 13px; color: var(--gray-800); transition: border-color .12s, background .12s; }
    .msghub-radio:hover { background: var(--gray-100); }
    .msghub-radio.active { border-color: var(--purple-300); background: rgba(66,44,112,.06); color: var(--purple-300); font-weight: 500; }
    .msghub-radio.requires-confirm { color: #991b1b; }
    .msghub-radio.requires-confirm.active { border-color: #b91c1c; background: rgba(220,38,38,.06); color: #991b1b; }
    .msghub-radio input { margin: 0; }
    .msghub-danger-badge { display: inline-block; margin-left: 4px; padding: 0 4px; background: rgba(220,38,38,.15); border-radius: 3px; font-size: 11px; color: #991b1b; }
    [data-theme="dark"] .msghub-radio.requires-confirm,
    [data-theme="dark"] .msghub-radio.requires-confirm.active { color: #fca5a5; }
    [data-theme="dark"] .msghub-danger-badge { background: rgba(220,38,38,.25); color: #fca5a5; }
    .msghub-select, .msghub-input, .msghub-textarea { width: 100%; box-sizing: border-box; padding: 8px 10px; border: 1px solid var(--gray-300); border-radius: 6px; font-family: inherit; font-size: 13px; color: var(--gray-900); background: var(--white); }
    .msghub-select:focus, .msghub-input:focus, .msghub-textarea:focus { outline: 2px solid var(--purple-200); outline-offset: -1px; border-color: var(--purple-200); }

    /* Type-to-filter combobox used inside the Audience picker in Message Hub.
       Sized to match .msghub-select so the visual weight of the field stays
       identical; menu escapes normal flow via absolute positioning. */
    .audience-combo { position: relative; }
    .audience-combo-control { position: relative; display: flex; align-items: center; width: 100%; box-sizing: border-box; border: 1px solid var(--gray-300); border-radius: 6px; background: var(--white); padding-right: 26px; cursor: text; transition: border-color .12s, box-shadow .12s; }
    .audience-combo-control.open { outline: 2px solid var(--purple-200); outline-offset: -1px; border-color: var(--purple-200); }
    .audience-combo-input { flex: 1; min-width: 0; padding: 8px 10px; border: none; outline: none; background: transparent; font-family: inherit; font-size: 13px; color: var(--gray-900); }
    .audience-combo-input::placeholder { color: var(--gray-500); }
    .audience-combo-caret { position: absolute; right: 10px; color: var(--gray-500); font-size: 10px; pointer-events: none; }
    .audience-combo-clear { position: absolute; right: 26px; background: transparent; border: none; color: var(--gray-500); cursor: pointer; font-size: 16px; line-height: 1; padding: 2px 6px; border-radius: 4px; }
    .audience-combo-clear:hover { color: var(--red-500, #dc2626); background: var(--gray-100); }
    .audience-combo-menu { position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 40; background: var(--white); border: 1px solid var(--gray-300); border-radius: 8px; box-shadow: 0 8px 24px rgba(0,0,0,.10); max-height: 280px; overflow-y: auto; padding: 4px; }
    .audience-combo-opt { display: block; width: 100%; text-align: left; padding: 8px 10px; border: none; background: transparent; font: inherit; font-size: 13px; color: var(--gray-900); cursor: pointer; border-radius: 5px; }
    .audience-combo-opt.hl       { background: rgba(107,70,193,.10); }
    .audience-combo-opt.selected { background: rgba(247,148,31,.14); font-weight: 600; }
    .audience-combo-opt.selected.hl { background: rgba(247,148,31,.24); }
    .audience-combo-empty { padding: 10px 12px; font-size: 12.5px; color: var(--gray-600); }
    [data-theme="dark"] .audience-combo-control { background: rgba(255,255,255,.03); border-color: var(--gray-700); }
    [data-theme="dark"] .audience-combo-input   { color: var(--gray-100); }
    [data-theme="dark"] .audience-combo-input::placeholder { color: var(--gray-500); }
    [data-theme="dark"] .audience-combo-menu    { background: rgba(30,30,40,.98); border-color: var(--gray-700); box-shadow: 0 8px 24px rgba(0,0,0,.35); }
    [data-theme="dark"] .audience-combo-opt     { color: var(--gray-100); }
    [data-theme="dark"] .audience-combo-opt.hl  { background: rgba(147,124,229,.15); }

    /* Hand-picked people audience (MFB-277). The control itself reuses
       .audience-combo-*; only the chip row above it is new. */
    .people-picker { position: relative; }
    .people-picker-chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 8px; }
    .people-chip { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; padding: 4px 6px 4px 10px; border-radius: 999px; background: rgba(107,70,193,.10); border: 1px solid rgba(107,70,193,.22); font-size: 12.5px; color: var(--gray-900); }
    .people-chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; }
    .people-chip-x { border: none; background: transparent; color: var(--gray-600); cursor: pointer; font-size: 15px; line-height: 1; padding: 0 2px; border-radius: 4px; }
    .people-chip-x:hover { color: var(--red-500, #dc2626); background: rgba(0,0,0,.06); }
    .people-picker-clear { border: none; background: transparent; color: var(--gray-600); cursor: pointer; font-size: 12px; text-decoration: underline; padding: 2px 4px; }
    .people-opt-email { color: var(--gray-600); font-size: 12px; }
    [data-theme="dark"] .people-chip { background: rgba(147,124,229,.16); border-color: rgba(147,124,229,.32); color: var(--gray-100); }
    [data-theme="dark"] .people-chip-x:hover { background: rgba(255,255,255,.08); }
    [data-theme="dark"] .people-opt-email { color: var(--gray-400); }
    .msghub-textarea { min-height: 220px; resize: vertical; line-height: 1.55; font-family: "IBM Plex Sans", Arial, sans-serif; }
    /* Short form is chat-sized copy — 220px of empty box reads as "write an essay here". */
    /* THE SHORT FORM MATCHES THE LONG FORM. Both are message bodies sitting one above
       the other, and they were set differently: the rich editor's surface is 14px/1.6
       with 14px 16px padding, the textarea was 13px/1.55 with 8px 10px, and in dark
       mode the textarea forced #e5e5ef while the editor inherited its own token. The
       result read as a different, lighter text colour in the same column. These values
       are deliberately copied from `.rte-surface` rather than invented; if that
       changes, change this with it. */
    .msghub-textarea-short {
      min-height: 140px;
      padding: 14px 16px;
      font-size: 14px;
      line-height: 1.6;
      color: var(--gray-900);
    }
    .msghub-textarea-short::placeholder { color: var(--gray-500); }
    [data-theme="dark"] .msghub-textarea-short { color: #e5e5ef; }

    /* The Message box header: title left, draft actions right, wrapping on narrow
       screens rather than squeezing the title. */
    /* The type dropdown inside the Audience card: card-sized, not form-sized, so it
       sits with the Recipients value above it rather than looking like a field that
       wandered in from the Message box. */
    .msghub-msgtype-select { max-width: 100%; font-size: 13px; padding: 6px 8px; margin-top: 2px; }
    /* The type is a NAME, not a measurement, so it does not get the recipient count's
       display size: at that scale it shouted over the number it qualifies. */
    .msghub-msgtype-value { font-size: 13px; color: var(--gray-900); margin-top: 4px; }
    .msghub-msgtype-value strong { font-weight: 600; }
    [data-theme="dark"] .msghub-msgtype-value { color: #e5e5ef; }
    /* Compact table for the channel split: it sits inside a card, not on a page. */
    .msghub-channel-table { margin-top: 4px; }
    .msghub-channel-table td { padding: 5px 0; font-size: 12.5px; border-bottom: none; }
    .msghub-channel-table td:first-child { padding-right: 10px; }

    /* ONE HEADER HEIGHT ACROSS BOTH COLUMNS. Audience and Message sit side by side, so
       their first controls (Filter and Sender) only line up if the headers above them
       match. The Message header carries the draft button and the Audience header carries
       nothing, so the height comes from min-height rather than from the contents:
       28px is the small button's height, which is the taller of the two. */
    /* Starter templates. auto-fit rather than a fixed column count so one starter
       does not sit in a third of the width looking like a mistake. */
    .starter-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; }
    .starter-card { border: 1px solid var(--gray-200); border-radius: 10px; padding: 16px; display: flex; flex-direction: column; gap: 6px; align-items: flex-start; }
    .starter-card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
    .starter-card-name { font-size: 14px; font-weight: 600; color: var(--gray-900); }
    /* A pill sitting next to a title, so it needs its own space and a baseline
       that agrees with the text beside it: it rendered flush against the name and
       sat slightly high (Arnold, 2026-08-27). */
    .starter-card-badge {
      display: inline-block; margin-left: 8px; vertical-align: 1px;
      font-size: 10.5px; font-weight: 500; letter-spacing: .02em;
      padding: 2px 8px; border-radius: 99px; line-height: 1.5;
      background: var(--orange-200); color: var(--gray-900); white-space: nowrap;
    }
    /* Edit + Open in composer are one row, never two. */
    .starter-row-actions { display: flex; align-items: center; gap: 6px; flex-wrap: nowrap; }

    /* THE DRAFTS / TEMPLATES TABLE (Arnold, 2026-08-28).
       The first column held a name, a subject, a two-sentence description and,
       for a blocked starter, a paragraph explaining why it cannot be sent. With
       nothing constraining it that column took whatever the panel was wide, so
       the description ran the full width of the screen and Author and Last
       edited were pushed to the far right edge, a long eye-track away from the
       row they belong to. Fixed layout puts a ceiling on the text column and
       brings the other two back in beside it. */
    .stats-links-table.drafts-table { table-layout: fixed; }
    /* The text column is the only one given a real width; the ACTIONS column is
       the one left auto, so a wide screen adds its extra space after the buttons
       rather than in front of Author. That is what keeps Author and Last edited
       beside the title instead of against the right-hand edge. */
    .stats-links-table.drafts-table .drafts-col-title   { width: 560px; }
    .stats-links-table.drafts-table .drafts-col-who     { width: 120px; }
    .stats-links-table.drafts-table .drafts-col-when    { width: 130px; }
    .stats-links-table.drafts-table .drafts-col-actions { width: auto; }
    /* A measure, not a column width: long prose stops being readable well before
       it stops fitting, and the cap keeps the description a paragraph shape
       rather than one very long line. */
    .stats-links-table.drafts-table .drafts-title-cell > * { max-width: 62ch; }
    .drafts-title-line { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
    .drafts-title-name { font-weight: 500; overflow-wrap: anywhere; }
    .drafts-subject { font-size: 12px; margin-top: 2px; }
    .drafts-desc { font-size: 12px; color: var(--gray-700); line-height: 1.5; margin: 4px 0 0; }
    .drafts-blocked { margin-top: 6px; }
    [data-theme="dark"] .drafts-desc { color: var(--gray-400); }

    @media (max-width: 1100px) {
      /* Below this there is not enough width left for the action buttons once the
         text column has taken its 560px, and the actions column is the one that
         cannot shrink (the buttons do not wrap). There is also far less slack to
         misplace at this size, which is the problem the fixed layout exists to
         solve, so hand the table back to auto layout. */
      .stats-links-table.drafts-table { table-layout: auto; }
      .stats-links-table.drafts-table .drafts-title-cell > * { max-width: none; }
    }
    .starter-card-subject { font-size: 12px; color: var(--gray-700); font-style: italic; }
    .starter-card-desc { font-size: 13px; color: var(--gray-800); line-height: 1.5; margin: 2px 0 0; }
    .starter-card-blocked { font-size: 12px; color: var(--gray-700); line-height: 1.5; margin: 0; padding: 8px 10px; background: var(--gray-100); border-radius: 6px; }
    .starter-card .btn { margin-top: 6px; min-height: 44px; }
    @media (max-width: 768px) {
      .starter-grid { grid-template-columns: 1fr; }
      .starter-card .btn { width: 100%; }
    }
    [data-theme="dark"] .starter-card { border-color: var(--gray-700); }
    [data-theme="dark"] .starter-card-name { color: #e5e5ef; }
    [data-theme="dark"] .starter-card-blocked { background: rgba(255,255,255,.04); color: var(--gray-400); }

    .msghub-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; min-height: 28px; margin-bottom: 14px; }
    .msghub-panel-head-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
    /* The host chip rides with the panel title, not with the buttons: which host you
       are on qualifies the word "Message", so it reads as part of the heading. */
    .msghub-panel-head-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

    /* The signature belongs to the long form. This used to be a 14px vertical stub
       between the two, which at that size read as a stray grey pixel rather than as a
       connector. Now the whole block is indented behind a full-height rail: the rail
       has a length, so it reads as a relationship, and the indent says "this is part of
       the thing above" without needing a caption. */
    .msghub-signature-attached {
      margin-top: 12px;
      padding-left: 14px;
      border-left: 2px solid var(--gray-200);
    }
    .msghub-signature-attached .msghub-field { margin-bottom: 0; }
    [data-theme="dark"] .msghub-signature-attached { border-left-color: var(--gray-700); }
    /* A label that is also a tick-box: the whole label is the hit target, and
       the box sits on the text baseline rather than floating above it. */
    .msghub-label-check { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; }
    .msghub-label-check input[type="checkbox"] { width: 15px; height: 15px; margin: 0; cursor: pointer; accent-color: var(--purple-300); }
    .msghub-shortform-folded { margin-top: 6px; }
    .msghub-charcount { margin-top: 6px; font-size: 12px; color: var(--gray-600); font-variant-numeric: tabular-nums; }
    .msghub-charcount.near { color: #B4690E; }
    .msghub-charcount.over { color: #991b1b; font-weight: 500; }
    /* Badge on whichever form the selected channels don't consume. Dim, not
       hidden: typed copy that vanished would read as lost work. */
    .msghub-form-badge { margin-left: 8px; padding: 2px 7px; border-radius: 999px; font-size: 10px; font-weight: 500; letter-spacing: .02em; vertical-align: middle; }
    .msghub-form-badge.unused { background: var(--gray-200); color: var(--gray-600); }
    /* Long-form copy checks (word count + best-practice read-out). */
    .copy-checks { margin-top: 10px; border: 1px solid var(--gray-200); border-radius: 10px; background: var(--gray-100); overflow: hidden; }
    /* A button that fills the box: the whole row is the hit target, which is what a
       collapsed summary should be, and 44px keeps it thumb-sized on mobile. */
    .copy-checks-summary {
      display: flex; align-items: center; justify-content: space-between; gap: 12px;
      width: 100%; min-height: 44px; padding: 10px 14px; margin: 0;
      background: none; border: 0; font: inherit; text-align: left; cursor: pointer;
      color: inherit;
    }
    .copy-checks-summary:hover { background: rgba(0,0,0,.03); }
    .copy-checks-summary:focus-visible { outline: 2px solid var(--purple-200); outline-offset: -2px; }
    .copy-checks-trigger { display: inline-flex; align-items: center; gap: 8px; flex-shrink: 0; }
    .copy-checks-badge { font-size: 11px; color: #B4690E; background: rgba(180,105,14,.12); border-radius: 999px; padding: 2px 8px; white-space: nowrap; }
    .copy-checks-badge.ok { color: var(--gray-600); background: rgba(0,0,0,.05); }
    .copy-checks-chevron { font-size: 10px; color: var(--gray-600); }
    .copy-checks-panel { padding: 0 14px 12px; border-top: 1px solid var(--gray-200); margin-top: 2px; padding-top: 10px; }
    [data-theme="dark"] .copy-checks-summary:hover { background: rgba(255,255,255,.04); }
    [data-theme="dark"] .copy-checks-badge.ok { color: var(--gray-300); background: rgba(255,255,255,.07); }
    [data-theme="dark"] .copy-checks-chevron { color: var(--gray-400); }
    [data-theme="dark"] .copy-checks-panel { border-top-color: var(--gray-700); }
    .copy-checks-metrics { display: flex; flex-wrap: wrap; gap: 14px; align-items: baseline; }
    .copy-metric { font-size: 12px; color: var(--gray-600); }
    .copy-metric strong { font-size: 15px; color: var(--gray-900); font-variant-numeric: tabular-nums; }
    .copy-metric.over strong { color: #991b1b; }
    .copy-checks-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
    .copy-check { display: flex; gap: 8px; align-items: flex-start; font-size: 12px; line-height: 1.5; color: var(--gray-700); }
    .copy-check-icon { flex: 0 0 16px; width: 16px; height: 16px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 600; margin-top: 1px; }
    .copy-check.bad  .copy-check-icon { background: rgba(220,38,38,.12);  color: #991b1b; }
    .copy-check.warn .copy-check-icon { background: rgba(180,105,14,.14); color: #B4690E; }
    .copy-check.tip  .copy-check-icon { background: rgba(66,44,112,.10);  color: var(--purple-300); }
    .copy-check.ok   .copy-check-icon { background: rgba(39,124,84,.12);  color: #277C54; }
    .copy-check.bad  .copy-check-text { color: #991b1b; }
    .copy-checks-foot { margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--gray-200); font-size: 11px; color: var(--gray-600); line-height: 1.5; }
    /* Which form a preview tab is showing. */
    .channel-form-note { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 10px 0 6px 0; font-size: 12px; color: var(--gray-600); line-height: 1.5; }
    .channel-form-pill { padding: 2px 8px; border-radius: 999px; font-size: 10px; font-weight: 600; letter-spacing: .02em; }
    .channel-form-pill.long  { background: rgba(66,44,112,.10); color: var(--purple-300); }
    .channel-form-pill.short { background: rgba(247,148,31,.14); color: #B4690E; }
    /* THE RECIPIENTS CARD. Arnold, 2026-08-18: "the box is odd, the font is
       bigger, spacing is different, labels/pills/tags are different". Measured
       in Chrome, he was describing three real things:

       1. SOLID, NOT DASHED. A dashed grey box is this app's note style — it is
          what .comms-config-note, .triggers-channel-info and .msghub-optin-note
          all use. This card holds the headline number of the page, so the
          container was saying "aside" while the contents said "read me first".
       2. ONE TYPE SCALE. The box carried EIGHT sizes (26/18/14/13/12.5/12/11/10)
          in about 300px. It is now three: the number, 13px body, 11px label.
          .msghub-dim is 14px app-wide, which made "to 11 people" LARGER than the
          table under it; scoped down here rather than changed globally, since it
          has 38 call sites.
       3. ONE SPACING RULE. Section gaps were inline styles applied at three of
          the four sites (12px, 2px, 4px, none). They live here now, so a new
          section cannot forget them. */
    .msghub-recipient-card { margin-top: 8px; padding: 14px; border-radius: 10px; background: var(--gray-100); border: 1px solid var(--gray-300); }
    /* SAME LABEL AS THE FORM IT SITS UNDER. This was an 11px uppercase
       letter-spaced label 20px below "Filter", which is 12px sentence case:
       two label systems in one column, which is the "labels are different" half
       of Arnold's report. Matched to .msghub-label rather than the other way
       round — the form labels are the ones repeated across the whole page. */
    .msghub-recipient-label { font-size: 12px; color: var(--gray-700); font-weight: 500; }
    .msghub-recipient-card .msghub-recipient-label { margin-top: 14px; }
    .msghub-recipient-card > .msghub-recipient-label:first-child { margin-top: 0; }
    .msghub-recipient-value { font-size: 13px; color: var(--gray-900); margin-top: 4px; }
    .msghub-recipient-value strong { font-size: 24px; color: var(--purple-300); font-variant-numeric: tabular-nums; }
    .msghub-recipient-card .msghub-dim { font-size: 12.5px; }
    .msghub-recipient-card .msghub-address-split { font-size: 12.5px; }
    .msghub-dim-block { line-height: 1.5; }
    .msghub-channel-none { margin-top: 6px; }
    /* A "dim" modifier should change the COLOUR of text, not its size. At a
       fixed 14px it was LARGER than most of what it qualifies — the table rows
       it sits in are 13px and .msghub-hint is 12px — so "· no delivery path
       yet" read as more important than the channel name beside it (Arnold,
       2026-08-19). It had already been patched down twice at individual call
       sites, which is the sign the rule itself was wrong.

       `inherit` leaves it at 14px wherever it sits directly in a panel (body is
       14px), so nothing that was right changes, and it finally follows the
       context everywhere else. */
    .msghub-dim { color: var(--gray-500); font-size: inherit; }
    .msghub-hint { margin-top: 8px; font-size: 12px; color: var(--gray-600); line-height: 1.5; }
    .msghub-hint code { font-family: "IBM Plex Mono", monospace; font-size: 11px; background: var(--gray-200); padding: 1px 5px; border-radius: 4px; }
    .msghub-channels { display: flex; flex-wrap: nowrap; gap: 6px; overflow-x: auto; padding-bottom: 2px; }
    .msghub-channels .msghub-channel { flex: 0 0 auto; white-space: nowrap; }
    .msghub-channel { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border: 1px solid var(--gray-200); border-radius: 8px; cursor: pointer; font-size: 13px; transition: border-color .12s, background .12s; }
    .msghub-channel:hover { background: var(--gray-100); }
    .msghub-channel.active { border-color: var(--purple-300); background: rgba(66,44,112,.06); color: var(--purple-300); font-weight: 500; }
    .msghub-channel.not-ready { color: var(--gray-600); }
    .msghub-channel input { margin: 0; }
    .msghub-channel-label { flex: 1; }
    .msghub-badge { font-size: 10px; padding: 1px 6px; border-radius: 99px; background: var(--gray-200); color: var(--gray-700); font-weight: 500; letter-spacing: .04em; }
    .msghub-actions { margin-top: 4px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
    .msghub-status { padding: 8px 12px; border-radius: 6px; font-size: 12px; line-height: 1.5; }
    .msghub-status.ok    { background: rgba(34,197,94,.12);  color: #166534; border: 1px solid rgba(34,197,94,.3); }
    .msghub-status.warn  { background: rgba(247,148,31,.12); color: #7a4b12; border: 1px solid rgba(247,148,31,.3); }
    .msghub-status.error { background: rgba(220,38,38,.12);  color: #991b1b; border: 1px solid rgba(220,38,38,.3); }

    [data-theme="dark"] .msghub-panel { background: var(--gray-800); border-color: var(--gray-700); }
    [data-theme="dark"] .msghub-radio,
    [data-theme="dark"] .msghub-channel { border-color: var(--gray-700); color: #e5e5ef; }
    [data-theme="dark"] .msghub-radio:hover,
    [data-theme="dark"] .msghub-channel:hover { background: rgba(255,255,255,.04); }
    [data-theme="dark"] .msghub-radio.active,
    [data-theme="dark"] .msghub-channel.active { border-color: var(--purple-200); background: rgba(94,55,142,.25); color: #fff; }
    [data-theme="dark"] .msghub-recipient-card { background: rgba(255,255,255,.03); border-color: var(--gray-700); }

    /* Verify audience modal — step 3 of the release flow. Lists the first
       ~20 recipients from the resolved audience so the operator can catch
       obvious filter mistakes before dispatch fires. */
    .verify-audience-summary { font-size: 13px; color: var(--gray-700); padding: 10px 12px; background: var(--gray-100); border: 1px dashed var(--gray-300); border-radius: 8px; margin-bottom: 12px; line-height: 1.55; }
    .verify-audience-summary strong { color: var(--gray-900); font-variant-numeric: tabular-nums; }
    .verify-audience-list { list-style: none; margin: 0; padding: 0; max-height: 380px; overflow-y: auto; border: 1px solid var(--gray-200); border-radius: 8px; }
    .verify-audience-row  { display: flex; align-items: baseline; gap: 12px; padding: 10px 12px; border-bottom: 1px solid var(--gray-100); }
    .verify-audience-row:last-of-type { border-bottom: none; }
    .verify-audience-idx  { flex-shrink: 0; width: 24px; font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--gray-500); text-align: right; }
    .verify-audience-body { flex: 1; min-width: 0; }
    .verify-audience-name { font-size: 13px; font-weight: 500; color: var(--gray-900); }
    .verify-audience-detail { font-size: 11.5px; color: var(--gray-600); margin-top: 2px; word-break: break-all; }
    .verify-audience-more  { margin-top: 10px; padding: 8px; border-radius: 8px; background: rgba(107,70,193,.06); font-family: 'IBM Plex Mono', monospace; font-size: 12px; color: var(--purple-300); text-align: center; }
    [data-theme="dark"] .verify-audience-summary { background: rgba(255,255,255,.04); border-color: var(--gray-700); color: var(--gray-300); }
    [data-theme="dark"] .verify-audience-summary strong { color: var(--gray-100); }
    [data-theme="dark"] .verify-audience-list { background: rgba(255,255,255,.03); border-color: var(--gray-700); }
    [data-theme="dark"] .verify-audience-row  { border-bottom-color: rgba(255,255,255,.05); }
    [data-theme="dark"] .verify-audience-name { color: var(--gray-100); }
    [data-theme="dark"] .verify-audience-detail { color: var(--gray-400); }
    [data-theme="dark"] .verify-audience-more { background: rgba(147,124,229,.12); color: #b8a4f5; }

    /* Sample-recipients card — the eye-check list of the first 15 people
       an audience filter resolves to. Sits directly below the recipient
       count card. Lightweight: names + community/country, one per row. */
    .msghub-sample-card { margin-top: 10px; padding: 12px 14px; border-radius: 10px; background: var(--white); border: 1px solid var(--gray-200); }
    .msghub-sample-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; gap: 8px; }
    .msghub-sample-title { font-size: 12px; font-weight: 600; color: var(--gray-800); text-transform: uppercase; letter-spacing: .05em; }
    .msghub-sample-count { font-size: 11px; color: var(--gray-500); font-family: 'IBM Plex Mono', monospace; }
    .msghub-sample-list { list-style: none; margin: 0; padding: 0; max-height: 260px; overflow-y: auto; }
    .msghub-sample-row  { display: flex; align-items: baseline; justify-content: space-between; padding: 6px 0; border-bottom: 1px solid var(--gray-100); gap: 12px; font-size: 12.5px; }
    .msghub-sample-row:last-of-type { border-bottom: none; }
    .msghub-sample-name  { color: var(--gray-900); font-weight: 500; }
    .msghub-sample-detail{ color: var(--gray-500); font-size: 11px; text-align: right; flex-shrink: 0; }
    .msghub-sample-more  { margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--gray-300); font-size: 11px; color: var(--gray-500); text-align: center; font-family: 'IBM Plex Mono', monospace; }
    [data-theme="dark"] .msghub-sample-card   { background: rgba(255,255,255,.03); border-color: var(--gray-700); }
    [data-theme="dark"] .msghub-sample-row    { border-bottom-color: rgba(255,255,255,.05); }
    [data-theme="dark"] .msghub-sample-name   { color: var(--gray-100); }
    [data-theme="dark"] .msghub-sample-detail { color: var(--gray-400); }
    [data-theme="dark"] .msghub-sample-more   { border-top-color: var(--gray-700); }
    [data-theme="dark"] .msghub-recipient-value strong { color: #c4b5fd; }
    [data-theme="dark"] .msghub-select,
    [data-theme="dark"] .msghub-input,
    [data-theme="dark"] .msghub-textarea { background: var(--gray-800); border-color: var(--gray-700); color: #e5e5ef; }
    [data-theme="dark"] .msghub-hint code { background: var(--gray-700); color: #e5e5ef; }
    [data-theme="dark"] .msghub-badge { background: var(--gray-700); color: var(--gray-400); }
    [data-theme="dark"] .msghub-form-badge.unused { background: var(--gray-700); color: var(--gray-400); }
    [data-theme="dark"] .copy-checks { background: var(--gray-800); border-color: var(--gray-700); }
    [data-theme="dark"] .copy-metric strong { color: #e5e5ef; }
    [data-theme="dark"] .copy-check { color: var(--gray-300); }
    [data-theme="dark"] .copy-check.bad .copy-check-text { color: #f0a09a; }
    [data-theme="dark"] .copy-check.bad  .copy-check-icon { background: rgba(240,160,154,.16); color: #f0a09a; }
    [data-theme="dark"] .copy-check.warn .copy-check-icon { background: rgba(240,196,120,.16); color: #f0c478; }
    [data-theme="dark"] .copy-check.tip  .copy-check-icon { background: rgba(196,181,253,.16); color: #c4b5fd; }
    [data-theme="dark"] .copy-checks-foot { border-top-color: var(--gray-700); }
    [data-theme="dark"] .msghub-charcount.near { color: #f0c478; }
    [data-theme="dark"] .msghub-charcount.over { color: #f0a09a; }
    [data-theme="dark"] .channel-form-pill.long  { background: rgba(196,181,253,.16); color: #c4b5fd; }
    [data-theme="dark"] .channel-form-pill.short { background: rgba(247,148,31,.18); color: #f0c478; }

    /* ─── Action Triggers ─── */
    .triggers-grid { display: grid; grid-template-columns: minmax(240px, 320px) 1fr; gap: 20px; align-items: start; }
    @media (max-width: 1000px) { .triggers-grid { grid-template-columns: 1fr; } }
    /* Left column stays put; only its content scrolls when the trigger list
       grows past the viewport. Sticky top matches the app's fixed topbar so
       the list doesn't slide under it, and the right-hand editor can grow as
       tall as it likes without pushing the list away. */
    .triggers-list { display: flex; flex-direction: column; gap: 18px; position: sticky; top: 16px; max-height: calc(100vh - 96px); overflow-y: auto; padding-right: 6px; }
    @media (max-width: 1000px) { .triggers-list { position: static; max-height: none; overflow-y: visible; padding-right: 0; } }
    .triggers-category-h { font-size: 11px; font-weight: 600; color: var(--gray-600); text-transform: uppercase; letter-spacing: .08em; margin-bottom: 6px; padding: 0 4px; }
    .triggers-row { display: flex; gap: 12px; align-items: center; padding: 12px 14px; background: var(--white); border: 1px solid var(--gray-200); border-radius: 10px; margin-bottom: 6px; cursor: pointer; transition: border-color .12s, box-shadow .12s; }
    .triggers-row:hover { border-color: var(--purple-200); }
    .triggers-row.selected { border-color: var(--purple-300); box-shadow: 0 0 0 1px var(--purple-300) inset; }
    .triggers-row-body { flex: 1; min-width: 0; }
    .triggers-row-name { font-weight: 500; color: var(--gray-900); font-size: 13.5px; }
    .triggers-row-desc { font-size: 12px; color: var(--gray-600); margin-top: 2px; line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .triggers-row-meta { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
    .triggers-badge { font-size: 10px; padding: 1px 8px; border-radius: 99px; background: var(--gray-200); color: var(--gray-700); text-transform: uppercase; letter-spacing: .04em; font-weight: 500; }
    .triggers-updated { font-size: 10px; color: var(--gray-500); }

    .triggers-toggle { position: relative; display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; }
    .triggers-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
    .triggers-toggle-slider { width: 36px; height: 20px; background: var(--gray-300); border-radius: 99px; position: relative; transition: background .15s; flex-shrink: 0; }
    .triggers-toggle-slider::after { content: ''; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background: var(--white); border-radius: 50%; transition: transform .15s; box-shadow: 0 1px 2px rgba(0,0,0,.15); }
    .triggers-toggle.on .triggers-toggle-slider { background: var(--purple-300); }
    .triggers-toggle.on .triggers-toggle-slider::after { transform: translateX(16px); }
    .triggers-toggle-label { font-size: 12px; color: var(--gray-700); }

    .triggers-editor { position: sticky; top: 12px; }
    .triggers-editor-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 16px; }
    .triggers-editor-sub { font-size: 12.5px; color: var(--gray-600); line-height: 1.5; max-width: 520px; }
    .triggers-channel-info { padding: 10px 14px; background: var(--gray-100); border: 1px dashed var(--gray-300); border-radius: 8px; font-size: 12.5px; line-height: 1.55; color: var(--gray-700); }
    .triggers-channel-info strong { color: var(--gray-900); }
    [data-theme="dark"] .triggers-channel-info { background: rgba(255,255,255,.03); border-color: var(--gray-700); color: var(--gray-400); }
    [data-theme="dark"] .triggers-channel-info strong { color: #e5e5ef; }

    [data-theme="dark"] .triggers-row { background: var(--gray-800); border-color: var(--gray-700); }
    [data-theme="dark"] .triggers-row:hover { border-color: var(--purple-200); }
    [data-theme="dark"] .triggers-row.selected { border-color: var(--purple-200); box-shadow: 0 0 0 1px var(--purple-200) inset; }
    [data-theme="dark"] .triggers-row-name { color: #e5e5ef; }
    [data-theme="dark"] .triggers-badge { background: var(--gray-700); color: var(--gray-300); }
    [data-theme="dark"] .triggers-toggle-slider { background: var(--gray-700); }
    [data-theme="dark"] .triggers-toggle.on .triggers-toggle-slider { background: var(--purple-200); }

    .triggers-row-emoji { font-size: 15px; margin-right: 2px; }
    .triggers-row-pill { margin: 4px 0 2px; }
    .triggers-sublevel-pill { display: inline-block; padding: 1px 8px; border-radius: 99px; color: #fff; font-size: 10px; font-weight: 600; letter-spacing: .02em; font-variant-numeric: tabular-nums; vertical-align: middle; }

    .triggers-sublevel-group { margin-bottom: 10px; }
    .triggers-sublevel-group:last-child { margin-bottom: 0; }
    .triggers-sublevel-h { display: flex; align-items: center; gap: 8px; padding: 6px 4px 4px; font-size: 11px; font-weight: 600; color: var(--gray-700); letter-spacing: .02em; }
    .triggers-sublevel-h-label { line-height: 1.2; }
    .triggers-sublevel-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
    [data-theme="dark"] .triggers-sublevel-h { color: #cfcfe5; }

    /* ─── Communication Configuration ─── */
    .comms-config-intro { margin: 16px 0 12px; }
    .comms-config-h { font-size: 15px; font-weight: 600; color: var(--gray-900); margin: 0 0 4px; }
    .comms-config-sub { font-size: 13px; color: var(--gray-600); line-height: 1.55; margin: 0; max-width: 720px; }
    [data-theme="dark"] .comms-config-h { color: #e5e5ef; }
    [data-theme="dark"] .comms-config-sub { color: var(--gray-400); }

    .comms-config-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 14px; }
    .comms-config-card { background: var(--white); border: 1px solid var(--gray-200); border-radius: 12px; padding: 16px 18px; display: flex; flex-direction: column; gap: 10px; }
    .comms-config-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
    .comms-config-card-title { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; color: var(--gray-900); }
    .comms-config-card-emoji { font-size: 18px; line-height: 1; }
    .comms-config-status { font-size: 10px; padding: 2px 8px; border-radius: 99px; letter-spacing: .04em; text-transform: uppercase; font-weight: 600; }
    .comms-config-status.ready { background: rgba(16,185,129,.15); color: #047857; }
    .comms-config-status.pending { background: var(--gray-200); color: var(--gray-700); }
    .comms-config-card-blurb { font-size: 12.5px; color: var(--gray-700); line-height: 1.5; }
    .comms-config-card-callout { border: 1px solid; border-radius: 8px; padding: 10px 12px; font-size: 12.5px; line-height: 1.5; }
    .comms-config-card-callout.warn { background: rgba(247,148,31,.08); border-color: rgba(247,148,31,.35); color: #7a4b12; }
    .comms-config-card-callout.ok   { background: rgba(34,197,94,.08);  border-color: rgba(34,197,94,.35);  color: #166534; }
    .comms-config-card-callout code { font-family: 'IBM Plex Mono', monospace; font-size: 11.5px; background: rgba(0,0,0,.05); padding: 1px 5px; border-radius: 4px; }
    [data-theme="dark"] .comms-config-card-callout.warn { color: #f7ba7d; background: rgba(247,148,31,.14); }
    [data-theme="dark"] .comms-config-card-callout.ok   { color: #86efac; background: rgba(34,197,94,.14); }
    [data-theme="dark"] .comms-config-card-callout code { background: rgba(255,255,255,.08); }
    .comms-config-card-provider { display: flex; align-items: center; gap: 8px; font-size: 12px; }
    .comms-config-card-provider-label { color: var(--gray-500); text-transform: uppercase; letter-spacing: .04em; font-weight: 600; font-size: 10px; }
    .comms-config-card-provider-value { color: var(--gray-800); font-weight: 500; }
    .comms-config-setup { display: flex; flex-direction: column; gap: 4px; margin: 4px 0 0; padding: 10px 12px; background: var(--gray-100); border-radius: 8px; }
    .comms-config-setup-row { display: grid; grid-template-columns: 130px 1fr; gap: 10px; font-size: 12px; line-height: 1.5; }
    .comms-config-setup-row dt { color: var(--gray-500); text-transform: uppercase; letter-spacing: .04em; font-weight: 600; font-size: 10px; margin: 3px 0 0; }
    .comms-config-setup-row dd { margin: 0; color: var(--gray-800); }
    .comms-config-note { margin-top: 18px; padding: 12px 16px; background: var(--gray-100); border: 1px dashed var(--gray-300); border-radius: 10px; font-size: 12.5px; line-height: 1.55; color: var(--gray-700); }
    .comms-config-note strong { color: var(--gray-900); }
    .comms-config-note code { background: var(--white); border: 1px solid var(--gray-200); border-radius: 4px; padding: 1px 5px; font-size: 12px; }

    /* ─── Message Hub — Opt-in filter toggle ─── */
    /* Primary/secondary address split under the Recipients number. Sits between
       the count and the explanatory hint, so it reads as a breakdown of the
       number above rather than a new fact. */
    .msghub-address-split { margin-top: 4px; display: flex; gap: 6px; align-items: baseline; font-size: 12px; color: var(--gray-700); }
    .msghub-address-split strong { font-variant-numeric: tabular-nums; }
    /* Sentence case since 2026-08-18: with the labels around it no longer
       shouting, a 10px uppercase pill was the loudest thing in the card after
       the number itself, which is not what it ranks. */
    .msghub-optin-badge { display: inline-block; margin-left: 8px; padding: 2px 8px; border-radius: 99px; background: rgba(13,148,136,.15); color: #0f766e; font-size: 11px; font-weight: 600; vertical-align: middle; }
    [data-theme="dark"] .msghub-optin-badge { background: rgba(13,148,136,.25); color: #5eead4; }
    .msghub-optin-toggle { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; margin: 12px 0 8px; }
    .msghub-optin-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
    .msghub-optin-slider { width: 36px; height: 20px; background: var(--gray-300); border-radius: 99px; position: relative; transition: background .15s; flex-shrink: 0; }
    .msghub-optin-slider::after { content: ''; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; background: var(--white); border-radius: 50%; transition: transform .15s; box-shadow: 0 1px 2px rgba(0,0,0,.15); }
    .msghub-optin-toggle input:checked + .msghub-optin-slider { background: #0d9488; }
    .msghub-optin-toggle input:checked + .msghub-optin-slider::after { transform: translateX(16px); }
    .msghub-optin-label { font-size: 13px; color: var(--gray-800); font-weight: 500; }
    [data-theme="dark"] .msghub-optin-slider { background: var(--gray-700); }
    [data-theme="dark"] .msghub-optin-label { color: #e5e5ef; }
    .msghub-optin-note { font-size: 11.5px; color: var(--gray-600); line-height: 1.5; padding: 8px 10px; border-radius: 6px; background: var(--gray-100); border: 1px dashed var(--gray-300); }
    .msghub-optin-note strong { color: var(--gray-900); }
    .msghub-optin-note code { background: var(--white); border: 1px solid var(--gray-200); border-radius: 3px; padding: 1px 5px; font-size: 11px; }
    .msghub-optin-note a { color: var(--purple-300); text-decoration: underline; }
    [data-theme="dark"] .msghub-optin-note { background: rgba(255,255,255,.03); border-color: var(--gray-700); color: var(--gray-400); }
    [data-theme="dark"] .msghub-optin-note strong { color: #e5e5ef; }
    [data-theme="dark"] .msghub-optin-note code { background: var(--gray-800); border-color: var(--gray-700); color: #e5e5ef; }
    [data-theme="dark"] .msghub-optin-note a { color: #c4b5fd; }

    /* ─── Message Hub — Password gate modal ─── */
    .msghub-pw-modal { max-width: 520px; padding: 22px 24px 20px; }
    .msghub-pw-title { font-size: 17px; font-weight: 600; color: var(--gray-900); margin: 0 0 14px; }
    .msghub-large-audience-warn { margin: 0 0 14px; padding: 10px 12px; border-radius: 6px; background: #fef2f2; border: 1px solid #fecaca; color: #7f1d1d; font-size: 12px; line-height: 1.45; }
    .msghub-large-audience-warn strong { color: #991b1b; }
    [data-theme="dark"] .msghub-large-audience-warn { background: rgba(220, 38, 38, .12); border-color: rgba(220, 38, 38, .35); color: #fca5a5; }
    [data-theme="dark"] .msghub-large-audience-warn strong { color: #fecaca; }
    [data-theme="dark"] .msghub-pw-title { color: #e5e5ef; }
    [data-theme="dark"] .msghub-pw-modal { background: var(--gray-800); }
    [data-theme="dark"] .msghub-pw-value code { background: var(--gray-800); border-color: #b45309; color: #fed7aa; }
    [data-theme="dark"] .comms-config-card { background: var(--gray-800); border-color: var(--gray-700); }
    [data-theme="dark"] .comms-config-card-title { color: #e5e5ef; }
    [data-theme="dark"] .comms-config-card-blurb { color: var(--gray-300); }
    [data-theme="dark"] .comms-config-card-provider-value { color: #e5e5ef; }
    [data-theme="dark"] .comms-config-status.ready { background: rgba(16,185,129,.2); color: #6ee7b7; }
    [data-theme="dark"] .comms-config-status.pending { background: var(--gray-700); color: var(--gray-300); }
    [data-theme="dark"] .comms-config-setup { background: rgba(255,255,255,.03); }
    [data-theme="dark"] .comms-config-setup-row dd { color: #e5e5ef; }
    [data-theme="dark"] .comms-config-note { background: rgba(255,255,255,.03); border-color: var(--gray-700); color: var(--gray-400); }
    [data-theme="dark"] .comms-config-note strong { color: #e5e5ef; }
    [data-theme="dark"] .comms-config-note code { background: var(--gray-800); border-color: var(--gray-700); color: #e5e5ef; }

    /* ─── Rich Text Editor (Notifications Engine) ─── */
    .rte { border: 1px solid var(--gray-300); border-radius: 8px; overflow: hidden; background: var(--white); }
    .rte:focus-within { outline: 2px solid var(--purple-200); outline-offset: -1px; }
    .rte-toolbar { display: flex; align-items: center; gap: 2px; padding: 6px 8px; border-bottom: 1px solid var(--gray-200); background: var(--gray-100); flex-wrap: wrap; }
    .rte-btn { padding: 4px 8px; border: 1px solid transparent; background: transparent; border-radius: 4px; cursor: pointer; font-size: 12px; color: var(--gray-800); font-family: inherit; line-height: 1.2; min-width: 26px; }
    .rte-btn:hover { background: var(--white); border-color: var(--gray-300); }
    .rte-btn:active { background: var(--gray-200); }
    .rte-sep { display: inline-block; width: 1px; height: 18px; background: var(--gray-300); margin: 0 4px; }
    .rte-surface { padding: 14px 16px; min-height: 260px; outline: none; font-size: 14px; line-height: 1.6; color: var(--gray-900); }
    .rte-surface:empty::before { content: attr(data-placeholder); color: var(--gray-500); pointer-events: none; }
    .rte-surface h1 { font-size: 22px; margin: 16px 0 8px; font-weight: 700; line-height: 1.3; }
    .rte-surface h2 { font-size: 18px; margin: 14px 0 6px; font-weight: 600; line-height: 1.35; }
    .rte-surface h3 { font-size: 15px; margin: 12px 0 4px;  font-weight: 600; line-height: 1.4; }
    .rte-surface p  { margin: 0 0 10px; }
    .rte-surface ul, .rte-surface ol { margin: 8px 0 12px; padding-left: 24px; }
    .rte-surface li { margin: 3px 0; }
    .rte-surface a { color: var(--purple-300); text-decoration: underline; }
    .rte-surface img { max-width: 100%; height: auto; border-radius: 6px; margin: 6px 0; }
    .rte-surface blockquote { margin: 8px 0; padding: 4px 12px; border-left: 3px solid var(--purple-200); color: var(--gray-700); font-style: italic; background: var(--gray-100); border-radius: 0 6px 6px 0; }

    [data-theme="dark"] .rte { background: var(--gray-800); border-color: var(--gray-700); }
    [data-theme="dark"] .rte-toolbar { background: rgba(255,255,255,.04); border-bottom-color: var(--gray-700); }
    [data-theme="dark"] .rte-btn { color: #e5e5ef; }
    [data-theme="dark"] .rte-btn:hover { background: var(--gray-700); border-color: var(--gray-700); }
    [data-theme="dark"] .rte-btn:active { background: rgba(255,255,255,.08); }
    [data-theme="dark"] .rte-sep { background: var(--gray-700); }
    [data-theme="dark"] .rte-surface { color: #e5e5ef; }
    [data-theme="dark"] .rte-surface a { color: #c4b5fd; }
    [data-theme="dark"] .rte-surface blockquote { background: rgba(255,255,255,.04); border-left-color: var(--purple-200); color: var(--gray-300); }

    /* Link / Image / Embed insert modals opened from the RTE toolbar. */
    .rte-insert-form { display: flex; flex-direction: column; gap: 6px; }
    .rte-insert-form .msghub-input { margin-bottom: 8px; }
    .rte-insert-form .msghub-input:last-of-type { margin-bottom: 0; }
    .rte-insert-label { font-size: 12px; font-weight: 600; color: var(--gray-800); margin: 4px 0 2px; display: flex; align-items: baseline; gap: 6px; }
    .rte-insert-hint { font-size: 11px; font-weight: 400; color: var(--gray-600); font-style: normal; }
    .rte-insert-error { margin-top: 6px; padding: 8px 10px; background: #fef2f2; border: 1px solid #fecaca; border-radius: 4px; color: #991b1b; font-size: 12px; }
    .rte-insert-preview { margin-top: 10px; padding: 10px; border: 1px dashed var(--gray-300); border-radius: 6px; background: var(--gray-100); }
    .rte-insert-preview-label { font-size: 10px; text-transform: uppercase; letter-spacing: .04em; color: var(--gray-600); margin-bottom: 6px; font-family: 'IBM Plex Mono', monospace; }
    .rte-insert-preview img { max-width: 100%; max-height: 160px; display: block; margin: 0 auto; border-radius: 4px; }

    /* Alignment picker in the Insert-button modal. Two buttons rather than a
       <select>: .modal-card clips an open dropdown at short viewport heights. */
    .rte-align-row { display: flex; gap: 6px; margin-bottom: 4px; }
    .rte-align-row .rte-btn { min-height: 32px; padding: 6px 14px; border-color: var(--gray-300); }
    .rte-btn.is-active { background: var(--purple-300); border-color: var(--purple-300); color: var(--white); }
    .rte-btn.is-active:hover { background: var(--purple-400); border-color: var(--purple-400); color: var(--white); }
    /* The preview renders the real email button, whose own inline styles carry the
       brand fill. Only the surrounding box is themed here. */
    .rte-insert-preview table { margin: 0 !important; }

    [data-theme="dark"] .rte-insert-label { color: #e5e5ef; }
    [data-theme="dark"] .rte-align-row .rte-btn { border-color: var(--gray-700); }
    [data-theme="dark"] .rte-btn.is-active { color: var(--white); }
    [data-theme="dark"] .rte-insert-hint { color: var(--gray-400); }
    [data-theme="dark"] .rte-insert-error { background: rgba(153, 27, 27, .18); border-color: rgba(220, 38, 38, .35); color: #fca5a5; }
    [data-theme="dark"] .rte-insert-preview { background: rgba(255,255,255,.03); border-color: var(--gray-700); }

    /* Preview + Send-test action row under the body editor. Shared between
       Message Hub and Action Triggers. */
    .composer-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
    .composer-preview { display: flex; flex-direction: column; }
    .composer-preview-meta { margin-bottom: 10px; padding: 10px 12px; background: var(--gray-100); border: 1px solid var(--gray-200); border-radius: 6px; font-size: 13px; }
    .composer-preview-label { display: inline-block; min-width: 56px; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--gray-600); font-family: 'IBM Plex Mono', monospace; margin-right: 6px; }
    .composer-preview-frame { width: 100%; height: 460px; border: 1px solid var(--gray-300); border-radius: 6px; background: #fff; }
    [data-theme="dark"] .composer-preview-meta { background: rgba(255,255,255,.03); border-color: var(--gray-700); }
    [data-theme="dark"] .composer-preview-frame { border-color: var(--gray-700); }

    /* Tabbed multi-channel preview modal. Tabs live at the top; each tab
       shows how the message renders on that channel (email iframe, plain
       text for the others). "wired/pending" badge sits inside each tab. */
    .channel-tabs { display: flex; gap: 4px; border-bottom: 1.5px solid var(--gray-200); margin-bottom: 12px; flex-wrap: wrap; }
    .channel-tab { background: none; border: none; border-bottom: 2px solid transparent; padding: 8px 12px; font-family: inherit; font-size: 13px; color: var(--gray-700); cursor: pointer; display: inline-flex; align-items: center; gap: 8px; margin-bottom: -1.5px; transition: color .12s, border-color .12s; }
    .channel-tab:hover  { color: var(--purple-300); }
    .channel-tab.active { color: var(--purple-300); border-bottom-color: var(--orange-400); font-weight: 600; }
    .channel-tab-badge { font-size: 9px; text-transform: uppercase; letter-spacing: .05em; padding: 2px 6px; border-radius: 99px; font-weight: 600; }
    .channel-tab-badge.ready   { background: rgba(34,197,94,.14);  color: #166534; }
    .channel-tab-badge.pending { background: rgba(148,163,184,.20); color: #475569; }
    .channel-tab-panel { min-height: 480px; }
    .channel-preview-body { font-size: 13px; color: var(--gray-800); line-height: 1.5; }
    .channel-preview-text { white-space: pre-wrap; word-break: break-word; background: #fff; border: 1px solid var(--gray-200); border-radius: 6px; padding: 12px 14px; margin: 0; font-family: 'IBM Plex Mono', monospace; font-size: 12.5px; max-height: 420px; overflow-y: auto; }

    /* ─── Per-channel preview mockups ───────────────────────────────────
       Each channel's tab renders a stylized approximation of the native
       chrome (Telegram, Nostr, WhatsApp, MFB App). The mockups don't
       have to be pixel-perfect — they just have to feel right enough that
       the composer can eyeball how long-form copy, links, and bold/italic
       will land on that channel before the delivery pipes are wired.
       Everything is inline-styled to survive the composer preview modal's
       background regardless of theme. */
    .channel-mockup { max-height: 460px; overflow-y: auto; border-radius: 10px; }
    .channel-mockup-empty { color: rgba(0,0,0,.4); font-style: italic; }

    /* Telegram — light desktop client. */
    .tg-mockup { background: #E7EBF0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; color: #000; }
    .tg-header { display: flex; align-items: center; gap: 12px; background: #FFFFFF; padding: 10px 16px; border-bottom: 1px solid #DEE3EA; }
    .tg-avatar { width: 36px; height: 36px; border-radius: 50%; background: linear-gradient(135deg, #46A9E8 0%, #5AB8F5 100%); color: #fff; font-weight: 600; font-size: 15px; display: inline-flex; align-items: center; justify-content: center; }
    .tg-header-meta { line-height: 1.25; }
    .tg-header-title { font-size: 14px; font-weight: 600; color: #000; }
    .tg-header-sub { font-size: 12px; color: #707579; }
    .tg-chat { padding: 20px 16px 24px; display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
    .tg-bubble { background: #FFFFFF; border-radius: 12px 12px 12px 0; padding: 8px 12px 6px 14px; max-width: 82%; box-shadow: 0 1px 2px rgba(16,35,47,.08); font-size: 14.5px; line-height: 1.42; color: #222; }
    .tg-subject { font-weight: 600; color: #168ACD; margin-bottom: 4px; }
    .tg-para { margin: 0 0 6px 0; white-space: pre-wrap; word-break: break-word; }
    .tg-para:last-of-type { margin-bottom: 4px; }
    .tg-para strong { font-weight: 600; }
    .tg-para em { font-style: italic; color: #333; }
    .tg-para a { color: #168ACD; text-decoration: none; }
    .tg-para a:hover { text-decoration: underline; }
    .tg-time { font-size: 11px; color: #707579; text-align: right; margin-top: 4px; }
    .tg-check { color: #4FAE4E; }

    /* Nostr DM — Damus-lean row treatment on a dark card. */
    .nostr-mockup { background: #14141C; color: #E8E8F2; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
    .nostr-header { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid rgba(255,255,255,.08); }
    /* #7B3AED is Nostr's own violet, not an MFB colour — same exception the
       --b4j sky-blue takes above. Kept literal so the third-party service
       reads as itself rather than as brand chrome. */
    .nostr-avatar { width: 34px; height: 34px; border-radius: 50%; background: linear-gradient(135deg, #7B3AED 0%, #F7941F 100%); color: #fff; font-size: 17px; line-height: 1; display: inline-flex; align-items: center; justify-content: center; }
    .nostr-header-meta { flex: 1; line-height: 1.25; }
    .nostr-header-title { font-size: 14px; font-weight: 600; color: #FFFFFF; }
    .nostr-header-sub { font-size: 12px; color: #8B8DA3; font-family: 'IBM Plex Mono', monospace; }
    .nostr-encrypted { font-size: 10px; color: #A3E635; background: rgba(163,230,53,.10); border: 1px solid rgba(163,230,53,.25); padding: 3px 8px; border-radius: 999px; letter-spacing: .04em; text-transform: uppercase; font-weight: 600; }
    .nostr-body { padding: 16px 18px; font-size: 14.5px; line-height: 1.55; color: #D9D9E7; }
    .nostr-para { margin: 0 0 12px 0; white-space: pre-wrap; word-break: break-word; }
    .nostr-para:last-of-type { margin-bottom: 6px; }
    .nostr-time { font-size: 11px; color: #6E7085; font-family: 'IBM Plex Mono', monospace; margin-top: 8px; }

    /* WhatsApp — light UI with green outbound bubble. */
    .wa-mockup { background: #ECE5DD; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; color: #000; position: relative; }
    /* Subtle doodle-y background dots, WhatsApp-esque. */
    .wa-mockup::before { content: ''; position: absolute; inset: 0; background-image: radial-gradient(rgba(0,0,0,.03) 1px, transparent 1px); background-size: 10px 10px; pointer-events: none; }
    .wa-header { position: relative; display: flex; align-items: center; gap: 12px; background: #075E54; color: #fff; padding: 10px 16px; }
    .wa-avatar { width: 36px; height: 36px; border-radius: 50%; background: #128C7E; color: #fff; font-weight: 700; font-size: 15px; display: inline-flex; align-items: center; justify-content: center; }
    .wa-header-meta { line-height: 1.25; }
    .wa-header-title { font-size: 14px; font-weight: 600; color: #fff; }
    .wa-header-sub { font-size: 12px; color: #A9DED4; }
    .wa-chat { position: relative; padding: 18px 16px 22px; display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
    .wa-bubble { background: #DCF8C6; border-radius: 8px 0 8px 8px; padding: 8px 12px 6px 12px; max-width: 82%; box-shadow: 0 1px 1px rgba(0,0,0,.08); font-size: 14.5px; line-height: 1.42; color: #111; }
    .wa-subject { font-weight: 600; color: #075E54; margin-bottom: 4px; }
    .wa-para { margin: 0 0 6px 0; white-space: pre-wrap; word-break: break-word; }
    .wa-para:last-of-type { margin-bottom: 4px; }
    .wa-para strong { font-weight: 700; }
    .wa-para em { font-style: italic; }
    .wa-para a { color: #039BE5; text-decoration: none; }
    .wa-para a:hover { text-decoration: underline; }
    .wa-time { font-size: 11px; color: rgba(0,0,0,.45); text-align: right; margin-top: 4px; }
    .wa-check { color: #34B7F1; }

    /* MFB App push — iOS-style lock-screen card. */
    .app-mockup { background: linear-gradient(180deg, #1E1B4B 0%, #0F172A 100%); padding: 32px 20px 20px 20px; color: #fff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; text-align: center; }
    .app-lockscreen-time { margin-bottom: 20px; }
    .app-lock-time { font-size: 62px; font-weight: 200; letter-spacing: -.02em; line-height: 1; color: #fff; }
    .app-lock-date { font-size: 14px; color: rgba(255,255,255,.7); margin-top: 4px; }
    .app-push-card { background: rgba(255,255,255,.12); backdrop-filter: blur(20px); border-radius: 14px; padding: 12px 14px; text-align: left; box-shadow: 0 8px 24px rgba(0,0,0,.28); border: 1px solid rgba(255,255,255,.10); max-width: 380px; margin: 0 auto; }
    .app-push-head { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; font-size: 12px; color: rgba(255,255,255,.75); }
    .app-push-icon { width: 22px; height: 22px; border-radius: 5px; background: linear-gradient(135deg, #F7941F 0%, #7B3AED 100%); display: inline-flex; align-items: center; justify-content: center; }
    .app-push-icon-b { font-size: 14px; font-weight: 700; color: #fff; font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
    .app-push-app-name { font-weight: 600; color: rgba(255,255,255,.85); text-transform: uppercase; letter-spacing: .05em; font-size: 11px; }
    .app-push-time { margin-left: auto; font-size: 11px; color: rgba(255,255,255,.55); }
    .app-push-title { font-size: 14.5px; font-weight: 600; color: #fff; line-height: 1.3; margin-bottom: 3px; }
    .app-push-body  { font-size: 13.5px; color: rgba(255,255,255,.85); line-height: 1.4; word-break: break-word; }
    .app-push-hint  { margin-top: 20px; font-size: 11px; color: rgba(255,255,255,.55); }
    [data-theme="dark"] .channel-tabs { border-bottom-color: var(--gray-700); }
    [data-theme="dark"] .channel-tab   { color: var(--gray-300); }
    [data-theme="dark"] .channel-tab-badge.ready   { background: rgba(34,197,94,.20);  color: #86efac; }
    [data-theme="dark"] .channel-tab-badge.pending { background: rgba(148,163,184,.20); color: #cbd5e1; }
    [data-theme="dark"] .channel-preview-body  { color: var(--gray-200); }
    [data-theme="dark"] .channel-preview-text  { background: rgba(0,0,0,.25); border-color: var(--gray-700); color: var(--gray-100); }

    /* Sender signature card — sits between the body editor and the save-draft
       row, mirroring where the signature lands in the email itself (after the
       body, before the postal address and unsubscribe line). The .msghub-sig-body
       holds operator-authored HTML, so its child spacing is normalised here. */
    /* WHITE, not grey. The body of this card is the operator's own signature
       HTML, and it is authored against the white background of an email client,
       so showing it on grey misreports what the recipient will see. */
    .msghub-sig-card { border: 1px solid var(--gray-200); border-radius: 10px; background: var(--white); overflow: hidden; }
    .msghub-sig-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding: 10px 14px; border-bottom: 1px solid var(--gray-200); }
    .msghub-sig-who { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-size: 13px; color: var(--gray-900); min-width: 0; }
    .msghub-sig-who .msghub-dim { font-size: 12px; word-break: break-all; }
    .msghub-sig-body { padding: 14px; font-size: 14px; line-height: 1.6; color: var(--gray-900); word-wrap: break-word; }
    .msghub-sig-body > :first-child { margin-top: 0; }
    .msghub-sig-body > :last-child { margin-bottom: 0; }
    .msghub-sig-body p { margin: 0 0 8px; }
    .msghub-sig-body img { max-width: 100%; height: auto; }
    .msghub-sig-body a { color: var(--purple-300); }
    .msghub-sig-empty { padding: 14px; font-size: 13px; color: var(--gray-600); line-height: 1.5; }

    [data-theme="dark"] .msghub-sig-card  { background: rgba(255,255,255,.03); border-color: var(--gray-700); }
    [data-theme="dark"] .msghub-sig-head  { border-bottom-color: var(--gray-700); }
    [data-theme="dark"] .msghub-sig-who   { color: var(--gray-100); }
    [data-theme="dark"] .msghub-sig-body  { color: var(--gray-200); }
    [data-theme="dark"] .msghub-sig-body a { color: #c4b5fd; }
    [data-theme="dark"] .msghub-sig-empty { color: var(--gray-400); }

    /* On a phone the sender line and the Edit button stop sharing a row: the
       button goes full width so it keeps a 44px touch target instead of being
       squeezed next to a wrapping email address. */
    @media (max-width: 768px) {
      .msghub-sig-head { align-items: stretch; }
      .msghub-sig-head .btn { width: 100%; min-height: 44px; justify-content: center; }
    }

    /* Save-draft row — sits between the body editor and the Release block. */

    /* Guided 3-step release flow — one card containing three step-rows for
       Preview → Send test → Send. Each row has a numbered badge on the left,
       title/subtitle in the middle, and its action button on the right.
       Rows carry .done / .current / .locked state; locked rows dim their
       action button and copy so the flow visibly gates from step to step. */
    .send-flow { margin: 14px 0 6px; border: 1px solid var(--gray-300); border-radius: 10px; background: var(--white); overflow: hidden; }
    .send-flow-head { padding: 10px 14px; background: linear-gradient(90deg, rgba(107,70,193,.06), rgba(247,148,31,.06)); border-bottom: 1px solid var(--gray-200); display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
    .send-flow-title { font-size: 13px; font-weight: 600; color: var(--purple-300); letter-spacing: -.005em; }
    /* The weekly chart's window and its reading caveats, on the panel title where
       its 8 / 12 / 26 / 52-week buttons used to be: the window is now the page's
       single period filter, so this states it rather than offering a second one.
       Dotted underline because the caveats are in the tooltip and nothing else on
       the line would say so. */
    .comms-chart-window { font-size: 12px; margin-left: auto; border-bottom: 1px dotted var(--gray-400); cursor: help; }

    /* HelpTip: the `?` that carries a caveat without spending a paragraph on it
       (Arnold, 2026-08-28). Sized and positioned like .kw-icon, whose behaviour
       it generalises; the body is fixed-position so it escapes any overflow clip
       it sits inside. */
    /* Panel heading with an action on the right: the same plain heading its
       sibling panels use, not the gradient strip the charts carry. An action put
       INSIDE the h3 inherits the heading's line box and sits a few pixels off
       the text beside it, which is what the CSV button on All sends was doing. */
    /* Same-person merge selection (Arnold, 2026-08-28). The bar only exists
       while something is picked, so it never takes space from the candidate
       list it sits above. */
    .dup-pick { margin-right: 8px; vertical-align: middle; accent-color: var(--purple-300); cursor: pointer; }
    .dup-merge-bar {
      display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap;
      margin-bottom: 14px; padding: 12px 14px;
      background: var(--gray-100); border: 1px solid var(--gray-200); border-radius: 10px;
    }
    .dup-merge-actions { display: flex; gap: 8px; margin-left: auto; }
    .dup-merge-cmd {
      flex: 1 1 100%; margin-top: 4px; padding: 8px 10px;
      background: var(--white); border: 1px solid var(--gray-200); border-radius: 6px;
      font-family: "IBM Plex Mono", monospace; font-size: 11px; color: var(--gray-800);
      overflow-x: auto; white-space: pre; display: block;
    }
    [data-theme="dark"] .dup-merge-bar { background: rgba(255,255,255,.04); border-color: var(--gray-700); }
    [data-theme="dark"] .dup-merge-cmd { background: rgba(0,0,0,.25); border-color: var(--gray-700); color: var(--gray-200); }

    .panel-head-row,
    .audience-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
    .panel-head-row .comms-h { flex: 1 1 auto; min-width: 0; }

    .help-tip { position: relative; display: inline-block; cursor: help; vertical-align: middle; }
    .help-tip-glyph {
      display: inline-flex; align-items: center; justify-content: center;
      width: 16px; height: 16px; margin-left: 6px;
      border: 1px solid var(--gray-300); border-radius: 50%;
      font-size: 10px; font-weight: 600; line-height: 1;
      color: var(--gray-600); opacity: .75; transition: opacity .15s, border-color .15s, color .15s;
    }
    .help-tip:hover .help-tip-glyph, .help-tip:focus .help-tip-glyph,
    .help-tip-glyph.on { opacity: 1; border-color: var(--purple-300); color: var(--purple-300); }
    .help-tip-body {
      position: fixed; transform: translate(-100%, calc(-100% - 8px));
      background: #1f2937; color: #fff; padding: 9px 12px; border-radius: 7px;
      font-size: 11.5px; line-height: 1.5; font-weight: 400;
      white-space: pre-wrap; word-break: break-word;
      max-width: 340px; width: max-content; pointer-events: none; z-index: 9999;
      box-shadow: 0 6px 18px rgba(15, 23, 42, .22); text-align: left;
    }
    .help-tip-label {
      display: block; font-size: 9.5px; font-weight: 700; text-transform: uppercase;
      letter-spacing: .06em; color: rgba(255,255,255,.55); margin-bottom: 4px;
    }
    .send-flow-caption { font-size: 12px; color: var(--gray-600); }
    .send-flow-row { display: grid; grid-template-columns: 40px 1fr auto; align-items: center; gap: 14px; padding: 14px 16px; border-top: 1px solid var(--gray-100); transition: background .18s; }
    .send-flow-row:first-of-type { border-top: none; }
    .send-flow-row.current { background: rgba(66,133,244,.05); }
    .send-flow-row.done    { background: rgba(34,197,94,.05); }
    .send-flow-row.locked  { opacity: .55; }
    .send-flow-row.locked .send-flow-action button { cursor: not-allowed; }
    .send-flow-badge { width: 34px; height: 34px; border-radius: 50%; background: var(--gray-200); color: var(--gray-700); font-size: 14px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; }
    .send-flow-row.current .send-flow-badge { background: #2563eb; color: #fff; box-shadow: 0 0 0 4px rgba(66,133,244,.15); }
    .send-flow-row.done .send-flow-badge    { background: #16a34a; color: #fff; }
    .send-flow-copy { min-width: 0; }
    .send-flow-step-title { font-size: 13.5px; font-weight: 600; color: var(--gray-900); margin-bottom: 3px; }
    .send-flow-step-sub   { font-size: 12px; color: var(--gray-600); line-height: 1.5; }
    .send-flow-action     { display: inline-flex; align-items: center; }
    [data-theme="dark"] .send-flow           { background: rgba(255,255,255,.03); border-color: var(--gray-700); }
    [data-theme="dark"] .send-flow-head      { background: linear-gradient(90deg, rgba(107,70,193,.12), rgba(247,148,31,.10)); border-bottom-color: var(--gray-700); }
    [data-theme="dark"] .send-flow-row       { border-top-color: rgba(255,255,255,.05); }
    [data-theme="dark"] .send-flow-step-title{ color: var(--gray-100); }
    [data-theme="dark"] .send-flow-badge     { background: rgba(255,255,255,.08); color: var(--gray-300); }

    /* Dispatch results panel — progress + final counts under the Send button. */
    .dispatch-results { margin-top: 14px; padding: 14px 16px; border: 1px solid var(--gray-200); border-radius: 8px; background: var(--gray-100); }
    .dispatch-results-h { font-size: 13px; font-weight: 600; color: var(--gray-900); margin-bottom: 8px; }
    .dispatch-results-body { font-size: 13px; color: var(--gray-700); line-height: 1.5; }
    .dispatch-results-hint { font-size: 12px; color: var(--gray-600); margin-top: 10px; }
    .dispatch-results-progress { border-color: #c7d2fe; background: #eef2ff; }
    .dispatch-results-ok       { border-color: #bbf7d0; background: #f0fdf4; }
    .dispatch-results-warn     { border-color: #fde68a; background: #fffbeb; }
    .dispatch-results-error    { border-color: #fecaca; background: #fef2f2; }
    .dispatch-progress { position: relative; height: 8px; background: var(--gray-200); border-radius: 4px; overflow: hidden; margin-bottom: 8px; }
    .dispatch-progress-bar { height: 100%; background: var(--purple-200); transition: width .4s ease; }
    .dispatch-fail { color: #991b1b; font-weight: 600; }
    .dispatch-results-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; margin-top: 4px; }
    .dispatch-stat { display: flex; flex-direction: column; padding: 8px 10px; background: rgba(255,255,255,.6); border: 1px solid var(--gray-200); border-radius: 6px; }
    .dispatch-stat-n { font-size: 20px; font-weight: 700; color: var(--gray-900); line-height: 1.1; }
    .dispatch-stat-l { font-size: 11px; color: var(--gray-600); margin-top: 2px; text-transform: uppercase; letter-spacing: .04em; font-family: 'IBM Plex Mono', monospace; }
    .dispatch-errors { margin-top: 10px; padding: 8px 10px; background: rgba(220, 38, 38, .06); border: 1px solid rgba(220, 38, 38, .25); border-radius: 6px; font-size: 12px; color: #991b1b; }
    .dispatch-errors-h { font-weight: 600; margin-bottom: 4px; }
    .dispatch-errors ul { margin: 0; padding-left: 18px; }
    .dispatch-errors code { font-size: 11px; }

    [data-theme="dark"] .dispatch-results { background: rgba(255,255,255,.03); border-color: var(--gray-700); }
    [data-theme="dark"] .dispatch-results-h { color: #e5e5ef; }
    [data-theme="dark"] .dispatch-results-body { color: var(--gray-300); }
    [data-theme="dark"] .dispatch-results-hint { color: var(--gray-400); }
    [data-theme="dark"] .dispatch-results-progress { background: rgba(94, 55, 142, .18); border-color: rgba(147, 108, 209, .35); }
    [data-theme="dark"] .dispatch-results-ok       { background: rgba(22, 101, 52, .18); border-color: rgba(74, 222, 128, .35); }
    [data-theme="dark"] .dispatch-results-warn     { background: rgba(180, 83, 9, .18); border-color: rgba(251, 191, 36, .35); }
    [data-theme="dark"] .dispatch-results-error    { background: rgba(153, 27, 27, .18); border-color: rgba(220, 38, 38, .35); }
    [data-theme="dark"] .dispatch-progress { background: var(--gray-700); }
    [data-theme="dark"] .dispatch-stat { background: rgba(255,255,255,.03); border-color: var(--gray-700); }
    [data-theme="dark"] .dispatch-stat-n { color: #e5e5ef; }
    [data-theme="dark"] .dispatch-fail { color: #fca5a5; }
    [data-theme="dark"] .dispatch-errors { background: rgba(153, 27, 27, .18); border-color: rgba(220, 38, 38, .35); color: #fca5a5; }

    /* Message Hub stats panel — sits below the compose grid. */
    .msghub-stats-row { margin-top: 20px; }
    .stats-panel { padding: 18px 20px; }
    .stats-panel-h { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 10px; }
    .stats-panel-controls { display: flex; align-items: center; gap: 8px; }
    .stats-window-select { max-width: 160px; }
    /* Wider than the selects beside it: an email address is long, and truncating
       the thing you are filtering by defeats the filter. */
    .stats-recipient-input { max-width: 260px; }
    @media (max-width: 768px) { .stats-recipient-input { max-width: 100%; } }
    .stats-links { margin-top: 16px; }
    .stats-links-h { font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--gray-600); font-family: 'IBM Plex Mono', monospace; margin-bottom: 8px; }
    .stats-links-table { width: 100%; border-collapse: collapse; font-size: 13px; }
    .stats-links-table th, .stats-links-table td { padding: 8px 10px; text-align: left; border-bottom: 1px solid var(--gray-200); vertical-align: top; }
    .stats-links-table th { font-weight: 600; color: var(--gray-700); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
    .stats-links-table .stats-num { text-align: right; font-variant-numeric: tabular-nums; }
    .stats-links-table .stats-when { color: var(--gray-600); font-size: 12px; white-space: nowrap; }
    .stats-links-table .stats-url { max-width: 460px; overflow-wrap: anywhere; }
    .stats-links-table .stats-url a { color: var(--purple-300); text-decoration: underline; }
    [data-theme="dark"] .stats-links-table th { color: var(--gray-300); }
    [data-theme="dark"] .stats-links-table th, [data-theme="dark"] .stats-links-table td { border-bottom-color: var(--gray-700); }
    [data-theme="dark"] .stats-links-table .stats-when { color: var(--gray-400); }
    [data-theme="dark"] .stats-links-table .stats-url a { color: #c4b5fd; }

    /* ── Clicked-link cell (Top clicked links, and the per-send copy) ──────
       The raw URL was the whole cell: a confirm or unsubscribe link is a host
       plus ~100 characters of base64 token, and a Resend-tracked link buries
       the real destination in an encoded path segment. So the column that
       exists to answer "which link did people click" was the one you could not
       read (Arnold, 2026-08-19).

       Host is quiet, path is the emphasis: within one campaign every row
       usually shares a host, so the path is what tells them apart. */
    .link-cell { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
    .link-cell-main { display: inline-flex; flex-wrap: wrap; align-items: baseline; text-decoration: none !important; min-width: 0; }
    .link-cell-main:hover .link-cell-path { text-decoration: underline; }
    .link-cell-host { color: var(--gray-600); font-size: 12px; }
    .link-cell-path { color: var(--purple-300); font-weight: 500; overflow-wrap: anywhere; }
    /* Parameter NAMES only. The value never reaches the DOM — an unsubscribe
       token is a credential for that address, which is why lib/display-url.js
       strips it from the href as well as from the text. */
    .link-cell-meta { display: flex; flex-wrap: wrap; gap: 4px; }
    .link-cell-tag { font-size: 10.5px; font-family: 'IBM Plex Mono', monospace; color: var(--gray-700); background: var(--gray-200); border-radius: 4px; padding: 1px 6px; white-space: nowrap; }
    [data-theme="dark"] .link-cell-host { color: var(--gray-400); }
    [data-theme="dark"] .link-cell-path { color: #c4b5fd; }
    [data-theme="dark"] .link-cell-tag { background: var(--gray-700); color: var(--gray-300); }

    /* To / From stacked under the subject in All sends. Run inline with a
       middot they read as one sentence, and a long audience wraps, which left
       "from x" stranded mid-line. The label column is fixed so the two values
       line up with each other. */
    .sends-meta-row { display: flex; gap: 6px; align-items: baseline; }
    .sends-meta-k { flex: 0 0 auto; min-width: 30px; color: var(--gray-600); font-size: 10.5px; font-family: 'IBM Plex Mono', monospace; }
    .sends-meta-v { min-width: 0; overflow-wrap: anywhere; }
    [data-theme="dark"] .sends-meta-k { color: var(--gray-400); }

    /* ── Communication area: brand pass (Arnold, 2026-08-19) ──────────────
       He asked for the Campaigns pages and their subpages to be checked
       against the brand book. Brand rule 1 is "no ALL-CAPS, ever", and these
       are the six micro-label classes those pages still used.

       SCOPED TO [data-area="campaigns"], stamped by app.js, and that scoping is
       load-bearing: the same classes are used across the rest of the CRM, where
       the ~130 uppercase sites were ruled out of scope on 2026-08-05 and were
       explicitly not to be re-cased wholesale. This is the same decision that
       was made for .comms-h on the Sends & analytics page, widened to the area
       Arnold has now named, and nothing outside it moves.

       Sizes move with the case. All-caps needs letter-spacing to stay legible
       and Title Case does not, so tracking goes to zero and the smallest labels
       come up half a point where losing the caps would otherwise make them
       recede too far. */
    [data-area="campaigns"] .msghub-h,
    [data-area="campaigns"] .stats-links-h,
    [data-area="campaigns"] .triggers-category-h,
    [data-area="campaigns"] .composer-preview-label,
    [data-area="campaigns"] .comms-config-card-provider-label,
    [data-area="campaigns"] .dispatch-stat-l,
    [data-area="campaigns"] .stats-links-table th {
      text-transform: none;
      letter-spacing: 0;
    }
    /* .msghub-h is the panel heading on every Campaigns page except the two
       already converted. Matched to .comms-h so a reader moving between them
       sees one heading style, not two. */
    [data-area="campaigns"] .msghub-h { font-size: 14px; }
    /* These four are mono-spaced micro-labels. Without the caps the monospace
       is what still marks them as labels, so it stays. */
    [data-area="campaigns"] .stats-links-h { font-size: 12.5px; }
    [data-area="campaigns"] .composer-preview-label { font-size: 11.5px; }
    [data-area="campaigns"] .comms-config-card-provider-label { font-size: 10.5px; }
    [data-area="campaigns"] .dispatch-stat-l { font-size: 11.5px; }
    [data-area="campaigns"] .triggers-category-h { font-size: 11.5px; }
    /* gray-600 is 3.47:1 on white and AA wants 4.5:1 at these sizes; gray-700
       is 5.15:1 and reads just as quiet. Measured when the Sends & analytics
       page had the same fix. */
    [data-area="campaigns"] .stats-links-h,
    [data-area="campaigns"] .composer-preview-label,
    [data-area="campaigns"] .dispatch-stat-l,
    [data-area="campaigns"] .triggers-category-h,
    [data-area="campaigns"] .stats-links-table .stats-when { color: var(--gray-700); }
    [data-theme="dark"] [data-area="campaigns"] .stats-links-h,
    [data-theme="dark"] [data-area="campaigns"] .composer-preview-label,
    [data-theme="dark"] [data-area="campaigns"] .dispatch-stat-l,
    [data-theme="dark"] [data-area="campaigns"] .triggers-category-h,
    [data-theme="dark"] [data-area="campaigns"] .stats-links-table .stats-when { color: var(--gray-400); }

    /* Audience Overview share bars. Proportional to the largest option in that
       column, not to the whole audience: the question is which channel people
       prefer, and against a 4,000-person total every bar would be a sliver. */
    .audience-bar-track { height: 8px; min-width: 80px; border-radius: 4px; background: var(--gray-200); overflow: hidden; }
    .audience-bar-fill  { height: 100%; background: var(--purple-300); border-radius: 4px; }
    [data-theme="dark"] .audience-bar-track { background: var(--gray-700); }
    [data-theme="dark"] .audience-bar-fill  { background: #a78bfa; }

    /* Analytics view — full page under Communication. */
    .analytics-wrap { display: flex; flex-direction: column; gap: 16px; }

    /* ── Audience Overview (MFB-310) ──────────────────────────────────────
       Same treatment as the Sends & analytics page beside it: panels get a
       rhythm instead of touching, headings are Title Case (.comms-h), stat
       fills are solid, and the small copy is measured against AA. */
    .audience-wrap { display: flex; flex-direction: column; gap: 16px; }
    /* SOLID, not rgba(255,255,255,.6). Brand rule 2 forbids translucent fills
       on brand shapes; scoped here rather than changed on the shared
       .dispatch-stat, which is also the live dispatch progress panel. */
    .audience-wrap .dispatch-stat { background: var(--gray-100); }
    /* Sentence case and no letter-spacing: brand rule 1 again, and these are
       labels a person reads ("Eligible for the newsletter"), not micro-tags. */
    .audience-wrap .dispatch-stat-l { text-transform: none; letter-spacing: 0; font-family: inherit; font-size: 11.5px; color: var(--gray-700); }
    /* gray-600 is 3.47:1 on white and AA wants 4.5:1 at this size; gray-700 is
       5.15:1. Measured when the analytics page got the same fix. */
    .audience-wrap .msghub-hint { color: var(--gray-700); }
    .audience-wrap .comms-h-count { font-weight: 400; }
    [data-theme="dark"] .audience-wrap .dispatch-stat { background: rgba(255,255,255,.04); }
    .analytics-controls { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
    .msghub-tabs { display: inline-flex; gap: 2px; padding: 4px; background: var(--gray-100); border-radius: 10px; border: 1px solid var(--gray-200); }
    .msghub-tab { background: transparent; border: 0; cursor: pointer; padding: 6px 14px; border-radius: 7px; font: inherit; font-size: 12.5px; font-weight: 500; color: var(--gray-700); display: inline-flex; align-items: center; gap: 6px; transition: background .12s, color .12s; }
    .msghub-tab:hover { color: var(--gray-900); }
    .msghub-tab.active { background: var(--white); color: var(--purple-300); box-shadow: 0 1px 2px rgba(0,0,0,.04); }
    .msghub-tab-count { font-family: "IBM Plex Mono", monospace; font-size: 10.5px; padding: 1px 6px; border-radius: 99px; background: var(--gray-200); color: var(--gray-700); }
    .msghub-tab.active .msghub-tab-count { background: rgba(94,55,142,.1); color: var(--purple-300); }
    .analytics-jobs { table-layout: auto; }
    .analytics-jobs th, .analytics-jobs td { padding: 8px 10px; font-size: 12.5px; }
    .analytics-pill { display: inline-block; padding: 2px 8px; border-radius: 99px; font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: .04em; }
    .analytics-pill-ok    { background: rgba(22,101,52,.15); color: #166534; }
    .analytics-pill-warn  { background: rgba(180,83,9,.15); color: #92400e; }
    .analytics-pill-error { background: rgba(153,27,27,.15); color: #991b1b; }
    .analytics-detail { display: flex; flex-direction: column; gap: 10px; }
    .btn-small { padding: 4px 10px; font-size: 12px; }
    [data-theme="dark"] .analytics-pill-ok    { background: rgba(74,222,128,.20); color: #86efac; }
    [data-theme="dark"] .analytics-pill-warn  { background: rgba(251,191,36,.20); color: #fcd34d; }
    [data-theme="dark"] .analytics-pill-error { background: rgba(220,38,38,.20); color: #fca5a5; }

    /* Editing-a-draft banner at the top of the Message Hub compose panel. */
    .msghub-draft-banner { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 14px; margin-bottom: 12px; background: rgba(94,55,142,.06); border: 1px solid var(--purple-200); border-radius: 8px; font-size: 13px; color: var(--gray-800); flex-wrap: wrap; }
    [data-theme="dark"] .msghub-draft-banner { background: rgba(94,55,142,.16); border-color: rgba(147,108,209,.35); color: #e5e5ef; }

/* ── Schedule Agenda ─────────────────────────────────────────────────────
 * Rooms × time-slots grid with draggable speaker cards. Editor lives in
 * the CRM SPA at /schedule-agenda; the read-only projection at /agenda
 * has its own inline styles (self-contained, no CRM shell). */
.agenda-view { display: flex; flex-direction: column; gap: 14px; }

/* Row 1 — agenda picker (left) + save pill + share/open actions (right). */
.agenda-picker-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  padding: 10px 14px; background: var(--white);
  border: 1.5px solid var(--gray-200); border-radius: 10px;
}
.agenda-picker-left,
.agenda-picker-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.agenda-picker-label {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px; letter-spacing: .04em;
  color: var(--gray-600); font-weight: 500;
}
.agenda-picker-select {
  min-width: 220px; max-width: 360px;
  padding: 7px 10px; border-radius: 6px;
  border: 1.5px solid var(--gray-300); background: var(--white);
  color: var(--gray-900); font-family: inherit; font-size: 13px; font-weight: 500;
  cursor: pointer;
}
.agenda-picker-select:focus { outline: none; border-color: var(--purple-300); }
.agenda-picker-btn { padding: 6px 10px; font-size: 12px; }
.agenda-picker-danger { color: #B91C1C; }
.agenda-picker-danger:hover { border-color: #FCA5A5; background: rgba(220,38,38,.06); }

/* Row 2 — event metadata card. Title takes a full row on top so it can
 * grow to fit long labels; the meta grid underneath is 3 up on desktop,
 * stacks on mobile. */
.agenda-meta-card {
  padding: 14px 16px 16px; background: var(--white);
  border: 1.5px solid var(--gray-200); border-radius: 10px;
  display: flex; flex-direction: column; gap: 10px;
}
.agenda-meta-card.agenda-meta-compact { padding: 10px 12px 12px; gap: 8px; }
.agenda-meta-title-row { display: flex; align-items: center; gap: 12px; }
/* Grid preserved for any legacy meta-card that still uses it. */
.agenda-meta-grid {
  display: grid; gap: 10px 14px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
@media (max-width: 720px) {
  .agenda-meta-grid { grid-template-columns: 1fr; }
}
/* Date / Location / Timezone moved into the "Event details" panel in
   .agenda-meta-subs, where .agenda-sub-body stacks them — the old
   .agenda-meta-row 3-column grid is gone with it. */
/* Compact select for the Event/TouchPoint picker in the actions row —
   the .agenda-meta-input default is width:100% (grid-cell fill), which
   would explode inside the flex toolbar row. */
.agenda-event-picker {
  /* Inside its toolbar group it takes the space the group has, rather
     than a fixed 180–260px that would decide the column's width. */
  flex: 1 1 140px; width: auto; min-width: 0; max-width: 100%;
}
.agenda-meta-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.agenda-meta-label {
  font-size: 10.5px; font-weight: 600; color: var(--gray-600);
  text-transform: uppercase; letter-spacing: 0.03em;
}
.agenda-meta-input {
  padding: 6px 9px; border-radius: 6px;
  border: 1.5px solid var(--gray-300); background: var(--white);
  color: var(--gray-900); font-family: inherit; font-size: 13px;
  width: 100%; min-width: 0;
}
.agenda-meta-input:focus { outline: none; border-color: var(--purple-300); }
.agenda-meta-status {
  align-self: end; padding: 6px 8px;
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px; color: var(--purple-400);
  background: var(--gray-100);
  border-radius: 6px; white-space: nowrap;
}
.agenda-meta-hint {
  font-size: 11.5px; color: var(--gray-600); line-height: 1.5;
}
.agenda-meta-hint a { color: var(--orange-300); text-decoration: underline; text-underline-offset: 2px; }

/* Action row inside the meta card — sits directly under the meta row
 * so every toolbar affordance lives in one place. */
/* Three equal thirds, not a wrapping flex row: the groups are peers and
 * should look like it (Arnold, 2026-08-11). Grid also gives them a shared
 * row height for free — stretch is the default — so a group whose
 * controls wrap does not leave the other two looking short.
 * minmax(0, 1fr) rather than 1fr so a long select can't push a column
 * past its third. */
.agenda-meta-actions {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px;
  padding-top: 10px; margin-top: 6px;
  border-top: 1px dashed var(--gray-200);
}
@media (max-width: 768px) {
  .agenda-meta-actions { grid-template-columns: 1fr; }
}
/* Named toolbar groups. The label sits ABOVE its buttons rather than
 * beside them: the row wraps on a narrow window, and a leading label
 * would be the first thing to wrap away from what it names. */
.agenda-toolbar-group {
  display: flex; flex-direction: column; gap: 5px;
  padding: 7px 10px 8px;
  border: 1px solid var(--gray-200); border-radius: 10px;
  background: var(--gray-100);
  min-width: 0;                 /* let the grid column, not the content, set the width */
}
.agenda-toolbar-group-label {
  font-size: 10.5px; font-weight: 600; letter-spacing: .02em;
  color: var(--gray-600); line-height: 1;
}
.agenda-toolbar-group-row {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}

.agenda-title {
  flex: 1 1 240px; min-width: 200px;
  font-size: 20px; font-weight: 700; color: var(--ink-900);
  border: 1px solid transparent; background: transparent;
  padding: 6px 8px; border-radius: 6px;
  letter-spacing: -.01em;
}
.agenda-title:hover  { border-color: var(--gray-200); background: var(--gray-50); }
.agenda-title:focus  { outline: none; border-color: var(--purple-300); background: var(--white); }
.agenda-toolbar-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.agenda-save-pill {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  padding: 4px 10px; border-radius: 99px;
}
.agenda-save-saving { background: rgba(247,148,31,.14); color: #B45309; }
.agenda-save-saved  { background: rgba(34,197,94,.14);  color: #16A34A; }
/* A failed or conflicted save is the one state the operator must act on,
   so it reads as solid and urgent rather than a tinted whisper — and the
   error variant is clickable (retry now). */
.agenda-save-error,
.agenda-save-conflict {
  background: #B91C1C; color: var(--white); font-weight: 600;
}
.agenda-save-error { cursor: pointer; }
.agenda-save-error:hover { background: #991B1B; }

/* Inline banners above the grid — unsaved-draft recovery + edit conflict. */
.agenda-alert {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 14px; border-radius: 10px; margin-bottom: 12px;
  border: 1.5px solid transparent; font-size: 13px;
}
.agenda-alert-body { flex: 1 1 320px; min-width: 0; }
.agenda-alert-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.agenda-alert-warn   { background: #FFF7ED; border-color: #FDBA74; color: #7C2D12; }
.agenda-alert-danger { background: #FEF2F2; border-color: #FCA5A5; color: #7F1D1D; }

/* How this agenda counts votes: phones, or a show of hands (MFB-366). A
 * segmented pair rather than a checkbox, because the two are exclusive and the
 * choice changes what the Unassigned cards let you do. Fills the 280px column
 * so both options are the same size and neither reads as the afterthought. */
.agenda-vote-mode {
  display: flex; gap: 0; margin: 8px 0 0;
  border: 1.5px solid var(--gray-300); border-radius: 6px; overflow: hidden;
}
.agenda-vote-mode-btn {
  flex: 1 1 0; min-width: 0; padding: 7px 8px;
  border: none; background: var(--white); color: var(--gray-700);
  font-family: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
  transition: background .12s, color .12s;
}
.agenda-vote-mode-btn + .agenda-vote-mode-btn { border-left: 1.5px solid var(--gray-300); }
.agenda-vote-mode-btn:hover:not(.is-on) { background: rgba(66,44,112,.06); color: var(--purple-300); }
.agenda-vote-mode-btn.is-on { background: var(--purple-300); color: var(--white); cursor: default; }

/* The hand-counted running total, so the organiser can sanity-check the sum
 * against the size of the room without adding the cards up themselves. */
.agenda-vote-total {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--gray-200);
}
.agenda-vote-total strong {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 18px; color: var(--purple-300);
}

/* Live voting setup + status. */
.agenda-vote-enable {
  display: flex; align-items: flex-start; gap: 8px; cursor: pointer;
  font-size: 13px; margin: 8px 0; color: var(--gray-700, #4A4A63);
}
/* This one checkbox turns attendee voting on for a live event, so it is
   sized to be found and hit rather than to match a form row. accent-color
   paints the checked state in MFB purple. */
.agenda-vote-enable input[type="checkbox"] {
  width: 18px; height: 18px; flex-shrink: 0; margin: 0;
  accent-color: var(--purple-300); cursor: pointer;
}
/* The voting card's actions are a stacked column, one full-width button
   per action (Arnold, 2026-08-11) — in a 280px column a row of buttons
   wrapped into ragged half-widths. */
.agenda-voting-card .agenda-field-row { flex-direction: column; align-items: stretch; gap: 8px; }
.agenda-voting-card .agenda-picker-btn { width: 100%; text-align: center; }
.agenda-vote-panel { display: flex; flex-direction: column; gap: 10px; margin-top: 6px; }
.agenda-vote-status {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--gray-600);
}
.agenda-vote-live {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 10px; font-weight: 700; letter-spacing: .08em;
  background: #B91C1C; color: var(--white);
  padding: 2px 7px; border-radius: 99px;
}
/* The join row (QR + URL + "Show QR big") lived here until 2026-08-11. It
   is the host screen's job now, so the rules went with the markup. */

/* Display-mode control for a cell holding several talks.
   Styled as a thin header strip above the cards — a tab row, not a box. It
   describes the cards below it, so it should read as their heading rather than
   as another card competing with them. */
.agenda-panel-toggle {
  display: flex; flex-direction: column; gap: 4px;
  margin: 0 0 6px; padding: 0 0 4px;
  border-bottom: 1px solid var(--gray-200);
}
.agenda-panel-toggle.is-on { border-bottom-color: var(--purple-300); }
/* Separate / Panel / Back-to-back — one line of borderless text options with
   hairline separators, the active one marked by colour + an underline accent.
   Grid columns are narrow, so the type is small and the row wraps as a last
   resort rather than clipping a label. */
.agenda-cell-modes { display: flex; align-items: center; flex-wrap: wrap; }
.agenda-cell-mode {
  position: relative;
  font-family: inherit; font-size: 10px; font-weight: 600; line-height: 1.2;
  padding: 3px 6px; cursor: pointer; white-space: nowrap;
  background: none; border: 0; color: var(--gray-600);
}
/* Hairline between options, not around them. */
.agenda-cell-mode + .agenda-cell-mode { box-shadow: -1px 0 0 var(--gray-200); }
.agenda-cell-mode:hover { color: var(--purple-300); }
.agenda-cell-mode.is-active { color: var(--purple-300); font-weight: 700; }
.agenda-cell-mode.is-active::after {
  content: ''; position: absolute; left: 6px; right: 6px; bottom: -5px;
  height: 2px; background: var(--purple-300); border-radius: 2px;
}
/* One line under the strip saying what the ACTIVE option does. Sits below
 * the underline accent, so it needs clearance from it. */
.agenda-cell-mode-hint {
  margin-top: 7px;
  font-size: 10.5px; line-height: 1.4; color: var(--gray-600);
}
/* Panel title sits on its own line under the mode strip, kept visually quiet
   so the strip still reads as a single header line. */
/* Typography matched to .agenda-card-title above — this IS the title of
 * the merged card, so it should not read as a smaller, lesser field
 * (Arnold, 2026-08-11). The visible border stays: unlike a card title it
 * sits on the grey strip, where a borderless input is hard to find. */
.agenda-panel-title-input {
  width: 100%;
  font-family: inherit; font-size: 13px; font-weight: 600;
  color: var(--ink-900);
  padding: 2px 4px;
  border: 1px solid var(--gray-200); border-radius: 4px; background: var(--white);
}
.agenda-panel-title-input:focus { outline: none; border-color: var(--purple-300); }
/* The word in front of the names on a merged session. Quieter than the title
 * (which is the session) and quieter than the mode strip (which decides the
 * shape): this only chooses a word, so it reads as a setting, not a heading. */
.agenda-panel-word { display: block; margin-top: 7px; }
.agenda-panel-word-label {
  display: block; font-size: 10px; letter-spacing: .04em;
  color: var(--gray-600); margin-bottom: 3px;
}
.agenda-panel-word-select {
  width: 100%;
  font-family: inherit; font-size: 12px; color: var(--ink-900);
  padding: 2px 4px;
  border: 1px solid var(--gray-200); border-radius: 4px; background: var(--white);
}
.agenda-panel-word-select:focus { outline: none; border-color: var(--purple-300); }
.agenda-panel-warn { font-size: 10.5px; color: #B45309; font-style: italic; }

/* Collapsible sub-sections of the meta card (Co-host branding, Live voting).
   These read as real panels rather than stray links: a bordered block with a
   proper summary row, and ONE grid inside that sizes fields evenly whatever
   the count. They previously borrowed .agenda-meta-row, whose 3-column ratios
   are tuned for Date/Location/Timezone — with four fields the widths went to
   nonsense and the last one wrapped. */
/* Same chip as .agenda-toolbar-group below the grid — these three are the
   same kind of thing, so they read the same way (Arnold, 2026-08-11). */
.agenda-sub {
  margin-top: 10px; border: 1px solid var(--gray-200); border-radius: 10px;
  background: var(--gray-100);
}
/* Event details · Co-host branding, half each. Live voting used to be the
   third panel here; it now lives above Unassigned, next to the topics it
   puts on the ballot.
   `align-items: start` (NOT the grid default of stretch) is deliberate:
   opening one panel would otherwise stretch its collapsed neighbour to the
   same height, and a summary row inside a tall box reads as an empty panel.
   Closed — which is how the builder always loads — both are the same height
   anyway. */
.agenda-meta-subs {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px; align-items: start;
}
@media (max-width: 768px) {
  .agenda-meta-subs { grid-template-columns: 1fr; }
}
.agenda-meta-subs > .agenda-sub { margin-top: 0; min-width: 0; }

.agenda-sub[open] { background: var(--white); }
.agenda-sub-summary {
  display: flex; align-items: center; gap: 7px;
  padding: 8px 10px; cursor: pointer; user-select: none; list-style: none;
}
.agenda-sub-summary::-webkit-details-marker { display: none; }
/* Own chevron so the row is consistent across browsers. */
.agenda-sub-summary::before {
  content: '▸'; font-size: 10px; color: var(--gray-600);
  transition: transform .12s ease; flex-shrink: 0;
}
.agenda-sub[open] > .agenda-sub-summary::before { transform: rotate(90deg); }
/* Same label treatment as .agenda-toolbar-group-label. */
.agenda-sub-title {
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.02em;
  color: var(--gray-600); line-height: 1;
}
.agenda-sub-summary:hover .agenda-sub-title { color: var(--purple-300); }
.agenda-sub-pill {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 9.5px; letter-spacing: .06em; text-transform: uppercase;
  background: rgba(34,197,94,.16); color: #16A34A;
  padding: 1px 6px; border-radius: 99px;
}
.agenda-sub-body {
  padding: 4px 10px 10px; border-top: 1px solid var(--gray-200);
  display: flex; flex-direction: column; gap: 10px;
}
/* Even columns regardless of field count — no bespoke ratios to go stale. */
.agenda-sub-grid {
  display: grid; gap: 10px 12px; align-items: end;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
/* The speaker-application deadline (MFB-365/370). Set off from the event dates
 * directly above it, because they look alike and mean different things: one is
 * when the event runs, the other is when the form stops taking applications. */
.agenda-window-block {
  margin-top: 12px; padding-top: 12px;
  border-top: 1px solid var(--gray-200);
}
.agenda-window-row { display: flex; gap: 8px; align-items: center; }
.agenda-window-row input { flex: 1 1 auto; min-width: 0; }
/* Clearing the deadline is a real action, not an edge case: an organiser who
 * mistypes one needs applications open again, and emptying a datetime input is
 * fiddly in every browser. */
.agenda-window-clear {
  flex: 0 0 auto; padding: 6px 10px;
  border: 1.5px solid var(--gray-300); border-radius: 6px;
  background: var(--white); color: var(--gray-700);
  font-family: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
}
.agenda-window-clear:hover { border-color: var(--purple-300); color: var(--purple-300); }
/* Controls that sit beside each other keep one height, so rows line up. */
.agenda-field-row { display: flex; align-items: center; gap: 6px; min-height: 30px; flex-wrap: wrap; }
.agenda-field-note {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 10.5px; color: var(--gray-600);
}
.agenda-mini-btn { padding: 5px 9px; font-size: 11.5px; min-height: 30px; }
.agenda-color-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.agenda-color-input {
  width: 40px; height: 30px; padding: 2px; cursor: pointer; flex-shrink: 0;
  border: 1.5px solid var(--gray-200); border-radius: 6px; background: var(--white);
}
.agenda-cohost-preview {
  height: 30px; width: auto; max-width: 110px; object-fit: contain;
  border: 1.5px solid var(--gray-200); border-radius: 6px;
  padding: 2px 5px; background: var(--white);
}
.agenda-cohost-error { font-size: 12px; color: #B91C1C; }

/* Designed confirm dialog (close / reopen a voting session). */
.agenda-confirm-body { text-align: center; }
.agenda-confirm-icon { font-size: 36px; line-height: 1; margin-bottom: 10px; }
.agenda-confirm-text { font-size: 14px; line-height: 1.6; color: var(--gray-700, #4A4A63); margin: 0 0 10px; }
.agenda-confirm-note { font-size: 12.5px; line-height: 1.55; color: var(--gray-600); margin: 0; }

/* Big-QR modal. */
.agenda-qr-modal-body { display: flex; flex-direction: column; align-items: center; gap: 12px; }
.agenda-qr-modal-img { display: block; width: min(360px, 70vw); height: auto; }
.agenda-qr-modal-url {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 12px; color: var(--gray-600); word-break: break-all; text-align: center;
}

/* Destructive confirm button — solid red so it never gets mistaken for the
   safe option. Used by the "delete card from Unassigned" confirmation. */
.btn-danger {
  background: #B91C1C; color: var(--white); border: 1.5px solid #B91C1C;
  font-weight: 600;
}
.btn-danger:hover { background: #991B1B; border-color: #991B1B; }

/* Delete-card confirmation — shows who is about to be lost. */
.agenda-delete-card {
  display: flex; align-items: center; gap: 12px;
  padding: 12px; border: 1.5px solid var(--gray-200); border-radius: 10px;
  margin-bottom: 12px;
}
.agenda-delete-avatar {
  width: 48px; height: 48px; border-radius: 50%; object-fit: cover;
  flex-shrink: 0; border: 1.5px solid var(--gray-200);
}
.agenda-delete-avatar-ph {
  display: flex; align-items: center; justify-content: center;
  background: var(--gray-100); color: var(--purple-300);
  font-weight: 600; font-size: 15px;
}
.agenda-delete-meta { min-width: 0; }
.agenda-delete-name { font-weight: 600; font-size: 14px; }
.agenda-delete-talk { font-size: 13px; color: var(--gray-600); }
.agenda-delete-votes {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px; color: var(--gray-600); margin-top: 2px;
}

/* Version-history list. */
.agenda-history-modal .modal-body { max-height: 62vh; overflow-y: auto; }
.agenda-history-list { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.agenda-history-row {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 8px 10px; border: 1.5px solid var(--gray-200); border-radius: 8px;
}
.agenda-history-row:hover { border-color: var(--purple-300); background: var(--gray-50); }
.agenda-history-when { flex: 1 1 200px; font-size: 13px; min-width: 0; }
.agenda-history-actor { font-size: 11px; color: var(--gray-600); }
.agenda-history-counts {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px; color: var(--gray-600); flex: 0 1 auto;
}
.agenda-history-current {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
  background: rgba(34,197,94,.14); color: #16A34A;
  padding: 2px 6px; border-radius: 99px; margin-left: 6px;
}

.agenda-body {
  display: grid; grid-template-columns: 280px 1fr; gap: 16px;
  align-items: start;
}
@media (max-width: 900px) {
  .agenda-body { grid-template-columns: 1fr; }
}

/* Left column of the body: Live voting stacked above Unassigned. */
.agenda-body-left {
  display: flex; flex-direction: column; gap: 10px; min-width: 0;
}
/* Deliberately identical to .agenda-unassigned below — the two are peers in
   one column, and a different card treatment made the top one look like a
   different KIND of thing (Arnold, 2026-08-11). Always open: no <details>,
   no chevron. */
.agenda-voting-card {
  background: var(--white); border: 1.5px solid var(--gray-200);
  border-radius: 10px; padding: 12px;
  display: flex; flex-direction: column; gap: 8px;
}
.agenda-voting-head { display: flex; align-items: center; gap: 8px; }
.agenda-unassigned {
  background: var(--white); border: 1.5px solid var(--gray-200);
  border-radius: 10px; padding: 12px; min-height: 200px;
  display: flex; flex-direction: column; gap: 8px;
}
.agenda-panel-title {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--gray-600); font-weight: 500;
}
.agenda-hint {
  font-size: 12px; color: var(--gray-600); font-style: italic;
  padding: 12px 8px; border: 1.5px dashed var(--gray-200); border-radius: 8px;
  text-align: center;
}

.agenda-grid-wrap {
  background: var(--white); border: 1.5px solid var(--gray-200);
  border-radius: 10px; overflow-x: auto;
}
.agenda-grid { width: 100%; border-collapse: separate; border-spacing: 0; }
.agenda-grid thead th {
  background: var(--gray-100); font-weight: 600; font-size: 13px;
  padding: 10px; border-bottom: 1.5px solid var(--gray-200);
  border-right: 1px solid var(--gray-200); vertical-align: middle;
  min-width: 200px;
}
.agenda-grid thead th:last-child { border-right: none; }
/* The time column is PINNED. `.agenda-grid-wrap` scrolls horizontally once
 * there are more than a couple of rooms, and without this the times scrolled
 * away with everything else — leaving a grid of cards with nothing to say what
 * hour you were looking at. It also sits ABOVE the cards (z-index), so they
 * pass underneath it instead of over the top as they scroll by.
 *
 * Three things this depends on, all already true, and all of which silently
 * break stickiness if changed:
 *   - `.agenda-grid` uses border-collapse: separate. Under `collapse` a sticky
 *     cell loses its borders entirely.
 *   - both cells carry an OPAQUE background, or the cards show through them.
 *   - the column has a fixed width (180px), so the offset is stable.
 * The corner sits one layer higher than the body cells so the header cannot be
 * overlapped by the column scrolling under it. */
.agenda-grid .agenda-corner {
  background: var(--white); width: 180px; min-width: 180px;
  position: sticky; left: 0; z-index: 3;
}
.agenda-grid tbody th.agenda-slot-head {
  background: var(--gray-50); border-right: 1.5px solid var(--gray-200);
  border-bottom: 1px solid var(--gray-200);
  padding: 10px; vertical-align: top; white-space: nowrap;
  width: 180px; min-width: 180px;
  position: sticky; left: 0; z-index: 2;
}
/* Time inputs (start + end) stay on ONE row — wider slot column above
 * gives them the space; nowrap prevents them from stacking on narrower
 * viewports before the outer table itself scrolls. */
.agenda-slot-times { display: flex; align-items: center; gap: 2px; flex-wrap: nowrap; }
.agenda-slot-times .agenda-slot-input { min-width: 70px; }
.agenda-grid tbody td.agenda-cell {
  padding: 8px; border-right: 1px solid var(--gray-200);
  border-bottom: 1px solid var(--gray-200); vertical-align: top;
  min-height: 80px; min-width: 240px;
  /* IMPORTANT: keep the td as table-cell — overriding this to `flex`
   * breaks table column-width computation and drag targets misalign.
   * Multi-card layout lives on `.agenda-cell-inner` (a plain div child). */
}
.agenda-cell-inner {
  display: flex; flex-wrap: wrap; gap: 8px; align-content: flex-start;
  min-height: 64px;   /* keeps empty cells sized so drop targets are grabbable */
  /* Fill the cell so the visible empty area matches the droppable area. The
     drop handler sits on the td (see the builder), so this is about the cursor
     agreeing with the hit box rather than about the target itself. */
  height: 100%;
}
.agenda-cell-inner > .agenda-card { flex: 1 1 200px; min-width: 180px; max-width: 100%; }
/* The display-mode strip is a HEADING for every card in the cell, so it must
 * claim the whole first line. Without this it's just another flex item and
 * lands to the LEFT of the first card, reading as a sibling of the talks
 * rather than as the label that explains them. */
.agenda-cell-inner > .agenda-panel-toggle { flex: 0 0 100%; width: 100%; }

/* Break slots — coffee, lunch, hallway. Amber slab across the row so
 * operators + attendees don't mistake the block for a talk. */
/* Opaque on purpose: this is the sticky column, so a translucent or absent
 * background would let the cards scroll visibly through the times. */
.agenda-row-break .agenda-slot-head-break { background: #FFF7E6; color: #B45309; }
.agenda-row-break .agenda-cell-break      { background: #FFFAF0; }
.agenda-slot-break-toggle {
  display: flex; align-items: center; gap: 6px;
  margin-top: 6px; padding: 2px 4px;
  font-size: 11px; color: var(--gray-600); cursor: pointer;
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
}
.agenda-slot-break-toggle input { width: 12px; height: 12px; margin: 0; }
.agenda-slot-break-toggle:hover { color: var(--gray-800); }
.agenda-grid tbody td.agenda-cell:last-child { border-right: none; }
.agenda-grid tbody tr:last-child td, .agenda-grid tbody tr:last-child th { border-bottom: none; }
.agenda-empty {
  padding: 32px; text-align: center; color: var(--gray-600);
  font-style: italic;
}

.agenda-room-label-row, .agenda-slot-label-row {
  display: flex; align-items: center; gap: 4px;
}
.agenda-room-input, .agenda-slot-input {
  flex: 1; background: transparent; border: 1px solid transparent;
  padding: 4px 6px; border-radius: 4px;
  font-size: 13px; font-weight: 600; color: var(--ink-900); min-width: 0;
}
.agenda-slot-input {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-weight: 500; color: var(--purple-300);
}
.agenda-room-input:hover, .agenda-slot-input:hover {
  border-color: var(--gray-200); background: var(--white);
}
.agenda-room-input:focus, .agenda-slot-input:focus {
  outline: none; border-color: var(--purple-300); background: var(--white);
}
.agenda-remove-x {
  border: none; background: transparent; color: var(--gray-500);
  width: 24px; height: 24px; border-radius: 4px; cursor: pointer;
  font-size: 16px; line-height: 1; flex-shrink: 0;
}
.agenda-remove-x:hover { background: rgba(220,38,38,.1); color: #B91C1C; }

/* Room description input — smaller, less prominent than the room name.
 * Sits directly under the room label row; blank by default. Shown on
 * the public page below the room name so attendees can find the space. */
.agenda-room-desc {
  display: block; width: 100%;
  margin-top: 4px;
  padding: 3px 6px;
  background: transparent; border: 1px solid transparent; border-radius: 4px;
  font-size: 11.5px; font-weight: 400; color: var(--gray-600);
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  box-sizing: border-box;
}
.agenda-room-desc::placeholder { color: var(--gray-400); font-style: italic; }
.agenda-room-desc:hover  { border-color: var(--gray-200); background: var(--white); }
.agenda-room-desc:focus  { outline: none; border-color: var(--purple-300); background: var(--white); }

.agenda-card {
  background: var(--white); border: 1.5px solid var(--gray-200);
  border-left: 3px solid var(--orange-300);
  border-radius: 8px; padding: 8px 10px;
  cursor: grab; display: flex; flex-direction: column; gap: 6px;
}
.agenda-card:active { cursor: grabbing; }
.agenda-card:hover { border-color: var(--purple-300); border-left-color: var(--orange-300); }
/* Label card — a grid marker with no speaker behind it ("Doors open",
 * "Close and networking"). Purple edge rather than the orange talk
 * accent, so the two are told apart at a glance in Unassigned. */
.agenda-card-label { border-left-color: var(--purple-300); background: var(--gray-100); }
.agenda-card-label:hover { border-color: var(--purple-300); border-left-color: var(--purple-300); }
.agenda-card-label .agenda-card-title { color: var(--purple-300); }
.agenda-card-label-hint {
  font-size: 10.5px; line-height: 1.4; color: var(--gray-600);
  padding: 0 4px;
}
.agenda-card-head { display: flex; align-items: center; gap: 4px; }
/* font-family: inherit — an <input> otherwise falls back to the UA font
 * (Arial here), so the card title had never actually been in the brand
 * face. Found while matching the panel-title field to it. */
.agenda-card-title {
  flex: 1; font-family: inherit; font-weight: 600; font-size: 13px; color: var(--ink-900);
  background: transparent; border: 1px solid transparent;
  padding: 2px 4px; border-radius: 4px; min-width: 0;
}
.agenda-card-title:hover { border-color: var(--gray-200); }
.agenda-card-title:focus { outline: none; border-color: var(--purple-300); background: var(--white); }
.agenda-card-speaker {
  display: flex; align-items: center; gap: 6px; min-width: 0;
}
.agenda-card-avatar {
  width: 28px; height: 28px; border-radius: 6px;
  flex-shrink: 0; object-fit: cover;
  background: var(--gray-100); display: block;
}
.agenda-card-avatar-placeholder {
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(66,44,112,.12); color: var(--purple-300);
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-weight: 700; font-size: 11px;
}
.agenda-card-name {
  flex: 1; min-width: 0; font-family: inherit;
  font-size: 12px; color: var(--purple-300); font-weight: 500;
  background: transparent; border: 1px solid transparent;
  padding: 2px 4px; border-radius: 4px;
}
.agenda-card-name:hover { border-color: var(--gray-200); }
.agenda-card-name:focus { outline: none; border-color: var(--purple-300); background: var(--white); }
/* Speaker social icons on the builder card — read-only mini row that
 * mirrors the Person Detail contact strip. Edit handles by opening the
 * person's profile, then re-importing from the Applicants modal. */
.agenda-card-socials {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin: 2px 4px 0;
}
.agenda-card-socials a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; border-radius: 4px;
  color: var(--purple-300);
  background: rgba(66,44,112,.06);
  text-decoration: none;
}
.agenda-card-socials a:hover { background: rgba(66,44,112,.12); color: var(--purple-400); }
.agenda-card-socials svg { width: 12px; height: 12px; display: block; }
.agenda-card-desc {
  font-size: 12px; color: var(--gray-800); line-height: 1.4;
  background: var(--gray-50); border: 1px solid var(--gray-200);
  padding: 6px 8px; border-radius: 4px; resize: vertical;
  font-family: inherit;
}
.agenda-card-desc:focus { outline: none; border-color: var(--purple-300); background: var(--white); }
.agenda-card-desc-preview {
  font-size: 12px; color: var(--gray-600); line-height: 1.4;
  padding: 2px 4px; white-space: pre-wrap;
  max-height: 3em; overflow: hidden; text-overflow: ellipsis;
}
.agenda-card-toggle {
  align-self: flex-start; background: transparent; border: none;
  color: var(--purple-300); font-size: 11px; font-weight: 500;
  padding: 2px 4px; cursor: pointer; text-decoration: underline;
}
.agenda-card-toggle:hover { color: var(--purple-400); }
.agenda-card-x {
  border: none; background: transparent; color: var(--gray-500);
  width: 22px; height: 22px; border-radius: 4px; cursor: pointer;
  font-size: 14px; line-height: 1; flex-shrink: 0;
}
.agenda-card-x:hover { background: rgba(220,38,38,.1); color: #B91C1C; }

/* Vote stepper — Unassigned-panel only. Compact row so it doesn't crowd
 * the card; matches the card's own type scale and purple accent. */
.agenda-card-votes {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 2px 0;
}
.agenda-card-votes-label {
  font-size: 10.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .06em; color: var(--gray-600); margin-right: 2px;
}
.agenda-card-votes-btn {
  width: 22px; height: 22px; padding: 0;
  border: 1px solid var(--gray-300); background: var(--white);
  border-radius: 4px; color: var(--gray-700);
  font-size: 14px; line-height: 1; font-family: inherit;
  cursor: pointer; flex-shrink: 0;
  transition: border-color .12s, color .12s, background .12s;
}
.agenda-card-votes-btn:hover:not(:disabled) {
  border-color: var(--purple-300); color: var(--purple-300);
  background: rgba(66,44,112,.06);
}
.agenda-card-votes-btn:disabled { opacity: .4; cursor: not-allowed; }
.agenda-card-votes-input {
  width: 48px; min-width: 0; text-align: center;
  padding: 2px 4px; font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 12px; font-weight: 600; color: var(--gray-900);
  border: 1px solid var(--gray-300); background: var(--white);
  border-radius: 4px;
}
.agenda-card-votes-input:focus {
  outline: none; border-color: var(--purple-300); background: var(--white);
}
/* Hide the native number-input spin arrows — the ± buttons handle it. */
.agenda-card-votes-input::-webkit-outer-spin-button,
.agenda-card-votes-input::-webkit-inner-spin-button {
  -webkit-appearance: none; margin: 0;
}
.agenda-card-votes-input { -moz-appearance: textfield; appearance: textfield; }

/* The digital tally, which the builder does not own (MFB-366). Same type and
 * width as the input it replaces, so switching an agenda between counting modes
 * does not reflow the card, but flat: no border and no field affordance, because
 * there is nothing here to type into. */
.agenda-card-votes-readonly {
  min-width: 48px; text-align: center;
  padding: 2px 4px; font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 12px; font-weight: 600; color: var(--gray-700);
}

/* Slot time range — two <input type="time"> side by side inside the
 * slot header cell. type=time gives the native picker on both mobile
 * and desktop; no library needed. */
.agenda-slot-times { display: flex; align-items: center; gap: 4px; flex: 1; min-width: 0; }
.agenda-slot-times .agenda-slot-input {
  width: auto; min-width: 0; flex: 1 1 60px;
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-weight: 500; font-size: 12px; color: var(--purple-300);
}
.agenda-slot-dash { color: var(--gray-500); flex-shrink: 0; }

/* Agenda share modal — eyebrow + title live inside .modal-header. Rows
 * are two- or three-column: [target-info | copy | open]. Placeholder
 * calendar rows use `.disabled` to dim + no-hover the target. */
.modal-eyebrow {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--gray-600); font-weight: 500; margin-bottom: 2px;
}
.modal-title { font-size: 16px; font-weight: 600; color: var(--ink-900); line-height: 1.3; }

.agenda-share-modal { max-width: 640px; }
.agenda-share-section-title {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--gray-600); font-weight: 500; margin-bottom: 6px;
  display: flex; align-items: center; gap: 8px;
}
.agenda-share-soon {
  font-family: 'IBM Plex Sans', sans-serif; text-transform: none;
  letter-spacing: 0; font-weight: 500; font-size: 10px;
  padding: 2px 8px; border-radius: 99px;
  background: rgba(247,148,31,.14); color: #B45309;
}
.agenda-share-hint {
  font-size: 12px; color: var(--gray-600);
  margin-bottom: 10px; line-height: 1.5;
}
.agenda-share-row {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 12px; border: 1.5px solid var(--gray-200);
  border-radius: 8px; margin-bottom: 8px; background: var(--white);
}
.agenda-share-row.disabled { background: var(--gray-50); opacity: 0.7; }
.agenda-share-row.disabled .btn { cursor: not-allowed; }
.agenda-share-url {
  flex: 1 1 240px; min-width: 0;
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 12px; padding: 6px 8px;
  border: 1px solid var(--gray-200); border-radius: 4px;
  color: var(--ink-900); background: var(--gray-50);
}
.agenda-share-url:focus { outline: none; border-color: var(--purple-300); background: var(--white); }
.agenda-share-target { flex: 1 1 200px; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.agenda-share-target-name { font-weight: 600; font-size: 13px; color: var(--ink-900); }
.agenda-share-target-note { font-size: 12px; color: var(--gray-600); line-height: 1.4; }

    /* Campaign versus transactional pills on the Sends & analytics table, and the
       notice that says how much of the window is unattributed (MFB-306). Solid
       token fills and sentence case, per the brand rules. Measured on white:
       purple-300 #422C70 is 9.4:1, gray-700 #6C6C7D is 4.8:1, both AA for body
       text. Deliberately NOT orange: orange on white fails AA at this size. */
    .comms-kind { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 11.5px; font-weight: 500; white-space: nowrap; }
    .comms-kind-campaign { background: var(--gray-200); color: var(--purple-300); }
    .comms-kind-tx       { background: var(--gray-200); color: var(--gray-700); }
    .comms-kind-unknown  { background: var(--gray-100); color: var(--gray-600); font-style: italic; }
    [data-theme="dark"] .comms-kind-campaign { background: rgba(94,55,142,.22); color: #d9c9f0; }
    [data-theme="dark"] .comms-kind-tx       { background: rgba(255,255,255,.08); color: var(--gray-300); }
    [data-theme="dark"] .comms-kind-unknown  { background: rgba(255,255,255,.05); color: var(--gray-400); }
