    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

    /* Color/scale tokens (light + dark) now live in shared/dashboard-tokens.css
       — the single source for dashboard.html, client_dashboard.html and
       customer_view.html. See that file for the WCAG contrast notes this
       block used to carry inline; nothing here overrides it. */

    /* Layer B used to set this with `html, body { background: … !important }`.
       With that gone, relying on body-background-propagating-to-canvas works
       but breaks the moment anything sets a background on html. color-scheme
       also makes native form controls and scrollbars follow the theme. */
    html {
      background: var(--bg);
    }
    :root[data-theme="light"] { color-scheme: light; }


    /* Teal / warm / purple / midnight theme blocks removed. Light and dark are
       the two themes now, both contrast-verified; those four never were, and
       every one of them produced a dark client-facing dashboard by accident.
       (Historic note below kept for why they went.)
       Teal / warm / purple / midnight theme blocks removed — none were contrast-
       verified, and every one produced a dark client-facing dashboard. */

    body {
      background: var(--bg);
      color: var(--text);
      /* Every fallback here covers Hebrew, so an RTL page never drops
         through to a Latin-only face mid-sentence. */
      font-family: 'Rubik', system-ui, -apple-system, 'Segoe UI', 'Noto Sans Hebrew', Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      font-size: var(--fs-200);
      line-height: 1.55;
    }

    ::-webkit-scrollbar { width: 4px; height: 4px; }
    ::-webkit-scrollbar-track { background: transparent; }
    ::-webkit-scrollbar-thumb { background: var(--border-2); border-radius: 4px; }

    /* Sidebar */
    #sidebar {
      position: fixed;
      right: 0; top: 0; bottom: 0;
      width: var(--sidebar-w);
      background: var(--surface);
      border-left: 1px solid var(--border);
      display: flex;
      flex-direction: column;
      z-index: 40;
      overflow: hidden;
    }

    #sb-logo {
      padding: 20px 20px 16px;
      border-bottom: 1px solid var(--border);
      flex-shrink: 0;
    }

    #sb-client-wrap {
      padding: 12px 12px 8px;
      flex-shrink: 0;
    }

    #sb-nav {
      flex: 1;
      padding: 4px 12px 12px;
      display: flex;
      flex-direction: column;
      gap: 2px;
      overflow-y: auto;
    }

    #sb-footer {
      padding: 12px 16px 16px;
      border-top: 1px solid var(--border);
      flex-shrink: 0;
    }

    /* ── System-health strip ───────────────────────────────────────────────
       Three measured facts in the sidebar foot: is the API answering, how many
       portfolio artefacts are loaded, when the data actually landed. Rendered
       by systemHealthStrip() in dashboard.js.

       Replaces two rows of inline styles. Nothing here is a new value: --sp-*,
       --fs-100/--lh-100, --r-md, --surface-2, --border, --text-2/-3 and the
       --status-* set are all already the file's vocabulary. The row is a
       three-column grid rather than a flex row so the dots, the labels and the
       values line up as three columns down the strip instead of each row
       finding its own alignment. */
    /* A command stated in words, with the invocation folded away. The sentence
       is the instruction; the command is the escape hatch for when a stage
       misbehaves. Same construction as .rf-raw, which folds the JSON dumps. */
    .cmd-what {
      font-size: var(--fs-200); color: var(--text-2); line-height: 1.55;
    }
    .cmd-fold { margin-top: var(--sp-2); }
    /* Primary action in the sidebar rail. Full width because the rail is
       narrow and this is the only action in it — not because .ea-btn is
       full width (it is not; that would fight the component). Tokens only:
       the markup this replaces hardcoded rgba(14,165,233,…), the sky-blue
       accent this theme no longer uses. */
    .sb-newclient {
      display: flex; align-items: center; justify-content: center; gap: 6px;
      width: 100%; height: 38px; margin-bottom: var(--sp-2);
      border: 1px solid var(--accent); border-radius: var(--r-md);
      background: var(--accent-soft); color: var(--accent-on-tint);
      font-family: inherit; font-size: var(--fs-200); font-weight: var(--fw-semi);
      cursor: pointer;
      transition:background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
    }
    .sb-newclient:hover { background: var(--accent); color: var(--on-accent); }
    .sb-newclient:focus-visible { outline: none; box-shadow: var(--sh-focus); }

    .sys-health {
      display: flex;
      flex-direction: column;
      gap: var(--sp-1);
      padding: var(--sp-2);
      border: 1px solid var(--border);
      border-radius: var(--r-md);
      background: var(--surface-2);
    }
    .sh-row {
      display: grid;
      grid-template-columns: 7px auto 1fr;
      align-items: center;
      gap: var(--sp-2);
      font-size: var(--fs-100);
      line-height: var(--lh-100);
    }
    .sh-k { color: var(--text-3); font-weight: var(--fw-medium); }
    /* text-align:end, not right — the sidebar is RTL and the value column has
       to hug the inline end of the strip in either direction. */
    .sh-v { color: var(--text-2); font-weight: var(--fw-semi); text-align: end; }
    /* Colour reinforces the dot; it is never the only carrier, because each
       row also states its status in words. */
    .sh-row.is-ok   .sh-v { color: var(--status-done); }
    .sh-row.is-warn .sh-v { color: var(--status-warn); }
    .sh-row.is-fail .sh-v { color: var(--status-fail); }
    .sh-row.is-idle .sh-v { color: var(--text-3); }
    .sh-foot { display: flex; justify-content: flex-end; margin-top: var(--sp-2); }

    /* Topbar */
    /* Safe area. dashboard.html now carries viewport-fit=cover, which is what
       makes env(safe-area-inset-*) resolve to anything but 0 in Safari — and
       which also lets the page draw INTO the notch and the home-indicator
       strip. Opting in without paying for it is worse than not opting in, so
       the insets are absorbed here.

       Absorbed by growing the header rather than by padding each child: five
       rules already position themselves off var(--header-h) (#content-wrap's
       margin and min-height, #mobile-tabs' top, the mobile margin override).
       Padding the bar alone would move its contents down and leave all five
       measuring from a line that no longer exists. */
    :root {
      --safe-top: env(safe-area-inset-top, 0px);
      --safe-bottom: env(safe-area-inset-bottom, 0px);
      --header-h: calc(var(--header-h-base, 56px) + var(--safe-top));
      /* The bottom tab bar's full occupied height, in one place. Three rules
         need to clear this bar — #content-wrap's padding, #chat-fab and
         #chat-panel — and each used to restate `52px + safe-bottom` (or, in
         the FAB's case, not clear it at all, which is how the FAB ended up
         sitting on top of the bar's own customise button). .mob-tab's
         min-block-size is the 52px; keep the two in sync. */
      --mobile-nav-h: calc(52px + var(--safe-bottom));
    }

    #topbar {
      position: fixed;
      top: 0;
      left: var(--wp-w, 0px);
      right: var(--sidebar-w);
      height: var(--header-h);
      /* Content sits below the notch; the bar's background fills it. */
      padding-top: var(--safe-top);
      /* No transition on `left` — same defect as #content-wrap's margin-left
         below: the value comes from var(--wp-w), and a media-query-driven
         change to that variable leaves the animated property stale. */
      background: var(--surface);   /* opaque: glass read as a template */
      border-bottom: 1px solid var(--border);
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 0 24px;
      z-index: 30;
      gap: 12px;
    }

    /* #hdr-right carries the run-agents button and the view switcher. It was a
       fixed-width flex child in a nowrap, overflow:visible fixed header, so
       below ~459px it slid past the viewport edge — measured at left:-72 at
       375px, where elementFromPoint returned null. Because the header is fixed
       and visible it produced no scrollbar either, so the control did not look
       broken, it simply ceased to exist. It scrolls inside its own box now. */
    #hdr-right {
      min-width: 0;
      overflow-x: auto;
      overflow-y: hidden;
      scrollbar-width: none;
      -webkit-overflow-scrolling: touch;
    }
    #hdr-right::-webkit-scrollbar { display: none; }
    #hdr-right > div { flex-wrap: nowrap; }
    #hdr-left { min-width: 0; }

    /* Content wrap */
    #content-wrap {
      margin-right: var(--sidebar-w);
      margin-left: var(--wp-w, 0px);
      margin-top: var(--header-h);
      /* 24px, was 40/48 then 32px. The workspace is information-dense by
         design and the old horizontal inset cost ~48px of usable width per
         side at the width this dashboard is actually used at. Shell-wide:
         applies to every tab, not just the flow grid. */
      padding: var(--sp-6) var(--sp-6);
      min-height: calc(100vh - var(--header-h));
      /* NO transition on margin-left. It used to animate the work-plan
         collapse, but the animated value comes from var(--wp-w), and when
         --wp-w changes because a MEDIA QUERY flipped (rather than because the
         collapse class toggled), the transition leaves margin-left stuck at
         its previous computed value. Live-resizing across the 1024px
         breakpoint therefore left the content offset by the old rail width —
         at 1600px the panel overlapped the content, and only a forced reflow
         corrected it. Clean loads always looked fine, which is why it
         survived. (The work-plan panel was removed on 2026-10-21; --wp-w is
         now never set, so the fallback 0px always applies.) */
    }
    /* --content-max was declared and never consumed by anything, so the stated
       intent had no enforcement: past ~1900px the centre column kept stretching
       and the KPI row spread until the tiles stopped reading as a group. It
       binds here. Below the cap this is inert, so narrow and mid widths are
       unchanged. */
    #content-wrap > * {
      max-width: var(--content-max);
      margin-inline: auto;
    }

    /* Cards */
    .ea-card {
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: var(--r-lg);
      box-shadow: var(--sh-xs);
      transition:border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
    }

    .ea-card:hover {
      border-color: var(--border-strong);
      box-shadow: var(--sh-sm);
    }

    /* "Selected" KPI treatment — matches the blue-ringed stat tile pattern
       from the reference layout (AgencyAnalytics). A ring, not just a border
       color swap, so it reads as "this is the number in focus" rather than a
       hover state that happened to stick. */
    .ea-card--selected {
      border-color: var(--select-ring);
      box-shadow: 0 0 0 2px var(--select-ring);
    }

    .ea-card-pad {
      padding: 24px;
    }

    /* Agent DNA tab (renderAgentDNA in dashboard.js), redesigned 2026-08-25.
       The old version had one failure mode: a client with zero real agent
       reports — the common case — fell through to _buildStaticDNA(), fifteen
       near-identical cards, each carrying its own "לדוגמה בלבד" badge. Fifteen
       repeats of the same warning is not fifteen pieces of information; it is
       one piece of information said fifteen times, which reads as noise, not
       content. That fallback is now ONE empty state with ONE explanation, and
       the agent glossary — genuinely useful, but reference material, not a
       report — collapses into a single compact chip row instead of masquerading
       as fifteen report cards. */

    .dna-kpis {
      display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
      gap: var(--sp-3); margin-bottom: var(--sp-5);
    }
    .dna-kpi {
      background: var(--surface); border: 1px solid var(--border);
      border-radius: 12px; padding: var(--sp-4);
    }
    .dna-kpi-val { font-size: var(--fs-400); font-weight: var(--fw-bold); color: var(--text); line-height: 1; }
    .dna-kpi-val[data-tone="warn"] { color: var(--o); }
    .dna-kpi-val[data-tone="bad"]  { color: var(--r); }
    .dna-kpi-label { font-size: var(--fs-100); color: var(--text-3); margin-top: var(--sp-1); }

    .dna-grid {
      display: grid; gap: var(--sp-4);
      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    }
    .dna-card {
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: 12px;
      padding: 16px;
      /* Was borderless-flat — a card with no shadow token applied reads as a
         plain bordered box, not a card. --sh-xs is the system's own lightest
         elevation step (already used by nothing here before this). */
      box-shadow: var(--sh-xs);
      transition: border-color var(--dur-base) var(--ease-out),
        transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
      /* Entrance stagger — grid items fade+rise in rather than all snapping
         on at once. Capped at 8 explicit steps (matches Emil's "keep stagger
         short, 30-80ms between items" guidance); a longer list just shares
         the last step instead of growing the wait. animation, not transition:
         this fires once per render, never rapidly re-triggered, which is
         exactly where keyframes are fine and transitions would gain nothing. */
      animation: ea-card-in var(--dur-slow) var(--ease-out) both;
    }
    @media (hover: hover) {
      .dna-card:hover { border-color: var(--border-2); transform: translateY(-1px); box-shadow: var(--sh-sm); }
    }
    @keyframes ea-card-in {
      from { opacity: 0; transform: translateY(8px); }
      to   { opacity: 1; transform: translateY(0); }
    }
    .dna-grid > .dna-card:nth-child(1) { animation-delay: 0ms; }
    .dna-grid > .dna-card:nth-child(2) { animation-delay: 35ms; }
    .dna-grid > .dna-card:nth-child(3) { animation-delay: 70ms; }
    .dna-grid > .dna-card:nth-child(4) { animation-delay: 105ms; }
    .dna-grid > .dna-card:nth-child(5) { animation-delay: 140ms; }
    .dna-grid > .dna-card:nth-child(6) { animation-delay: 175ms; }
    .dna-grid > .dna-card:nth-child(7) { animation-delay: 210ms; }
    .dna-grid > .dna-card:nth-child(n+8) { animation-delay: 245ms; }
    @media (prefers-reduced-motion: reduce) {
      .dna-card { animation: none; }
    }

    .dna-header {
      display: flex;
      align-items: center;
      gap: 10px;
      margin-bottom: 10px;
    }
    /* Role-coded avatar, not a stock portrait: the icon already carries the
       agent's function (dnaIconSvg), --dna-role sets which of the six existing
       chart hues (--viz-1..6) it sits on — real client photos stay on client/
       media cards, never here. */
    .dna-icon {
      display: flex; align-items: center; justify-content: center;
      flex-shrink: 0; width: 34px; height: 34px; border-radius: 9px;
      background: color-mix(in srgb, var(--dna-role, var(--viz-1)) 16%, var(--surface));
      color: var(--dna-role, var(--viz-1));
    }
    .dna-name { font-weight: 700; font-size: var(--fs-200); color: var(--text); flex: 1; min-width: 0;
      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .dna-role-label { font-size: var(--fs-100); color: var(--text-3); display: block; margin-top: 1px; }
    .dna-stage {
      font-size: var(--fs-100); font-family: monospace; color: var(--text-3);
      background: var(--surface-2); border: 1px solid var(--border);
      border-radius: 5px; padding: 1px 7px; flex-shrink: 0;
    }
    .dna-status-ok, .dna-status-err {
      display: inline-flex; align-items: center; gap: 4px;
      font-size: var(--fs-100); white-space: nowrap; flex-shrink: 0;
    }
    .dna-status-ok  { color: var(--g); }
    .dna-status-err { color: var(--r); }
    .dna-status-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; flex-shrink: 0; }

    .dna-action { font-size: var(--fs-200); color: var(--text-2); line-height: 1.6; }
    /* AgentReport.to_dict() has always carried `warnings` separately from
       `what_i_did` — an agent-authored flag on an otherwise-successful run.
       --o (the same warning-orange used elsewhere) marks it distinct from
       the plain-text action log above it, without needing a second status
       color that would compete with .dna-status-ok/.dna-status-err. */
    .dna-warnings {
      font-size: var(--fs-100); color: var(--o); line-height: 1.5;
      margin-top: var(--sp-2); display: flex; gap: 6px; align-items: flex-start;
    }
    .dna-metric {
      font-size: var(--fs-100); color: var(--text-3); background: var(--surface-2);
      border-radius: 6px; padding: 3px 9px; margin: 0 6px 6px 0;
    }

    /* The agent glossary. One collapsed section, not fifteen open cards —
       expand for the reference, not by default. */
    .dna-ref { margin-bottom: var(--sp-5); }
    .dna-ref > summary {
      cursor: pointer; font-size: var(--fs-100); color: var(--text-3);
      padding: var(--sp-2) 0; list-style: none; display: flex; align-items: center; gap: 6px;
    }
    .dna-ref > summary::-webkit-details-marker { display: none; }
    .dna-ref-grid {
      display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3);
    }
    .dna-ref-chip {
      display: inline-flex; align-items: center; gap: 6px;
      border: 1px solid var(--border); border-radius: 999px;
      padding: 5px 12px 5px 6px; font-size: var(--fs-100); color: var(--text-2);
      background: var(--surface);
    }
    .dna-ref-chip .dna-icon { width: 22px; height: 22px; border-radius: 50%; }

    .dna-empty {
      text-align: center; padding: var(--sp-8) var(--sp-4);
      border: 1px solid var(--border); border-radius: 12px;
      background: var(--surface); margin-bottom: var(--sp-5);
    }
    .dna-empty-icon { font-size: 28px; margin-bottom: var(--sp-2); }
    .dna-empty-title { font-size: var(--fs-300); font-weight: var(--fw-semi); color: var(--text); }
    .dna-empty-sub { font-size: var(--fs-100); color: var(--text-3); margin-top: var(--sp-2); max-width: 42ch; margin-inline: auto; }

    /* Generic empty/error state, same anatomy as .dna-empty (icon, title,
       sub) but not DNA-specific — first reused by the agency-wide Overview,
       which used to hand-write this block twice (once for "no report yet",
       once for "failed to load") with no title/sub separation at all. */
    .ea-empty-state {
      text-align: center; padding: var(--sp-8) var(--sp-4);
      max-width: 480px; margin: 0 auto;
    }
    .ea-empty-icon { font-size: 32px; margin-bottom: var(--sp-3); }
    .ea-empty-title { font-size: var(--fs-300); font-weight: var(--fw-semi); color: var(--text); margin-bottom: var(--sp-2); }
    .ea-empty-sub { font-size: var(--fs-100); color: var(--text-3); line-height: 1.7; }

    /* A one-word freshness flag, reused wherever a widget can measure its own
       staleness (age_seconds is self-reported by the report, not guessed).
       The base carries layout only; each state supplies its own color, so a
       future LIVE/UNAVAILABLE variant is a second modifier, not a rewrite. */
    .status-badge {
      display: inline-flex; align-items: center; font-size: var(--fs-100);
      font-weight: var(--fw-semi); padding: 2px 8px; border-radius: 999px;
    }
    .status-badge--stale { color: var(--o); background: color-mix(in srgb, var(--o) 14%, transparent); }

    /* Agency-wide Overview (renderAgencyOverview) — the tab-overview host
       when no client is selected. Was six ad-hoc inline-styled divs; now the
       same kpiTile()/rg-auto components every other surface uses. */
    .agy-head { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-5); }
    .agy-head-name { font-size: var(--fs-300); font-weight: var(--fw-bold); color: var(--text); }
    .agy-head-age { font-size: var(--fs-100); color: var(--text-3); }
    .agy-section-lbl { font-size: var(--fs-100); color: var(--text-3); margin: var(--sp-5) 0 var(--sp-2); }
    .agy-status { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; font-size: var(--fs-100); color: var(--text-3); min-height: 20px; }
    .agy-rows { display: flex; flex-direction: column; gap: var(--sp-2); }
    .agy-row {
      display: flex; align-items: center; gap: var(--sp-3);
      background: var(--surface-2); border: 1px solid var(--border);
      /* Client color was carried in the data (CLIENTS[].color) but never
         drawn here — every row read as an interchangeable gray stack. The
         inline border-inline-start-color (dashboard.js) needs a wider start
         edge to actually read as a color, not a 1px hairline. */
      border-inline-start-width: 3px;
      border-radius: 12px; padding: var(--sp-3) var(--sp-4);
      cursor: pointer; min-height: 44px;
      /* A real onclick + role="button" + keydown handler (dashboard.js) —
         unlike .dna-card/.cl-card, this one genuinely is a button, so it
         gets the same hover/press treatment .flow-card already has. */
      box-shadow: var(--sh-xs);
      transition: border-color var(--dur-base) var(--ease-out),
        box-shadow var(--dur-base) var(--ease-out), transform var(--dur-fast) var(--ease-out);
    }
    @media (hover: hover) {
      .agy-row:not(.is-unknown):hover { border-color: var(--border-strong); box-shadow: var(--sh-sm); }
    }
    .agy-row:not(.is-unknown):active { transform: scale(0.98); }
    .agy-row:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
    .agy-row.is-unknown { cursor: default; opacity: .45; box-shadow: none; }
    .agy-row-avatar, .cl-avatar.agy-row-avatar { width: 32px; height: 32px; border-radius: 9px; font-size: 12px; }
    .agy-row-avatar--none { display: flex; align-items: center; justify-content: center; color: var(--text-3); }
    .live-dot { display: inline-block; width: 7px; height: 7px; margin-inline-end: 6px; border-radius: 50%; background: var(--status-done); vertical-align: 1px; }
    @media (prefers-reduced-motion: no-preference) { .live-dot { animation: live-dot 2.4s var(--ease-out) infinite; } }
    @keyframes live-dot { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--status-done) 45%, transparent); } 70%, 100% { box-shadow: 0 0 0 6px transparent; } }
    .agy-row-name { flex: 1; min-width: 0; font-size: var(--fs-200); font-weight: var(--fw-semi); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .agy-row-tag, .agy-row-stat { font-size: var(--fs-100); color: var(--text-3); flex-shrink: 0; font-variant-numeric: tabular-nums; }
    .agy-row-tag.is-warn { color: var(--status-warn); font-weight: 600; }
    .ui-ic { display: inline-flex; vertical-align: -3px; margin-inline-end: 4px; }
    .run-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; border: 1.5px solid var(--text-3); } .run-dot.is-on { background: var(--status-done); border-color: var(--status-done); }
    .ui-ic[data-k="check"] { color: var(--status-done); } .ui-ic[data-k="x"] { color: var(--status-fail); } .ui-ic[data-k="warn"] { color: var(--status-warn); }
    @media (max-width: 640px) { .agy-row { flex-wrap: wrap; row-gap: 6px; } .agy-row-id { flex: 1 1 calc(100% - 60px); min-width: 0; } }

    /* KPI rows, turned up. 'agy-kpi-row' (Agency Overview, the default
       landing view) and 'ov-kpi-row' (client-scoped Overview's "מדדים"
       accordion, dashboard.js ~L12036) are the only two places kpiTile() is
       used (see DashboardGrid's own comment near renderAgencyOverview) — one
       rule list, shared by both selectors, so the two surfaces read as the
       same visual language instead of drifting into two washes of the same
       idea. Every other .kpi consumer (there are none today, but the class
       itself is shared infrastructure) is untouched. Their six-color system
       already exists per metric (kpi-ico--content/stages/cost/pipeline/
       clients/tokens below) — it was just turned down to a 12-14% tint on a
       28px chip, so from a normal viewing distance every card read as
       identically white. Same colors, same icons, same data: solid chips
       instead of washes, plus a top accent bar in the tile's own hue, so
       each row reads as distinct vitals instead of one repeated card. */
    .agy-kpi-row.rg-auto, .ov-kpi-row.rg-4 { gap: var(--sp-3); }
    .agy-kpi-row .kpi, .ov-kpi-row .kpi {
      position: relative; overflow: hidden;
      border-top: 3px solid transparent;
    }
    .agy-kpi-row .kpi:has(.kpi-ico--content), .ov-kpi-row .kpi:has(.kpi-ico--content)   { border-top-color: var(--accent); }
    .agy-kpi-row .kpi:has(.kpi-ico--stages),  .ov-kpi-row .kpi:has(.kpi-ico--stages)    { border-top-color: var(--g); }
    .agy-kpi-row .kpi:has(.kpi-ico--cost),    .ov-kpi-row .kpi:has(.kpi-ico--cost)      { border-top-color: var(--o); }
    .agy-kpi-row .kpi:has(.kpi-ico--pipeline),.ov-kpi-row .kpi:has(.kpi-ico--pipeline)  { border-top-color: var(--p); }
    .agy-kpi-row .kpi:has(.kpi-ico--clients)  { border-top-color: var(--viz-2); }
    .agy-kpi-row .kpi:has(.kpi-ico--tokens)   { border-top-color: var(--viz-4); }
    .agy-kpi-row .kpi-ico, .ov-kpi-row .kpi-ico { width: 30px; height: 30px; border-radius: 9px; }
    .agy-kpi-row .kpi-ico--content,  .ov-kpi-row .kpi-ico--content  { color: var(--text-inverse); background: var(--accent); }
    .agy-kpi-row .kpi-ico--stages,   .ov-kpi-row .kpi-ico--stages   { color: var(--text-inverse); background: var(--g); }
    .agy-kpi-row .kpi-ico--cost,     .ov-kpi-row .kpi-ico--cost     { color: var(--text-inverse); background: var(--o); }
    .agy-kpi-row .kpi-ico--pipeline, .ov-kpi-row .kpi-ico--pipeline { color: var(--text-inverse); background: var(--p); }
    .agy-kpi-row .kpi-ico--clients  { color: var(--text-inverse); background: var(--viz-2); }
    .agy-kpi-row .kpi-ico--tokens   { color: var(--text-inverse); background: var(--viz-4); }
    /* .is-empty already recedes the rest of the tile (dashed border, 45%
       icon opacity, no shadow) — the six-color signal above is a real
       measurement's own color, and a tile with nothing to say must not
       borrow it. Without this, an empty tile's top edge stayed at full
       saturation while everything else about it said "reserved, not
       broken" — the one part of the tile still arguing "lifted". Wins by
       source order over the color rules above (equal specificity). */
    .agy-kpi-row .kpi.is-empty, .ov-kpi-row .kpi.is-empty { border-top-color: var(--border); }

    /* Caption cards — mobile-first readable */
    .caption-card {
      display: flex;
      flex-direction: column;
      gap: 12px;
      padding: 16px;
      background: var(--surface-2);
      border: 1px solid var(--border);
      border-radius: 8px;
    }

    .caption-text {
      font-size: 1.2rem;
      line-height: 1.7;
      color: var(--text);
      font-family: 'Rubik', sans-serif;
      direction: rtl;
      word-break: break-word;
      white-space: pre-line;
    }

    .caption-hook {
      font-size: 1.2rem;
      font-weight: 700;
      color: var(--text);
      font-family: 'Rubik', sans-serif;
      direction: rtl;
    }

    .caption-body {
      font-size: 1.2rem;
      color: var(--text-3);
      line-height: 1.7;
      font-family: 'Rubik', sans-serif;
      direction: rtl;
    }

    .caption-cta {
      font-size: 1rem;
      font-weight: 600;
      color: var(--status-done);
      font-family: 'Rubik', sans-serif;
      direction: rtl;
    }

    .caption-tags {
      font-size: 0.85rem;
      color: var(--status-running);
      font-family: 'Rubik', sans-serif;
      direction: rtl;
      flex-wrap: wrap;
      display: flex;
      gap: 6px;
    }

    @media (max-width: 640px) {
      .caption-text, .caption-hook, .caption-body { font-size: 1.05rem; }
    }

    /* Nav items */
    .nav-item {
      display: flex;
      align-items: center;
      gap: 9px;
      padding: 7px 12px;
      border-radius: 7px;
      font-size: var(--fs-200);
      font-weight: 500;
      color: var(--text-2);
      background: none;
      border: none;
      cursor: pointer;
      transition:background var(--dur-fast) ease, color var(--dur-fast) ease, transform var(--dur-base) var(--ease-out);
      width: 100%;
      text-align: right;
    }

    .nav-item:hover {
      background: var(--surface-2);
      color: var(--text);
    }
    .nav-item:active { transform: scale(0.97); }

    .nav-item.active {
      background: color-mix(in srgb, var(--accent) 12%, transparent);
      color: var(--accent-on-tint);   /* --accent here measured 4.16:1 */
    }

    /* Nav groups — section headers over what was a flat list of 25 tabs.
       ALL_TABS carries a `group` field and the sidebar renders one
       .nav-group per TAB_GROUPS entry; see the grouping spec. Purely
       presentational: visibleTabIds() still decides WHICH tabs exist and
       ea-tabs-order-v1 still decides their order inside a group.

       Expected markup, because the collapsed rail below depends on it:

         <div class="nav-group">
           <div class="nav-group-label"><span class="nav-group-text">הפקה</span></div>
           <button class="nav-item">…</button>
         </div>

       The label text MUST sit in .nav-group-text. A bare text node cannot be
       hidden on the 44px rail, and the rail is the case this exists for. */
    .nav-group + .nav-group { margin-block-start: 14px; }

    /* The header is a real <button>, not the <div> the block above sketched:
       the sections collapse, so the header is a control, and a control only a
       mouse can reach is not navigation. Reset the UA button styling rather
       than restyle around it — `font: inherit` in particular is what keeps the
       label on the Hebrew stack instead of dropping to the system font. */
    .nav-group-label {
      inline-size: 100%;
      background: none;
      border: 0;
      font: inherit;
      text-align: start;
      cursor: pointer;
      /* 4px of vertical padding is right for a static label and far too small
         for a tap target, so the box grows to 32px here instead. Still reads as
         a word and a hairline; now it can be hit on a phone. */
      min-block-size: 32px;
    }

    .nav-group-label:hover .nav-group-text,
    .nav-group-label:focus-visible .nav-group-text { color: var(--text-2); }

    .nav-group-label:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: -2px;
      border-radius: 6px;
    }

    /* The hairline is .nav-group-label::after with flex:1, and generated
       ::after content always follows real children — so the chevron lands at
       the far end without needing an order or a margin. */
    .nav-group-chev {
      flex-shrink: 0;
      color: var(--text-3);
      transition: transform .16s ease;
    }

    .nav-group.is-collapsed .nav-group-chev { transform: rotate(-90deg); }

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

    /* [hidden] is already set on the wrapper by the renderer; this is what
       makes it stick, since .nav-group-items sets display and a bare [hidden]
       loses to any display declaration. */
    .nav-group.is-collapsed .nav-group-items { display: none; }

    @media (prefers-reduced-motion: reduce) {
      .nav-group-chev { transition: none; }
    }

    .nav-group-label {
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 4px 12px;
      font-size: var(--fs-100);
      font-weight: 600;
      color: var(--text-3);
      user-select: none;
      /* No text-transform/letter-spacing on purpose. Uppercase-with-tracking
         is a Latin eyebrow convention; Hebrew has no uppercase, and tracking
         only pulls its letterforms apart. These labels are Hebrew first. */
    }

    /* The rule carries the grouping when the word is gone, so it is part of
       the label rather than a border on the group — one element, one signal,
       and nothing to keep in sync. */
    .nav-group-label::after {
      content: "";
      flex: 1;
      height: 1px;
      background: var(--border);
    }

    /* NO body.wp-collapsed RULES HERE, DELIBERATELY. An earlier draft of this
       block hid .nav-group-text and strengthened the hairline to a measured
       3.43:1 under body.wp-collapsed, for a 44px rail. Both were wrong twice
       over, and the shape of the mistake is worth keeping:

       `wp` is #work-plan, docked OPPOSITE #sidebar (see the --wp-w comment
       below). body.wp-collapsed governs that panel, not this nav — so those
       rules fired when a user collapsed the work plan and blanked all seven
       nav labels for a reason they could not see. An unrelated flag reaching
       into this component is worse than dead weight.

       And the rail they targeted does not exist for #sidebar at any width:
       full above 1024, --sidebar-w:184px to 1024 (room for a word), and
       display:none !important at 768 where #mobile-tabs takes over. There is
       no narrow-but-visible state to style. The 640px block already carries a
       note about deleting exactly this kind of rule — children of a hidden
       parent — so this is the second time the file has had to learn it.

       Consequence for the hairline: it stays var(--border) at 1.19:1 light /
       1.31:1 dark and that is correct, because .nav-group-text is always
       rendered here. The WORD carries the grouping (5.14:1 / 5.36:1, both
       measured); the rule is decoration and is held to no contrast floor. It
       would only inherit the non-text 3:1 floor if it were ever the sole
       signal, which — with no rail — it never is. */

    /* Dots */
    .dot {
      width: 7px;
      height: 7px;
      border-radius: 50%;
      display: inline-block;
      flex-shrink: 0;
    }

    /* These five duplicated the status vocabulary as raw hex, in the old
       pre-redesign values, so a status dot and its label could disagree. */
    .dot-green  { background: var(--status-done); }
    .dot-blue   { background: var(--status-running); }
    .dot-orange { background: var(--status-warn); }
    .dot-red    { background: var(--status-fail); }
    .dot-gray   { background: var(--status-idle); }

    .dot-pulse {
      animation: pulse-dot 2s infinite;
    }

    /* RTL text */
    .rtl-text {
      /* bidi-override forced EVERY character into the paragraph direction,
         which reverses embedded Latin runs one character at a time — the
         comment at dashboard.js:1658 records this class turning "EA Marketing"
         into "AE gnitekraM", and the fix there was to stop applying the class
         rather than fix it. plaintext takes the direction from each line's
         first strong character instead, which is exactly right for the mixed
         Hebrew/Latin strings this class exists for (client names, pitches). */
      direction: rtl;
      font-family: 'Rubik', sans-serif;
      text-align: start;
      unicode-bidi: plaintext;
    }

    /* Section label */
    .sec-label {
      font-size: var(--fs-100);
      font-weight: 600;
      letter-spacing: 0.08em;
      text-transform: uppercase;
      color: var(--text-3);
      margin-bottom: 16px;
    }

    /* ── KPI tile ────────────────────────────────────────────────────────────
       Its own component rather than .ea-card + .ea-card-pad. The generic card
       padding is sized for a card with content in it; wrapped around a label,
       a number and a caption it left most of the tile empty, and four of them
       ate ~280px of vertical space to show four numbers. Denser padding, and
       the measurement is the only thing with weight. */
    .kpi {
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: var(--r-lg);
      padding: 14px 16px 15px;
      min-width: 0;
      /* Was borderless-flat, same gap .dna-card had before its own fix —
         this is the Overview tab, the first screen every session opens. */
      box-shadow: var(--sh-xs);
      transition:border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
      /* Same entrance stagger as .dna-card/.cl-card: fires once per grid
         render, never rapidly re-triggered. */
      animation: ea-card-in var(--dur-slow) var(--ease-out) both;
    }
    .kpi:hover { border-color: var(--border-strong); box-shadow: var(--sh-sm); }
    .rg-auto > .kpi:nth-child(1) { animation-delay: 0ms; }
    .rg-auto > .kpi:nth-child(2) { animation-delay: 35ms; }
    .rg-auto > .kpi:nth-child(3) { animation-delay: 70ms; }
    .rg-auto > .kpi:nth-child(4) { animation-delay: 105ms; }
    .rg-auto > .kpi:nth-child(5) { animation-delay: 140ms; }
    .rg-auto > .kpi:nth-child(6) { animation-delay: 175ms; }
    .rg-auto > .kpi:nth-child(7) { animation-delay: 210ms; }
    .rg-auto > .kpi:nth-child(n+8) { animation-delay: 245ms; }
    @media (prefers-reduced-motion: reduce) {
      .kpi { animation: none; }
    }
    /* No datum yet. GA4 and Amplitude drop the whole tile back rather than
       parking a placeholder glyph at full value weight — otherwise the tiles
       with nothing to say compete with the ones that have a real measurement.
       The dashed border states "reserved, not broken" without a second colour. */
    .kpi.is-empty {
      border-style: dashed;
      background: var(--surface-2);
      /* "Reserved, not broken" reads as recessed, not lifted — the new
         resting shadow above is for tiles with a real measurement. */
      box-shadow: none;
    }
    .kpi.is-empty .kpi-num { font-weight: var(--fw-medium); color: var(--text-3); }
    .kpi.is-empty:hover { border-color: var(--border); }
    /* ── Orchestrator assistant ─────────────────────────────────────────────
       inset-inline-END, matching client_dashboard's launcher. In this RTL
       document that is the left edge — the nav sidebar owns inline-start, so
       anchoring there would drop the launcher on top of the navigation.
       The panel floats above the FAB rather than over it, so the launcher
       stays available as the close control. */
    #chat-fab{
      /* Clear of the home indicator and the gesture strip — at inset-block-end
         20px on a modern iPhone the button sits under the swipe-up area, where
         a tap is as likely to close the app as open the assistant. */
      position:fixed;inset-inline-end:20px;
      inset-block-end:calc(20px + var(--safe-bottom));z-index:60;
      width:46px;height:46px;border-radius:50%;border:1px solid var(--border);
      background:var(--surface);box-shadow:var(--sh-md);cursor:pointer;
      display:flex;align-items:center;justify-content:center;color:var(--accent);
      transition:transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
    }
    #chat-fab:hover{transform:translateY(-2px);box-shadow:var(--sh-lg)}
    #chat-panel{
      position:fixed;inset-inline-end:20px;inset-block-end:84px;z-index:61;
      width:min(380px,calc(100vw - 40px));max-height:min(560px,calc(100vh - 124px));
      max-height:min(560px,calc(100dvh - 124px));  /* iOS: 100vh ignores the address bar */
      display:flex;flex-direction:column;overflow:hidden;
      background:var(--surface);border:1px solid var(--border);
      border-radius:var(--r-lg);box-shadow:var(--sh-lg);
      opacity:0;visibility:hidden;pointer-events:none;transform:translateY(8px);
    }
    #chat-panel.open{opacity:1;visibility:visible;pointer-events:auto;transform:translateY(0)}
    @media (prefers-reduced-motion: no-preference) {
      #chat-panel{transition:opacity var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out)}
    }
    .chat-hd{
      display:flex;align-items:center;gap:8px;flex:none;
      padding:10px 12px;border-bottom:1px solid var(--border);
    }
    .chat-title{font-size:var(--fs-200);font-weight:var(--fw-semi);color:var(--text)}
    .chat-state{font-size:var(--fs-100);color:var(--text-3);margin-inline-start:auto}
    .chat-x{flex:none;width:auto}
    .chat-log{
      flex:1;min-height:0;overflow-y:auto;padding:12px;
      display:flex;flex-direction:column;gap:8px;
    }
    .chat-msg{
      font-size:var(--fs-200);line-height:1.55;padding:8px 10px;
      border-radius:10px;max-width:88%;overflow-wrap:anywhere;white-space:pre-wrap;
    }
    .chat-msg.is-me{align-self:flex-start;background:var(--accent);color:var(--on-accent)}
    .chat-msg.is-bot{align-self:flex-end;background:var(--surface-2);color:var(--text)}
    .chat-msg.is-note{
      align-self:center;max-width:100%;background:none;padding:2px 0;
      font-size:var(--fs-100);color:var(--text-3);text-align:center;
    }
    /* The spend gate. It deliberately does not look like a chat bubble: this
       is a control that spends money, and it must not be skimmed past as if
       it were more conversation. */
    .chat-msg.is-gate{
      align-self:stretch;max-width:100%;background:var(--status-warn-bg);
      border:1px solid var(--status-warn);border-radius:var(--r-md);
      padding:12px;display:flex;flex-direction:column;gap:6px;white-space:normal;
    }
    .gate-title{font-size:var(--fs-200);font-weight:var(--fw-bold);color:var(--text)}
    .gate-row{font-size:var(--fs-100);color:var(--text-2);display:flex;gap:6px;align-items:baseline}
    .gate-row b{color:var(--text-3);font-weight:var(--fw-semi)}
    .gate-note{font-size:var(--fs-100);color:var(--text-3);line-height:1.5}
    .gate-warn{font-size:var(--fs-100);color:var(--o);line-height:1.5;font-weight:var(--fw-medium)}
    .gate-actions{display:flex;gap:6px;margin-top:4px}
    .gate-actions .ea-btn{flex:1;justify-content:center}
    .chat-input-row{
      display:flex;gap:6px;align-items:flex-end;flex:none;
      padding:10px 12px;border-top:1px solid var(--border);
    }
    .chat-input-row textarea{
      flex:1;min-width:0;resize:none;max-height:96px;
      font-family:inherit;font-size:var(--fs-200);line-height:1.5;
      padding:8px 10px;border-radius:9px;color:var(--text);
      border:1px solid var(--border-control,var(--border));background:var(--surface);
    }
    .chat-input-row textarea:focus-visible{outline:none;box-shadow:var(--sh-focus);border-color:var(--accent)}
    /* Claude Code quick actions: a menu that opens upward over the log. */
    .chat-qa{position:relative;flex:none;padding:8px 12px 0}
    .chat-qa-toggle{font-size:var(--fs-100)}
    .chat-qa-menu{
      position:absolute;inset-block-end:calc(100% + 4px);inset-inline-start:12px;z-index:2;
      min-width:220px;padding:4px;display:flex;flex-direction:column;gap:2px;
      background:var(--surface);border:1px solid var(--border);
      border-radius:var(--r-md);box-shadow:var(--sh-lg);
    }
    .chat-qa-menu[hidden]{display:none}
    .chat-qa-item{width:100%;justify-content:flex-start;text-align:start;border-color:transparent}
    /* The header's permanent Claude button. */
    .hdr-claude{flex-shrink:0;white-space:nowrap}
    .hdr-claude-glyph{color:var(--accent)}
    /* Operations tools: header menu (hung on <body>, positioned from the button)
       and the read-only drawer it opens. Reuses .sheet / .ea-btn. */
    .hdr-ops{flex-shrink:0;white-space:nowrap}
    .ops-menu{
      position:fixed;z-index:110;min-width:240px;padding:4px;
      display:flex;flex-direction:column;gap:2px;
      background:var(--surface);border:1px solid var(--border);
      border-radius:var(--r-md);box-shadow:var(--sh-lg);
    }
    .ops-menu[hidden]{display:none}
    .ops-item{width:100%;justify-content:flex-start;text-align:start;border-color:transparent}
    .sheet.ops-sheet{width:min(720px,100%)}
    .ops-chips{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px}
    .ops-chip{font-size:var(--fs-100);padding:3px 10px;border-radius:999px;
      border:1px solid var(--border);color:var(--text-2)}
    .ops-chip b{color:var(--text)}
    .ops-table-wrap{overflow-x:auto}
    .ops-table{width:100%;border-collapse:collapse;font-size:var(--fs-100)}
    .ops-table th,.ops-table td{padding:6px 8px;border-bottom:1px solid var(--border-2);
      text-align:start;vertical-align:top;color:var(--text)}
    .ops-table th{color:var(--text-3);font-weight:600;white-space:nowrap}
    .ops-msg{color:var(--text-2);font-size:var(--fs-200);line-height:1.6;margin:0 0 10px}
    .ops-msg.is-err{color:var(--status-fail)}
    .ops-h{margin:16px 0 8px;font-size:var(--fs-200);color:var(--text)}

    /* ── Customer status ────────────────────────────────────────────────────
       Status as a filled pill rather than a coloured dot, following the
       reference admin view: at roster density a 7px dot is the same weak
       encoding the attention rows already moved away from. */
    .cs-pill{
      flex:none;font-size:var(--fs-100);font-weight:var(--fw-semi);line-height:1;
      padding:4px 8px;border-radius:999px;white-space:nowrap;
    }
    /* Text pulled 20% toward --text: --g on its own 12% tint measured 4.27:1. */
    .cs-pill.is-active  {background:color-mix(in srgb, var(--g) 12%, var(--surface));color:color-mix(in srgb, var(--g) 80%, var(--text))}
    .cs-pill.is-setup   {background:var(--status-warn-bg);color:color-mix(in srgb, var(--o) 80%, var(--text))}
    .cs-pill.is-archived{background:var(--surface-2);color:var(--text-3)}
    /* repeat(3,1fr), not minmax(0,1fr), was the one surviving instance of the
       exact pattern documented above as the cause of 113px of horizontal
       scroll. Here it never showed as scroll because #content-wrap clips
       overflow-x — so the third tile was silently CUT OFF rather than
       reachable, which is the worse of the two failures. */
    .cs-tiles{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin-bottom:12px}
    .cs-tile{
      background:var(--surface-2);border:1px solid var(--border);
      border-radius:var(--r-md);padding:10px 12px;min-width:0;
    }
    .cs-tile-v{font-size:var(--fs-400);font-weight:var(--fw-bold);color:var(--text);line-height:1.1}
    .cs-tile.is-active .cs-tile-v{color:var(--g)}
    .cs-tile.is-archived .cs-tile-v{color:var(--text-3)}
    .cs-tile-l{font-size:var(--fs-100);color:var(--text-3);margin-top:4px}
    .cs-rows{display:flex;flex-direction:column}
    .cs-row{
      display:flex;align-items:center;gap:8px;width:100%;
      padding:8px 4px;border:0;border-top:1px solid var(--border);
      background:none;cursor:pointer;text-align:start;font-family:inherit;
      font-size:var(--fs-200);color:var(--text);
      transition:background var(--dur-fast) var(--ease-out);
    }
    .cs-row:first-child{border-top:0}
    .cs-row:hover{background:var(--surface-2)}
    .cs-row.is-current{font-weight:var(--fw-semi)}
    .cs-dot{width:8px;height:8px;border-radius:50%;flex:none}
    .cs-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
    /* Marks a row whose precise state was never checked, so an unverified
       "active" cannot be mistaken for a verified one. */
    .cs-unver{color:var(--text-3);font-size:var(--fs-200);line-height:1;flex:none}
    .cs-more{font-size:var(--fs-100);color:var(--text-3);padding-top:8px}
    .cs-note{
      font-size:var(--fs-100);color:var(--text-3);line-height:1.5;
      margin-top:10px;padding-top:8px;border-top:1px solid var(--border);
    }

    /* Readable data rows — replaces the raw JSON <pre> dumps that used to
       render vault objects as braces and quotes. Key column is fixed and
       muted so the eye runs down the values, not the field names. */
    .rf { display: flex; flex-direction: column; }
    .rf-row {
      display: grid; grid-template-columns: minmax(90px, 22%) 1fr;
      gap: var(--sp-3); align-items: baseline;
      padding: 6px 0; border-top: 1px solid var(--border);
    }
    .rf-row:first-child { border-top: 0; }
    .rf-key {
      font-size: var(--fs-100); font-weight: var(--fw-semi);
      color: var(--text-3); line-height: 1.5;
      overflow-wrap: anywhere;
    }
    .rf-val {
      font-size: var(--fs-200); color: var(--text); line-height: 1.55;
      min-width: 0; overflow-wrap: anywhere;
    }
    /* Nested rows indent by their own border rather than padding, so depth is
       legible without the row losing its left edge. */
    .rf-val .rf-row { padding-inline-start: var(--sp-3); }
    .rf-empty { color: var(--text-3); }
    .rf-pills { display: flex; flex-wrap: wrap; gap: 4px; }
    /* Escape hatch: closed by default, monospace only once opened. */
    .rf-raw { margin-top: var(--sp-2); }
    .rf-raw > summary {
      cursor: pointer; font-size: var(--fs-100); color: var(--text-3);
      user-select: none; padding: 3px 0;
    }
    .rf-raw > summary:hover { color: var(--accent); }
    .rf-raw > pre {
      margin: var(--sp-2) 0 0; padding: 10px;
      background: var(--surface-2); border: 1px solid var(--border);
      border-radius: var(--r-sm);
      font-size: var(--fs-100); line-height: 1.5; color: var(--text-2);
      white-space: pre-wrap; overflow-wrap: anywhere;
      max-height: 240px; overflow-y: auto;
    }
    /* Trend line. Full tile width, sitting between the value and its caption —
       NN/g ranks length and 2D position as the fastest-read encodings, and this
       buys both for 24px of height. `preserveAspectRatio="none"` on the svg is
       what lets one 100×24 viewBox stretch to whatever the grid gives it. */
    .spark {
      display: block; width: 100%; height: 24px;
      margin-top: 8px; overflow: visible;
    }
    .kpi.is-empty .spark { opacity: .35; }
    /* Delta colours here are COST semantics, not growth semantics: spending
       more is amber, spending less is green. Do not reuse this pairing on a
       revenue or traffic tile without inverting it — there, up is the good
       direction. Flat stays muted so only real movement draws the eye. */
    .kpi-delta {
      font-size: var(--fs-100); font-weight: var(--fw-semi);
      font-variant-numeric: tabular-nums; white-space: nowrap;
    }
    .kpi-delta.is-up   { color: var(--o); }
    .kpi-delta.is-down { color: var(--g); }
    .kpi-delta.is-flat { color: var(--text-3); }
    /* A state word, not a measurement — it must not wear the numeral's size,
       and it never needs tabular figures. */
    .kpi-num.kpi-state { font-size: var(--fs-400); letter-spacing: -.01em; }
    .kpi-num.kpi-state.is-run  { color: var(--accent); }
    .kpi-num.kpi-state.is-idle { color: var(--text-2); }
    /* Label and icon chip share the top line, label first so the tile still
       reads label-then-value; the chip is an anchor to find the tile by, not
       something to read. */
    .kpi-top { display: flex; align-items: flex-start; gap: var(--sp-2); }
    .kpi-lbl {
      font-size: var(--fs-100); font-weight: 600;
      letter-spacing: .07em; text-transform: uppercase;
      color: var(--text-3); flex: 1; min-width: 0;
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    /* Two KPI tiles per row on a phone leave the label ~84px beside its icon
       chip; "שלבים שהושלמו" measured 93px and read "שלבים שהוש…". Wrap
       instead of cutting a two-word label in half. */
    @media (max-width: 768px) { .kpi-lbl { white-space: normal; } }
    /* Soft-tinted square, one hue per measurement. Decoration only — it is
       aria-hidden and asserts nothing, which is why every tile can carry one
       while only the cost tile earns a delta. */
    .kpi-ico {
      flex: none; width: 28px; height: 28px; border-radius: 8px;
      display: inline-flex; align-items: center; justify-content: center;
      margin-block-start: -2px;
    }
    .kpi-ico svg { width: 16px; height: 16px; display: block; }
    .kpi-ico--content  { color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
    .kpi-ico--stages   { color: var(--g);      background: color-mix(in srgb, var(--g) 12%, transparent); }
    .kpi-ico--cost     { color: var(--o);      background: color-mix(in srgb, var(--o) 14%, transparent); }
    .kpi-ico--pipeline { color: var(--p);      background: color-mix(in srgb, var(--p) 12%, transparent); }
    .kpi-ico--clients  { color: var(--viz-2);  background: color-mix(in srgb, var(--viz-2) 12%, transparent); }
    .kpi-ico--tokens   { color: var(--viz-4);  background: color-mix(in srgb, var(--viz-4) 12%, transparent); }
    /* An empty tile's chip recedes with the rest of it. */
    .kpi.is-empty .kpi-ico { opacity: .45; }
    .kpi-row {
      display: flex; align-items: baseline; gap: 8px;
      margin-top: 8px; min-width: 0;
    }
    /* The denominator is context, not a second measurement — it should not read
       at the same weight as the value it qualifies. */
    .kpi-of {
      font-size: var(--fs-300); font-weight: 600; color: var(--text-3);
      font-variant-numeric: tabular-nums;
    }
    /* Keeps the value and its denominator as one LTR run inside the RTL page. */
    .kpi-frac { display: inline-flex; align-items: baseline; }
    .kpi-sub {
      font-size: var(--fs-100); color: var(--text-3); margin-top: 5px;
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }

    /* KPI number */
    .kpi-num {
      font-size: var(--fs-500);
      font-weight: var(--fw-bold);
      line-height: var(--lh-500);
      letter-spacing: var(--tracking-tight);
      color: var(--text);
      /* Was the only font-family in the file not leading with Rubik — every
         other rule (9 of them) uses 'Rubik', sans-serif. No comment or reason
         explained why the KPI numbers specifically needed Inter, and Rubik
         already renders every other number on this dashboard. Consistency
         fix, not a redesign. */
      font-family: 'Rubik', sans-serif;
      font-variant-numeric: tabular-nums;
    }

    /* Run button */
    .btn-run {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 7px 14px;
      background: var(--accent);
      color: var(--on-accent);
      border-radius: 7px;
      font-size: var(--fs-200);
      font-weight: 600;
      border: none;
      cursor: pointer;
      transition:opacity var(--dur-base) ease;
      white-space: nowrap;
    }

    .btn-run:hover { opacity: 0.85; }

    .btn-run.loading {
      opacity: 0.6;
      pointer-events: none;
    }

    /* Client selector */
    .client-btn {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 7px 10px;
      border-radius: 7px;
      background: var(--surface-2);
      border: 1px solid var(--border);
      font-size: var(--fs-200);
      font-weight: 500;
      color: var(--text);
      cursor: pointer;
      width: 100%;
      transition:background var(--dur-fast) ease;
    }

    .client-btn:hover {
      background: var(--surface-2);
    }

    .client-dropdown {
      position: absolute;
      top: calc(100% + 4px);
      left: 0;
      right: 0;
      background: var(--surface-2);
      border: 1px solid var(--border);
      border-radius: var(--r-md);
      overflow: hidden;
      /* Was 0 8px 24px rgba(0,0,0,.5) — a hairline plus a heavy diffuse black
         shadow at once, and a dark-theme alpha that reads as a smudge on white.
         One elevation, ink-tinted, matching every other floating surface. */
      box-shadow: var(--sh-lg);
      z-index: var(--z-dropdown);
      /* Anchored to its trigger (the client selector button right above it),
         so it scales from there, not from the viewport center — same
         reasoning as every other trigger-anchored popover, modals excepted. */
      transform-origin: top center;
      opacity: 1;
      transform: scale(1) translateY(0);
      transition:opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out), visibility var(--dur-base) var(--ease-out);
    }
    /* Overrides the generic .hidden{display:none} (dashboard.js toggles that
       same shared class) with the opacity/visibility pattern .sheet-back
       already uses below — display:none can't transition at all, which is
       why this dropdown used to just snap open/closed with no animation. */
    .client-dropdown.hidden {
      display: block;
      opacity: 0;
      visibility: hidden;
      transform: scale(0.96) translateY(-4px);
      pointer-events: none;
      transition:opacity var(--dur-fast) ease, transform var(--dur-fast) ease, visibility var(--dur-fast) var(--ease-out);
    }

    .client-opt {
      display: flex;
      align-items: center;
      gap: 8px;
      padding: 9px 12px;
      font-size: var(--fs-200);
      cursor: pointer;
      color: var(--text-2);
      transition:background var(--dur-fast) ease;
    }

    .client-opt:hover {
      background: var(--surface-2);
    }

    .client-opt.active {
      color: var(--accent);
    }

    /* Tab panels */
    .tab-panel { display: block; }
    .tab-panel.hidden { display: none; }
    /* showTab() hides every panel then unhides the target — a hard display
       cut with nothing in between, so every switch read as a jump-cut. The
       panel still gets its real content from renderCurrentTab() right after
       becoming visible; this only softens the container's own arrival, not
       a page transition — no exit animation to match (switches happen often
       enough that an exit fade would just add latency nobody asked for; see
       ea-panel-in's duration note below).
       Distinct from ea-card-in (used by grids of many small cards): a panel
       is one large surface, so it gets a smaller rise and a shorter, faster
       duration — --dur-base (160ms) instead of --dur-slow, 4px instead of
       8px — a big translateY on something this tall reads as sluggish, not
       gentle. animation, not transition, for the same reason as ea-card-in:
       .hidden's removal is a display:none -> block flip, which only
       `animation` (not `transition`) plays on. */
    .tab-panel:not(.hidden) {
      animation: ea-panel-in var(--dur-base) var(--ease-out) both;
    }
    @keyframes ea-panel-in {
      from { opacity: 0; transform: translateY(4px); }
      to   { opacity: 1; transform: translateY(0); }
    }
    @media (prefers-reduced-motion: reduce) {
      .tab-panel:not(.hidden) { animation: none; }
    }

    /* ── Tailwind replacements ─────────────────────────────────────────────
       The Tailwind Play CDN has now been removed. These three elements were
       the ONLY things depending on it: #client-dropdown and #ob-result need a
       GENERIC .hidden (ours was scoped to .tab-panel and #onboard-modal only),
       and #modal took its whole geometry from `fixed inset-0 z-[100]`. There
       are 17 classList.toggle('hidden') call sites in dashboard.js. Defining
       them here first means removing the CDN later is a no-op instead of an
       outage that leaves the client dropdown and both modals stuck open.
       Source order beats .tab-panel{display:block} (same specificity);
       #modal.hidden beats #modal on specificity. No !important needed. */
    .hidden { display: none; }

    /* Spotlight search — was an inline style blob plus onfocus/onblur handlers
       painting neon mint (#00FFC2), the last live remnant of the deleted skin.
       :focus in CSS is what those handlers were emulating. */
    .spotlight-input {
      width: 100%; height: 36px;
      padding: 0 36px 0 12px;
      box-sizing: border-box;
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: 10px;
      color: var(--text);
      font-size: var(--fs-200);
      font-family: inherit;
      outline: none;
      transition:border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out);
    }
    .spotlight-input::placeholder { color: var(--text-3); }
    .spotlight-input:focus {
      border-color: var(--accent);
      box-shadow: 0 0 0 3px var(--accent-soft);
    }

    /* ── Media carousel — 3D coverflow ─────────────────────────────────────
       The media tab is the one surface where the artefact leads and the UI
       recedes: a client looking at their own photos wants the photo, not a
       grid of 155px squares. Real CSS 3D (perspective + rotateY on a
       preserve-3d rail), so depth is genuine rather than a scale trick.

       --mc-dir carries the reading direction. In RTL "next" runs the other
       way, and a carousel that ignores that feels backwards to a Hebrew
       reader on every single interaction. */
    .mc {
      --mc-dir: 1;
      position: relative;
      display: grid;
      grid-template-rows: 1fr auto;
      gap: var(--sp-5);
      min-height: 380px;
      padding: var(--sp-6) 0 0;
      user-select: none;
    }
    html[dir="rtl"] .mc { --mc-dir: -1; }

    .mc-stage {
      position: relative;
      height: 320px;
      perspective: 1400px;
      perspective-origin: 50% 45%;
      overflow: hidden;
      touch-action: pan-y;
      cursor: grab;
    }
    .mc-stage:active { cursor: grabbing; }
    .mc-rail {
      position: absolute;
      inset: 0;
      transform-style: preserve-3d;
    }

    .mc-slide {
      position: absolute;
      top: 50%;
      left: 50%;
      width: 260px;
      height: 260px;
      margin: -130px 0 0 -130px;
      border-radius: var(--r-lg);
      overflow: hidden;
      background: var(--surface-3);
      border: 1px solid var(--border);
      box-shadow: var(--sh-md);
      transform-style: preserve-3d;
      /* Exponential ease-out from an already-visible default: the slide never
         fades in from nothing, it settles. */
      transition:transform var(--dur-slow) var(--ease-out), opacity var(--dur-slow) var(--ease-out), filter var(--dur-slow) var(--ease-out), box-shadow var(--dur-slow) var(--ease-out);
      will-change: transform;
    }
    .mc-slide img {
      width: 100%; height: 100%;
      object-fit: cover;
      display: block;
      pointer-events: none;
    }
    .mc-slide.is-active {
      box-shadow: var(--sh-lg);
      border-color: var(--border-strong);
    }
    /* Off-centre slides recede: pushed back, dimmed and softened so the eye
       has exactly one place to land. */
    .mc-slide:not(.is-active) { filter: saturate(.75) brightness(.94); }
    .mc-slide:not(.is-active):hover { filter: none; }

    .mc-cap {
      position: absolute;
      inset-inline: 0; bottom: 0;
      padding: var(--sp-5) var(--sp-3) var(--sp-3);
      background: linear-gradient(transparent, rgba(10,37,64,.78));
      color: var(--on-accent);
      font-size: var(--fs-100);
      line-height: var(--lh-100);
      opacity: 0;
      transition:opacity var(--dur-base) var(--ease-out);
    }
    .mc-slide.is-active .mc-cap { opacity: 1; }

    .mc-bar {
      display: flex; align-items: center; justify-content: center;
      gap: var(--sp-3);
    }
    .mc-nav {
      width: 40px; height: 40px;
      display: inline-flex; align-items: center; justify-content: center;
      border-radius: var(--r-full);
      border: 1px solid var(--border);
      background: var(--surface);
      color: var(--text-2);
      cursor: pointer;
      box-shadow: var(--sh-xs);
      transition:background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
    }
    .mc-nav:hover { background: var(--surface-2); color: var(--text); border-color: var(--border-strong); }
    .mc-nav:focus-visible { outline: none; box-shadow: var(--sh-focus); }
    .mc-nav svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
    /* One arrow glyph, mirrored for the other direction and again for RTL —
       so the icon always points the way the rail will actually move. */
    .mc-nav[data-dir="next"] svg { transform: scaleX(calc(-1 * var(--mc-dir))); }
    .mc-nav[data-dir="prev"] svg { transform: scaleX(var(--mc-dir)); }

    .mc-count {
      min-width: 66px; text-align: center;
      font-size: var(--fs-200);
      font-variant-numeric: tabular-nums;
      color: var(--text-3);
      /* "4 / 7" is a ratio, not a sentence. Inheriting the page's RTL flipped
         it to "7 / 4" on screen — the position and the total swapped places.
         Numbers, IDs and ratios stay LTR inside an RTL document. */
      direction: ltr;
    }
    /* The dot paints at 6px; the button around it is 24px (WCAG 2.2 target
       size). It was a 6x6 button with a 6px gap — a click 4px off missed.
       Gap 0 keeps the centres 24px apart, so neighbours never overlap. */
    .mc-dots { display: flex; gap: 0; align-items: center; }
    .mc-dot {
      position: relative; width: 24px; height: 24px; padding: 0;
      border-radius: var(--r-full);
      border: 0; cursor: pointer; background: transparent;
    }
    .mc-dot::before {
      content: ''; position: absolute; left: 50%; top: 50%;
      width: 6px; height: 6px; margin: -3px 0 0 -3px;
      border-radius: var(--r-full); background: var(--border-strong);
      transition:background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
    }
    .mc-dot:hover::before { background: var(--text-3); }
    .mc-dot.is-active::before { background: var(--accent); transform: scale(1.5); }
    .mc-dot:focus-visible { outline: none; box-shadow: var(--sh-focus); }
    /* Ten 24px dots plus the arrows and the counter do not fit a phone; there
       the arrows, the "n / total" counter and swipe carry the navigation. */
    @media (max-width: 480px) { .mc-dots { display: none; } }

    @media (max-width: 640px) {
      .mc-stage { height: 250px; }
      .mc-slide { width: 190px; height: 190px; margin: -95px 0 0 -95px; }
    }
    /* Reduced motion: the depth stays (it is information about position), the
       travel does not. */
    @media (prefers-reduced-motion: reduce) {
      .mc-slide { transition:none; }
      .mc-cap   { transition:none; }
    }

    /* ── Scroll reveal + hover motion ──────────────────────────────────────
       Asaf, 2026-08-05. Library cards and media thumbnails had a border-color
       swap on hover and nothing on scroll. .reveal-up is applied server-side
       (in the template string) and .is-visible is toggled by an
       IntersectionObserver in dashboard.js (initScrollReveal()) the first time
       each card enters the viewport -- CSS alone cannot know when that is.
       One JS class name, not sixty inline onmouseenter handlers: the existing
       .media-thumb hover already moved inline style properties directly,
       which means every thumbnail pays the cost of an inline style mutation
       on every hover. A class toggle lets the browser's own style engine and
       GPU compositing handle it instead. */
    /* One transition declaration for both effects, on the same selector list —
       not two separate rules that happen to both touch `transform`. The
       `transition` shorthand is a single cascaded property: a later rule
       setting `transition: transform .2s, box-shadow .2s, border-color .2s`
       does not MERGE with an earlier `transition: opacity .5s, transform .5s`
       on the same element, it REPLACES transition-property's whole list —
       found live: opacity silently lost its transition entirely, so the
       reveal would slide smoothly and pop into opacity instantly instead of
       fading. One rule, four properties, each with the duration that fits it:
       opacity/transform slow enough to read as an arrival (the reveal),
       box-shadow/border-color quick enough to read as feedback (the hover). */
    .lib-card, .media-thumb {
      transition:opacity .5s var(--ease-out, ease), transform .5s var(--ease-out, ease), box-shadow var(--dur-base) var(--ease-out, ease), border-color var(--dur-base) var(--ease-out, ease);
    }
    .reveal-up { opacity: 0; transform: translateY(18px); }
    .reveal-up.is-visible { opacity: 1; transform: translateY(0); }
    .lib-card:hover {
      transform: translateY(-3px);
      box-shadow: var(--sh-md, 0 4px 14px rgba(0,0,0,.10));
      border-color: var(--border-strong);
    }
    .media-thumb:hover {
      transform: translateY(-3px) scale(1.03);
      box-shadow: var(--sh-lg, 0 8px 22px rgba(0,0,0,.16));
    }

    @media (prefers-reduced-motion: reduce) {
      .reveal-up { opacity: 1; transform: none; transition:none; }
      .lib-card, .media-thumb { transition:none; }
      .lib-card:hover, .media-thumb:hover { transform: none; }
    }

    /* ── Social post preview ───────────────────────────────────────────────
       Shows each generated caption inside the frame it will actually live in.
       A caption approved as a paragraph in a table reads completely differently
       once it is 320px wide under a photo with the hashtags pushed below the
       fold — which is the only place the client will ever see it.

       These are structural imitations (aspect ratio, chrome, truncation), not
       reproductions of anyone's logo or UI. The platform is named in words. */
    .sp-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
      gap: var(--sp-6);
    }
    .sp-post {
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: var(--r-lg);
      box-shadow: var(--sh-xs);
      overflow: hidden;
      display: flex; flex-direction: column;
      transition:box-shadow var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
    }
    .sp-post:hover { box-shadow: var(--sh-sm); border-color: var(--border-strong); }

    /* Each platform gets one accent, carried on a 2px top rule rather than a
       coloured side border — a thick left border on a card is the tell of a
       template, and the top rule reads as a tab instead. */
    .sp-post[data-p="instagram"]      { --sp-accent: #c13584; }
    .sp-post[data-p="facebook"]       { --sp-accent: #1877f2; }
    .sp-post[data-p="tiktok"]         { --sp-accent: #0a2540; }
    .sp-post[data-p="google_business"]{ --sp-accent: #1a73e8; }
    .sp-post::before {
      content: ''; display: block; height: 2px;
      background: var(--sp-accent, var(--accent));
    }

    .sp-hd {
      display: flex; align-items: center; gap: var(--sp-2);
      padding: var(--sp-3);
      border-bottom: 1px solid var(--border);
    }
    .sp-av {
      width: 30px; height: 30px; flex: 0 0 30px;
      border-radius: var(--r-full);
      background: var(--sp-accent, var(--accent));
      /* #fff, not --on-accent: the fill is a fixed brand hex in both themes,
         and --on-accent turns to ink in dark mode — "TT" on TikTok navy
         measured 1.17:1 there. */
      color: #fff;
      display: flex; align-items: center; justify-content: center;
      font-size: var(--fs-100); font-weight: var(--fw-bold);
    }
    .sp-who { min-width: 0; }
    .sp-name {
      font-size: var(--fs-200); font-weight: var(--fw-semi); color: var(--text);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .sp-plat {
      font-size: var(--fs-100); color: var(--text-3);
      text-transform: uppercase; letter-spacing: var(--tracking-caps);
    }

    /* The frame is the point: Instagram is square, TikTok is 9:16, Facebook is
       landscape. The same caption sits very differently in each. */
    .sp-media { background: var(--surface-3); overflow: hidden; }
    .sp-post[data-p="instagram"]       .sp-media { aspect-ratio: 1/1; }
    .sp-post[data-p="tiktok"]          .sp-media { aspect-ratio: 9/16; max-height: 420px; }
    .sp-post[data-p="facebook"]        .sp-media { aspect-ratio: 1.91/1; }
    .sp-post[data-p="google_business"] .sp-media { aspect-ratio: 4/3; }
    .sp-media img { width: 100%; height: 100%; object-fit: cover; display: block; }

    .sp-body { padding: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); flex: 1; }
    .sp-hook {
      font-size: var(--fs-200); font-weight: var(--fw-semi);
      line-height: var(--lh-200); color: var(--text);
    }
    .sp-text {
      font-size: var(--fs-200); line-height: 1.65; color: var(--text-2);
      /* Platforms clamp long captions behind a "more" affordance. Showing the
         full body here would hide the one thing worth reviewing: whether the
         hook survives truncation. */
      display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
      overflow: hidden;
    }
    .sp-post.is-open .sp-text { -webkit-line-clamp: unset; display: block; }
    .sp-more {
      align-self: flex-start;
      background: none; border: 0; padding: 0; cursor: pointer;
      font: inherit; font-size: var(--fs-200);
      color: var(--accent);
    }
    .sp-more:focus-visible { outline: none; box-shadow: var(--sh-focus); border-radius: var(--r-xs); }
    .sp-cta {
      font-size: var(--fs-200); font-weight: var(--fw-semi);
      color: var(--sp-accent, var(--accent));
    }
    .sp-tags { font-size: var(--fs-100); color: var(--text-3); line-height: 1.7; word-break: break-word; }
    .sp-foot {
      display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
      padding: var(--sp-2) var(--sp-3);
      border-top: 1px solid var(--border);
      background: var(--surface-2);
      font-size: var(--fs-100); color: var(--text-3);
    }

    /* Schedule board */
    .sp-weeks { display: flex; flex-direction: column; gap: var(--sp-4); }
    .sp-week-hd {
      display: flex; align-items: baseline; gap: var(--sp-2);
      font-size: var(--fs-100); font-weight: var(--fw-bold);
      text-transform: uppercase; letter-spacing: var(--tracking-caps);
      color: var(--text-3);
    }
    .sp-week-line { flex: 1; height: 1px; background: var(--border); }
    .sp-slots { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
    .sp-slot {
      display: inline-flex; align-items: center; gap: 6px;
      padding: 6px var(--sp-3);
      border-radius: var(--r-full);
      border: 1px solid var(--border);
      background: var(--surface);
      font-size: var(--fs-100); color: var(--text-2);
      cursor: pointer;
      transition:border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
    }
    .sp-slot:hover { border-color: var(--border-strong); background: var(--surface-2); }
    .sp-slot:focus-visible { outline: none; box-shadow: var(--sh-focus); }
    .sp-slot i {
      width: 7px; height: 7px; border-radius: var(--r-full);
      background: var(--sp-accent, var(--accent)); display: inline-block;
    }

    /* ── Pro dashboard (layout-premium) ────────────────────────────────────
       Built into the `premium` view mode, which had a button in the topbar and
       styled nothing — every selector its old rules targeted (.card,
       .card-title, .section-label, .stat-big) had zero real usages, so clicking
       it did nothing at all. Now it is the analytical view: same data as the
       standard overview, read for trend and outlier rather than current value.

       Charts are hand-rolled SVG. There is no build step here and no chart
       library is loaded on this page; adding one to draw four small charts
       would cost more than it returns. */
    .pro-grid { display: grid; gap: var(--sp-6); }
    @media (min-width: 1024px) { .pro-grid { grid-template-columns: repeat(2, minmax(0,1fr)); } }
    .pro-wide { grid-column: 1 / -1; }

    .pro-sec { border: 1px solid var(--border); border-radius: var(--r-lg);
               background: var(--surface); box-shadow: var(--sh-xs); overflow: hidden; }
    .pro-hd {
      display: flex; align-items: center; gap: var(--sp-2);
      width: 100%; padding: var(--sp-4) var(--sp-5);
      background: none; border: 0; cursor: pointer;
      font: inherit; font-size: var(--fs-200); font-weight: var(--fw-semi);
      color: var(--text); text-align: start;
    }
    .pro-hd:hover { background: var(--surface-2); }
    .pro-hd:focus-visible { outline: none; box-shadow: var(--sh-focus); }
    .pro-hd .pro-caret {
      margin-inline-start: auto; color: var(--text-3);
      transition:transform var(--dur-base) var(--ease-out);
    }
    .pro-sec.is-collapsed .pro-caret { transform: rotate(-90deg); }
    .pro-sec.is-collapsed .pro-bd { display: none; }
    .pro-bd { padding: 0 var(--sp-5) var(--sp-5); }
    .pro-note { font-size: var(--fs-100); color: var(--text-3); line-height: 1.7; }

    /* Charts read left-to-right regardless of page direction — a time axis
       that mirrors with the UI is a misread waiting to happen. */
    .pro-chart { direction: ltr; width: 100%; overflow: visible; }
    .pro-chart .axis  { stroke: var(--border); stroke-width: 1; }
    .pro-chart .grid  { stroke: var(--border); stroke-width: 1; stroke-dasharray: 2 3; opacity: .7; }
    .pro-chart .lbl   { fill: var(--text-3); font-size: 11px; font-family: inherit; }
    .pro-chart .bar   { fill: var(--accent); }
    .pro-chart .bar:hover { fill: var(--accent-hover); }
    .pro-chart .area  { fill: var(--accent); opacity: .12; }
    .pro-chart .line  { fill: none; stroke: var(--accent); stroke-width: 2;
                        stroke-linejoin: round; stroke-linecap: round; }
    .pro-chart .dot   { fill: var(--surface); stroke: var(--accent); stroke-width: 2; }

    /* ── Reports tab — modern responsive grid ──────────────────────────────
       Same auto-fill/minmax rhythm as .dna-grid (established pattern), so
       the Reports tab reads like one system, not a one-off redesign. */
    .report-grid {
      display: grid; gap: var(--sp-4);
      grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
      align-items: start;
    }
    .report-card { margin-bottom: 0; }
    .report-card-wide { grid-column: 1 / -1; }
    .report-card.ea-card {
      animation: ea-card-in var(--dur-slow) var(--ease-out) both;
    }
    @media (hover: hover) {
      .report-card.ea-card:hover { border-color: var(--border-strong); box-shadow: var(--sh-sm); }
    }
    .report-grid > .report-card:nth-child(1) { animation-delay: 0ms; }
    .report-grid > .report-card:nth-child(2) { animation-delay: 45ms; }
    .report-grid > .report-card:nth-child(3) { animation-delay: 90ms; }
    .report-grid > .report-card:nth-child(4) { animation-delay: 135ms; }
    @media (prefers-reduced-motion: reduce) {
      .report-card.ea-card { animation: none; }
    }
    .report-stat-row { display: flex; align-items: center; gap: 20px; flex-wrap: wrap; }

    /* Activity calendar (GitHub-style heatmap) — real per-day counts only;
       an all-empty window renders nothing (the caller skips it), never a
       grid of fake cells. */
    .ea-heatmap-wrap { display: flex; flex-direction: column; gap: 8px; overflow-x: auto; }
    .ea-heatmap rect { transition: opacity var(--dur-fast) var(--ease-out); }
    .ea-heatmap rect:hover { opacity: .72; }
    .ea-heatmap-legend {
      display: flex; align-items: center; gap: 4px; direction: ltr;
      font-size: 11px; color: var(--text-3);
    }
    .ea-heatmap-legend i { width: 10px; height: 10px; border-radius: 2.5px; display: inline-block; margin: 0 1px; }
    @media (prefers-reduced-motion: reduce) {
      .ea-heatmap rect { transition: none; }
    }

    /* Sortable table */
    .pro-tbl { width: 100%; border-collapse: collapse; font-size: var(--fs-100); }
    .pro-tbl th {
      text-align: start; padding: var(--sp-2) var(--sp-3);
      border-bottom: 1px solid var(--border-strong);
      color: var(--text-2); font-weight: var(--fw-semi);
      cursor: pointer; user-select: none; white-space: nowrap;
    }
    .pro-tbl th:hover { color: var(--text); }
    .pro-tbl th[aria-sort] { color: var(--accent); }
    .pro-tbl th .sort-ind { opacity: .55; margin-inline-start: 4px; }
    .pro-tbl td { padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border); }
    .pro-tbl tbody tr:hover { background: var(--surface-2); }
    .pro-num { font-variant-numeric: tabular-nums; direction: ltr; text-align: end; }
    .pro-ok   { color: var(--status-done); }
    .pro-bad  { color: var(--status-fail); }
    .pro-warn { color: var(--status-warn); }

    /* Only the pro view; the standard overview keeps its own layout. */
    body:not(.layout-premium) #pro-dashboard { display: none; }
    body.layout-premium #overview-standard   { display: none; }

    /* ── Section launcher ──────────────────────────────────────────────────
       Every sidebar destination, on the main view. The point is not a second
       copy of the menu — it is that each card carries a live number from that
       area's own data, so the overview answers "where is there work" without
       opening anything. A launcher that only repeated the nav labels would be
       strictly worse than the nav itself. */
    /* ── Section launcher — a navigation strip, not a card grid ──────────────
       Was a grid of same-size icon + heading + number cards, wrapped in another
       card. Three problems: nested cards; the same-size-card grid as the page
       scaffold; and a number on every tile that competed with the KPI row right
       below it — "ספריית תוכן 8" against "פריטי תוכן 22", two counts of the same
       thing, disagreeing, with no way for a reader to tell which was true.

       It is a strip of text chips now, at the bottom of the page, because the
       sidebar already carries these twelve destinations permanently. A dot marks
       an area that is empty, which is the one thing the sidebar cannot say. */
    .sl-strip {
      display: flex; align-items: baseline; gap: var(--sp-4);
      flex-wrap: wrap;
      margin-top: var(--sp-8);
      padding-top: var(--sp-5);
      border-top: 1px solid var(--border);
    }
    .sl-strip-label {
      font-size: var(--fs-100); color: var(--text-3);
      letter-spacing: .04em; flex: none;
    }
    .sl-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); min-width: 0; }
    .sl-chip {
      display: inline-flex; align-items: center; gap: var(--sp-2);
      padding: 6px 11px;
      background: transparent;
      border: 1px solid var(--border);
      border-radius: var(--r-full);
      color: var(--text-2);
      font: inherit; font-size: var(--fs-100);
      cursor: pointer;
      transition:border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
    }
    .sl-chip:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
    .sl-chip:focus-visible { outline: none; box-shadow: var(--sh-focus); }
    .sl-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    /* An area with nothing in it. A dot, not a zero — a zero reads as a
       measurement, an absence is not one. */
    .sl-flag {
      width: 5px; height: 5px; border-radius: 50%;
      background: var(--text-3); flex: none;
    }
    .sl-chip.has-warn .sl-flag { background: var(--status-warn); }
    .sl-chip.has-fail .sl-flag { background: var(--status-fail); }
    .sl-chip.has-ok   .sl-flag { background: var(--status-done); }

    /* ── Attention block ─────────────────────────────────────────────────────
       The first thing on the page and the only one that reads for exceptions.
       Deliberately not a card: it is the page's opening statement, and putting
       it in the same container as everything else would flatten it back into
       the stack it exists to rise above. */
    .att-block {
      border: 1px solid var(--border-strong);
      border-radius: var(--r-lg);
      background: var(--surface);
      overflow: hidden;
      margin-bottom: var(--sp-6);
    }
    .att-head {
      display: flex; align-items: center; gap: var(--sp-3);
      padding: var(--sp-3) var(--sp-4);
      border-bottom: 1px solid var(--border);
    }
    .att-title { font-size: var(--fs-200); font-weight: var(--fw-semi); color: var(--text); }
    .att-count {
      font-size: var(--fs-100); font-weight: var(--fw-bold);
      padding: 1px 8px; border-radius: var(--r-full);
      background: var(--surface-2); color: var(--text-2);
      font-variant-numeric: tabular-nums;
    }
    .att-count.is-fail { background: var(--status-fail); color: #fff; }

    .att-row {
      /* flex-start, not center: the body is two lines now, and a centred icon
         against a two-line block floats between them instead of anchoring the
         title it belongs to. */
      width: 100%; display: flex; align-items: flex-start; gap: var(--sp-3);
      padding: var(--sp-3) var(--sp-4); position: relative;
      background: transparent; border: 0;
      border-top: 1px solid var(--border);
      font: inherit; text-align: start; cursor: pointer;
      transition:background var(--dur-fast) var(--ease-out);
    }
    .att-row:first-of-type { border-top: 0; }
    .att-row:hover { background: var(--surface-2); }
    .att-row:focus-visible { outline: none; box-shadow: var(--sh-focus); }
    /* Severity rides a tinted icon chip, the reference design's alert anatomy.
       It replaced a 7px dot (colour alone, smallest mark on the page carrying
       its most important distinction) and then a text chip. The word itself is
       not lost: it moved to .att-sev-sr below, which is read aloud but not
       drawn, so colour is still not the only carrier for a screen reader. */
    .att-ico {
      flex: none; width: 30px; height: 30px; border-radius: 9px;
      display: inline-flex; align-items: center; justify-content: center;
      margin-block-start: 1px;
    }
    .att-ico svg { width: 17px; height: 17px; display: block; }
    .att-row.is-warn .att-ico { color: var(--status-warn); background: var(--status-warn-bg); }
    .att-row.is-fail .att-ico { color: #fff; background: var(--status-fail); }
    /* Visually hidden, still announced. */
    .att-sev-sr {
      position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
      overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
    }
    /* A failure row carries a tinted ground so it separates from the warns
       above the fold, not just by its chip. --status-fail-bg was declared and
       never consumed. */
    .att-row.is-fail { background: var(--status-fail-bg); }
    .att-row.is-fail:hover { background: color-mix(in srgb, var(--status-fail) 14%, var(--surface)); }
    /* Finding and remedy stack instead of sharing one run at one weight. The
       remedy is the actionable half and used to truncate first. */
    .att-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
    .att-text {
      font-size: var(--fs-200); color: var(--text); font-weight: var(--fw-medium);
      line-height: 1.45; overflow-wrap: anywhere;
    }
    .att-action {
      font-size: var(--fs-100); color: var(--text-3); line-height: 1.5;
      min-width: 0; overflow-wrap: anywhere;
    }
    .att-go { color: var(--text-3); flex: none; transition:transform var(--dur-fast) var(--ease-out); }
    .att-row:hover .att-go { transform: translateX(-3px); color: var(--accent); }

    /* All-clear. Says what was checked, so "nothing here" reads as a result
       rather than as a component that failed to load. */
    .att-block.is-clear {
      display: flex; align-items: center; gap: var(--sp-3);
      padding: var(--sp-4) var(--sp-5);
      border-color: var(--border);
    }
    .att-clear-mark {
      width: 26px; height: 26px; flex: none;
      display: grid; place-items: center; border-radius: 50%;
      background: var(--status-done); color: #fff;
      font-size: var(--fs-100); font-weight: var(--fw-bold);
    }
    .att-clear-title { font-size: var(--fs-200); font-weight: var(--fw-semi); color: var(--text); }
    .att-clear-sub { font-size: var(--fs-100); color: var(--text-3); margin-top: 1px; }

    /* ── Collapsible overview block ──────────────────────────────────────── */
    .ov-fold > .ov-fold-sum,
    .pro-accordion > .ov-fold-sum {
      display: flex; align-items: center; justify-content: space-between;
      cursor: pointer; list-style: none;
    }
    .ov-fold > .ov-fold-sum::-webkit-details-marker,
    .pro-accordion > .ov-fold-sum::-webkit-details-marker { display: none; }
    .ov-fold > .ov-fold-sum:focus-visible,
    .pro-accordion > .ov-fold-sum:focus-visible { outline: none; box-shadow: var(--sh-focus); border-radius: var(--r-md); }
    .ov-fold-chev {
      color: var(--text-3); font-weight: var(--fw-bold); flex: none;
      transition:transform var(--dur-base) var(--ease-out);
    }
    [dir="rtl"] .ov-fold-chev { transform: rotate(180deg); }
    .ov-fold[open] .ov-fold-chev,
    [dir="rtl"] .ov-fold[open] .ov-fold-chev { transform: rotate(90deg); }
    .ov-fold[open] > .ov-fold-sum,
    .pro-accordion[open] > .ov-fold-sum { margin-bottom: var(--sp-3); }

    /* Pipeline-mode collapse: same behavior as .ov-fold, "+"/"−" glyph instead
       of a rotating chevron — pure CSS, no JS needed for the swap itself. */
    .pro-accordion-ind {
      display: inline-flex; align-items: center; justify-content: center;
      width: 20px; height: 20px; flex: none; border-radius: var(--r-full);
      border: 1px solid var(--border); color: var(--text-3);
      font-size: var(--fs-200); font-weight: var(--fw-bold); line-height: 1;
    }
    .pro-accordion-ind::before { content: '+'; }
    .pro-accordion[open] > .ov-fold-sum .pro-accordion-ind::before { content: '\2212'; }

    .theme-toggle {
      width: 28px; height: 28px;
      display: inline-flex; align-items: center; justify-content: center;
      border-radius: var(--r-full);
      border: 1px solid var(--border);
      background: var(--surface);
      color: var(--text-2);
      cursor: pointer;
      transition:background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
    }
    .theme-toggle:hover { background: var(--surface-2); color: var(--text); border-color: var(--border-strong); }
    .theme-toggle:focus-visible { outline: none; box-shadow: var(--sh-focus); }
    .theme-toggle svg { width: 14px; height: 14px; }

    /* Modal. Like .client-dropdown above, this used to be a bare
       display:flex <-> display:none toggle — no fade, no scale, just an
       instant snap in both directions. #modal-backdrop and #modal-inner
       below get the actual opacity/transform transition; this element only
       needs the display override so they have something to animate within. */
    #modal {
      position: fixed;
      inset: 0;
      z-index: 100;
      display: flex;
      align-items: center;
      justify-content: center;
      visibility: visible;
      transition:visibility var(--dur-base) var(--ease-out);
    }
    #modal.hidden { display: flex; visibility: hidden; pointer-events: none; }
    #modal.hidden #modal-backdrop,
    #modal.hidden #modal-inner { opacity: 0; }
    #modal.hidden #modal-inner { transform: scale(0.96); }

    /* ── Layout switcher (topbar) ──────────────────────────────────────────
       .view-btn was defined ONLY inside the deleted neon block, so it had no
       geometry anywhere else while being used at dashboard.js:817/827/829.
       Re-homed here; folded into the button system in a later phase. */
    .view-btn-group { display: inline-flex; gap: 4px; }
    .view-btn {
      width: 30px; height: 30px;
      display: inline-flex; align-items: center; justify-content: center;
      border-radius: 7px; cursor: pointer;
      border: 1px solid var(--border);
      background: var(--surface);
      color: var(--text-2);
      font-size: var(--fs-200);
      transition:background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
    }
    .view-btn:hover { background: var(--surface-2); color: var(--text); }
    .view-btn.active {
      background: var(--accent-soft);
      border-color: var(--accent);
      color: var(--accent);
    }

    #modal-backdrop {
      position: absolute;
      inset: 0;
      background: rgba(12, 18, 17, 0.55);
      opacity: 1;
      transition:opacity var(--dur-base) var(--ease-out);
    }

    #modal-inner {
      position: relative;
      z-index: 10;
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: 12px;
      width: 100%;
      max-width: min(860px, 96vw);
      max-height: 90vh;
      overflow: hidden;
      display: flex;
      flex-direction: column;
      /* Centered, not trigger-anchored — a modal isn't anchored to whatever
         button opened it, so unlike .client-dropdown this keeps the default
         center origin on purpose. */
      opacity: 1;
      transform: scale(1);
      transition:opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }

    #modal-header {
      display: flex;
      align-items: center;
      gap: 12px;
      padding: 16px 20px;
      border-bottom: 1px solid var(--border);
      flex-shrink: 0;
    }

    #modal-body {
      flex: 1;
      overflow-y: auto;
      padding: 16px 20px;
    }

    #modal-json {
      font-size: var(--fs-200);
      line-height: 1.6;
      color: var(--text-2);
    }

    #modal-footer {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 12px 20px;
      border-top: 1px solid var(--border);
      flex-shrink: 0;
    }

    #modal-title {
      font-size: var(--fs-200);
      font-weight: 600;
      color: var(--text);
    }

    #modal-sub {
      font-size: var(--fs-200);
      color: var(--text-3);
      margin-top: 2px;
    }

    #modal-timestamp {
      font-size: var(--fs-100);
      color: var(--text-3);
    }

    /* Animations */
    @keyframes spin {
      to { transform: rotate(360deg); }
    }

    .spin {
      animation: spin 0.8s linear infinite;
      display: inline-block;
    }

    @keyframes pulse-dot {
      0%, 100% { opacity: 1; }
      50% { opacity: 0.35; }
    }

    /* Table styles */
    .dash-table {
      width: 100%;
      border-collapse: collapse;
    }

    .dash-table th {
      font-size: var(--fs-100);
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.06em;
      color: var(--text-3);
      padding: 0 12px 10px;
      text-align: right;
      border-bottom: 1px solid var(--border);
    }

    .dash-table td {
      padding: 11px 12px;
      font-size: var(--fs-200);
      color: var(--text-2);
      border-bottom: 1px solid var(--border);
      vertical-align: middle;
    }

    .dash-table tr:last-child td {
      border-bottom: none;
    }

    .dash-table tbody tr:hover td {
      background: var(--surface-2);
    }

    /* ── Sortable headers ────────────────────────────────────────────────────
       The header cells became real controls (role=button, tabindex=0) in
       dashboard.js. These styles are what makes that visible: before, thirteen
       tables rendered 37 header cells that looked identical whether or not they
       did anything.

       cursor:pointer and the hover shift are the affordance. The focus ring is
       not optional — a th is not natively focusable, so nothing draws one for
       us, and a keyboard user tabbing through a table with no visible focus has
       no idea where they are. */
    .dash-table th[data-sortable="1"],
    .pro-tbl th[data-sortable="1"],
    .ea-table th[data-sortable="1"] {
      cursor: pointer;
      user-select: none;
      transition: color var(--dur-fast) var(--ease-out),
                  background var(--dur-fast) var(--ease-out);
    }

    .dash-table th[data-sortable="1"]:hover,
    .pro-tbl th[data-sortable="1"]:hover,
    .ea-table th[data-sortable="1"]:hover { color: var(--text) }

    .dash-table th[data-sortable="1"]:focus-visible,
    .pro-tbl th[data-sortable="1"]:focus-visible,
    .ea-table th[data-sortable="1"]:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: -2px;
      border-radius: 4px;
      color: var(--text);
    }

    /* The active column stays legible after the sort — otherwise the only
       signal that a sort happened is the row order, which is exactly what the
       reader is trying to interpret. */
    .dash-table th[aria-sort="ascending"],
    .dash-table th[aria-sort="descending"],
    .pro-tbl th[aria-sort="ascending"],
    .pro-tbl th[aria-sort="descending"] { color: var(--accent) }

    /* margin-inline-start, not margin-left: this page is RTL and a physical
       margin puts the arrow on the wrong side of the label. */
    .sort-ind {
      margin-inline-start: 4px;
      font-size: 11px;
      line-height: 1;
      opacity: .9;
    }

    /* Sticky header for long tables. The scroll container (.tbl-scroll) is what
       actually scrolls, so the header sticks to its top edge rather than the
       viewport's. background is required — a transparent sticky header lets
       rows slide visibly underneath the text. */
    .tbl-scroll { position: relative; max-height: 60vh; overflow: auto }
    .tbl-scroll .dash-table thead th,
    .tbl-scroll .pro-tbl thead th {
      position: sticky;
      top: 0;
      z-index: 1;
      background: var(--surface);
      padding-top: 10px;
    }

    /* A sortable header is a CONTROL, and on a touch screen it has to clear the
       same 44px floor as every other one. Measured at 390px with the real token
       sheet loaded: 37.5px. The header's padding is tuned for a LABEL, which is
       all it was until the sort landed and made all 37 of them tappable.

       Raised for fingers, not for width: a mouse hits 37px exactly as well as
       44px, and growing every header on a desktop costs a row of data per
       screen for nothing. `(pointer:coarse), (max-width:768px)` is the pair
       this file already uses for that reason — the width half catches a
       phone-sized window reporting a fine pointer, which is what a desktop
       browser's device emulation does.

       PLACED AFTER THE STICKY RULE, AND SCOPED TO IT AS WELL. `.tbl-scroll
       .dash-table thead th` sets padding-top:10px at two-class specificity;
       an earlier, less specific block lost the top padding to it silently and
       measured 42.5px — the box looked almost right, which is the worst way to
       be wrong. Both selectors are listed rather than relying on order alone. */
    @media (pointer: coarse), (max-width: 768px) {
      .dash-table th[data-sortable="1"],
      .pro-tbl th[data-sortable="1"],
      .ea-table th[data-sortable="1"],
      .tbl-scroll .dash-table thead th[data-sortable="1"],
      .tbl-scroll .pro-tbl thead th[data-sortable="1"] {
        /* Not min-height: a <th> is a table cell, and min-height on a cell is
           advisory in every engine, so the box is built from padding and an
           explicit line box — 12 + 20 + 12 = 44 — rather than padding fitted
           around whatever line-height happens to be inherited. A sortable
           header carries an indicator span, so its content box is not the same
           height as a plain one's, and two attempts at fitting landed at
           40.5px and 42.5px before this. */
        padding-block: 12px;
        line-height: 20px;
      }
    }


    /* Numeric columns line up on the decimal only with tabular figures;
       proportional digits make a column of numbers ragged and hard to compare. */
    .dash-table td.num, .pro-tbl td.pro-num, .ea-table td.num {
      font-variant-numeric: tabular-nums;
      text-align: start;
    }

    /* ── Client editor groups ────────────────────────────────────────────────
       Nineteen inputs in one flat column is a form nobody finishes. The group
       heading is the only chrome added: it costs one line and turns a wall of
       fields into five short scannable sections. */
    .f-group { margin-bottom: var(--sp-4) }
    .f-group-t {
      font-size: var(--fs-100);
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: .06em;
      color: var(--text-3);
      padding-bottom: var(--sp-2);
      margin-bottom: var(--sp-2);
      border-bottom: 1px solid var(--border);
    }
    /* The sheet is reachable on a phone, so its inputs carry the touch floor.
       A 32px input inside a 44px-everywhere product is the kind of
       inconsistency that reads as unfinished. */
    .f-row input { min-height: 44px }

    /* ── Table toolbar ───────────────────────────────────────────────────────
       Filter + CSV export, above any table with enough rows to need them.
       Logical properties throughout: this page is RTL, and a physical
       margin/padding here puts the controls on the wrong edge. */
    .tbl-tools {
      display: flex;
      align-items: center;
      gap: var(--sp-2);
      margin-bottom: var(--sp-2);
      flex-wrap: wrap;
    }
    .tbl-filter {
      flex: 1 1 180px;
      min-width: 0;
      min-height: 36px;
      padding: 0 var(--sp-3);
      font-size: var(--fs-200);
      color: var(--text);
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: 8px;
    }
    .tbl-filter:focus-visible {
      outline: 2px solid var(--accent);
      outline-offset: -1px;
      border-color: transparent;
    }
    .tbl-count {
      font-size: var(--fs-100);
      color: var(--text-3);
      font-variant-numeric: tabular-nums;
      white-space: nowrap;
    }
    .tbl-export {
      min-height: 36px;
      padding: 0 var(--sp-3);
      font-size: var(--fs-100);
      font-weight: 600;
      color: var(--text-2);
      background: transparent;
      border: 1px solid var(--border);
      border-radius: 8px;
      cursor: pointer;
      white-space: nowrap;
      transition: color var(--dur-fast) var(--ease-out),
                  border-color var(--dur-fast) var(--ease-out);
    }
    .tbl-export:hover { color: var(--accent); border-color: var(--accent) }
    .tbl-export:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px }

    /* On a phone the input takes the row and the two small controls share the
       next one, rather than three items competing for 343px. Both controls keep
       the 44px touch floor here; 36px is a pointer-only size. */
    @media (max-width: 640px) {
      .tbl-filter { flex: 1 1 100% }
      .tbl-filter, .tbl-export { min-height: 44px }
    }

    /* Visually hidden but announced. Used by the sort live-region: a screen
       reader needs to be told the table reordered; aria-sort marks which column
       is sorted, it does not say that anything moved. */
    .sr-only {
      position: absolute;
      width: 1px; height: 1px;
      padding: 0; margin: -1px;
      overflow: hidden;
      clip-path: inset(50%);
      white-space: nowrap;
      border: 0;
    }

    /* Agent row */
    .agent-row {
      display: flex;
      align-items: center;
      gap: 10px;
      padding: 10px 0;
      border-top: 1px solid var(--border);
    }

    .agent-row:first-child {
      border-top: none;
    }

    /* Code block */
    /* Grid items default to min-width:auto, so a track floors at its content's
       min-content width and the page scrolls sideways. The desktop rules already
       use minmax(0,1fr); the mobile overrides did not, which is what pushed the
       content/clients/media tabs past the viewport at 375px. These three carry
       the widest content on those tabs. */
    .ea-card, .cl-card, .mc-stage { min-width: 0; }

    /* A locked tile must not read as a low number. Same size as the numeral it
       replaces so the grid does not reflow, but muted — it is the absence of a
       reading, not a reading of zero. */
    .kpi-num--locked {
      opacity: .55;
      filter: grayscale(1);
      cursor: help;
    }

    /* Auth-failure banner. Fixed and loud on purpose: every panel behind it is
       showing an empty state it cannot actually vouch for, so the correction has
       to outrank whatever the reader is already looking at. */
    #ea-auth-banner {
      position: fixed;
      inset-block-start: 0;
      inset-inline: 0;
      z-index: 9999;
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 14px;
      flex-wrap: wrap;
      padding: 11px 18px;
      /* NOT var(--status-fail): that token is a LIGHT red tuned to sit on the
         dark surfaces, and white on it measured 2.77:1 — under the 4.5 floor.
         A fixed dark red keeps this readable in both themes, which matters more
         here than token consistency: the banner exists to be read. */
      background: #991b1b;
      color: #fff;
      font-size: var(--fs-200);
      font-weight: 600;
      box-shadow: 0 2px 12px -4px rgba(0, 0, 0, .45);
    }
    #ea-auth-banner button {
      min-height: 44px;
      padding: 0 16px;
      border: 1.5px solid #fff;
      border-radius: var(--r-sm, 5px);
      background: transparent;
      color: #fff;
      font: inherit;
      cursor: pointer;
    }
    #ea-auth-banner button:hover { background: rgba(255, 255, 255, .16); }
    #ea-auth-banner button:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }

    .code-block {
      background: var(--surface-2);
      border: 1px solid var(--border);
      border-radius: 6px;
      padding: 10px 14px;
      font-family: 'SF Mono', 'Fira Code', monospace;
      font-size: var(--fs-200);
      color: var(--text-2);
      overflow-x: auto;
      /* A shell command is LTR content sitting in an RTL page. Without an
         explicit direction it lays out right-to-left and renders centred and
         clipped — one call site had already been hand-patched with an inline
         text-align to work around this. min-width:0 so the block scrolls
         inside its own container instead of widening the grid track. */
      direction: ltr;
      text-align: left;
      min-width: 0;
      white-space: pre;
    }

    /* Progress bar */
    .prog-track {
      height: 4px;
      background: var(--border);
      border-radius: 2px;
      overflow: hidden;
    }

    .prog-fill {
      height: 100%;
      border-radius: 2px;
      transition:width 0.6s ease;
    }

    /* Page header */
    .page-hdr {
      margin-bottom: 28px;
    }
    /* Only the Overview header carries a trailing control today. The flex rule
       is scoped to headers that actually have one, so every other page header
       keeps its original block layout and vertical rhythm untouched. */
    .page-hdr:has(.page-hdr-main) {
      display: flex; align-items: flex-start;
      justify-content: space-between; gap: var(--sp-4);
    }
    .page-hdr-main { min-width: 0; }
    /* Two classes on purpose: .tp-open is declared ~900 lines further down, so
       a single-class .ovw-open rule loses to it on source order and both the
       width and the rail margin leak through. That is not hypothetical — it
       shipped: .tp-open sizes for the sidebar rail (width:calc(100% - 16px),
       margin:6px 8px 10px), and with flex:none (`0 0 auto`, cannot shrink) the
       button claimed the whole header and squeezed the h1 to zero width.
       Both the width and the margin have to be reset here.
       margin-block-start aligns it with the h1's cap-height rather than the
       block's top edge, so it reads as sitting on the title's line. */
    .tp-open.ovw-open {
      flex: none; width: auto;
      margin: 4px 0 0;
    }

    .page-hdr h1 {
      font-size: var(--fs-400);
      font-weight: var(--fw-bold);
      color: var(--text);
      line-height: var(--lh-400);
      letter-spacing: var(--tracking-tight);
    }

    .page-hdr p {
      font-size: var(--fs-200);
      color: var(--text-3);
      margin-top: 4px;
    }

    /* Divider */
    .div-line {
      border: none;
      border-top: 1px solid var(--border);
      margin: 16px 0;
    }

    /* Platform top border cards */
    .platform-card {
      border-top-width: 2px !important;
      border-top-style: solid !important;
    }

    /* .lib-card and .reveal-up are both already defined once, above (search
       "Scroll reveal" / ".lib-card, .media-thumb" near the top of this
       stylesheet) — not repeated here. */

    /* Wolt button */
    .btn-wolt {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 8px 16px;
      background: #009de0;
      color: var(--on-accent);
      border-radius: 7px;
      font-size: var(--fs-200);
      font-weight: 600;
      border: none;
      cursor: pointer;
      text-decoration: none;
      transition:opacity var(--dur-base) var(--ease-out);
      font-family: 'Rubik', sans-serif;
      direction: rtl;
    }

    .btn-wolt:hover { opacity: 0.85; }

    /* Close button */
    .btn-close {
      display: flex;
      align-items: center;
      justify-content: center;
      width: 28px;
      height: 28px;
      border-radius: 6px;
      background: none;
      border: 1px solid var(--border);
      color: var(--text-2);
      cursor: pointer;
      font-size: var(--fs-200);
      margin-right: auto;
      transition:background var(--dur-fast) var(--ease-out);
    }

    .btn-close:hover { background: var(--surface-2); }

    .btn-secondary {
      padding: 6px 14px;
      border-radius: 6px;
      background: var(--surface-2);
      border: 1px solid var(--border);
      color: var(--text-2);
      font-size: var(--fs-200);
      font-weight: 500;
      cursor: pointer;
      transition:background var(--dur-fast) var(--ease-out);
    }

    .btn-secondary:hover { background: rgba(255,255,255,0.1); }

    /* Stage dot */
    .stage-step {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 6px;
      flex: 1;
    }

    /* ── Start-to-finish flow ────────────────────────────────────────────────
       20 stages wrapping left-to-right. Grid rather than flex+arrows: the
       arrow glyphs the old 8-stage strip used don't survive wrapping (they
       stranded at row ends), and a fixed track keeps every circle aligned
       across rows regardless of label length. `direction: ltr` is deliberate
       inside an otherwise-RTL page — this is a process flow with an inherent
       start and end, and stage 00 must read first. */
    .flow-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
      gap: 14px 8px;
      direction: ltr;
    }
    .flow-step {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 5px;
      min-width: 0;
      position: relative;
    }
    /* Connector runs behind the circles, stopping short of each one. */
    .flow-step::before {
      content: '';
      position: absolute;
      top: 14px;
      left: -8px;
      width: 8px;
      height: 1px;
      background: var(--border);
    }
    .flow-step:first-child::before { display: none; }
    .flow-step__label {
      font-size: var(--fs-100);
      line-height: 1.25;
      color: var(--text-3);
      text-align: center;
      max-width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      direction: ltr;
    }
    .flow-step__pill { min-height: 18px; display: flex; align-items: center; }
    .flow-step.is-skipped { opacity: .45; }

    .stage-circle {
      width: 28px;
      height: 28px;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: var(--fs-100);
      font-weight: 700;
      flex-shrink: 0;
    }

    /* color-mix keeps the translucent tint tied to the token: change
       --status-* once and the fill, text and border all follow, instead of
       three hardcoded rgba() triples per state drifting apart. */
    .stage-circle.done {
      background: color-mix(in srgb, var(--status-done) 14%, transparent);
      color: var(--status-done);
      border: 1px solid color-mix(in srgb, var(--status-done) 32%, transparent);
    }

    .stage-circle.running {
      background: color-mix(in srgb, var(--status-running) 14%, transparent);
      color: var(--status-running);
      border: 1px solid color-mix(in srgb, var(--status-running) 40%, transparent);
    }

    .stage-circle.fail {
      background: color-mix(in srgb, var(--status-fail) 14%, transparent);
      color: var(--status-fail);
      border: 1px solid color-mix(in srgb, var(--status-fail) 32%, transparent);
    }

    .stage-circle.warn {
      background: color-mix(in srgb, var(--status-warn) 14%, transparent);
      color: var(--status-warn);
      border: 1px solid color-mix(in srgb, var(--status-warn) 32%, transparent);
    }

    .stage-circle.pending {
      background: color-mix(in srgb, var(--status-idle) 12%, transparent);
      color: var(--text-3);
      border: 1px solid var(--border);
    }

    .stage-arrow {
      color: var(--text-3);
      font-size: var(--fs-200);
      padding-top: 6px;
      flex-shrink: 0;
    }

    /* ── Pipeline rail (Overview) ──────────────────────────────────────────
       Replaces the 20-row two-column list. Same 20 stages, grouped into the
       five phases the architecture actually has, so "where is this run" is
       one glance down five rows instead of a scan of twenty.

       `direction: ltr` on the rail only — a process with a first and a last
       step reads left-to-right even on an RTL page, same reasoning as
       .flow-grid above. The phase names stay in the page's RTL flow. */
    .pl-now {
      display: flex;
      align-items: flex-start;
      gap: 9px;
      padding: 9px 11px;
      border: 1px solid;
      border-radius: var(--r-md, 7px);
      margin-bottom: 16px;
    }
    .pl-phases { display: flex; flex-direction: column; gap: 7px; }
    .pl-view-toggle{display:flex;gap:2px;background:var(--surface-2);border-radius:8px;padding:2px}
    .pl-view-btn{
      font-size:11px;font-weight:600;padding:4px 10px;border-radius:6px;border:none;
      background:transparent;color:var(--text-3);cursor:pointer;
      transition:background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
    }
    .pl-view-btn.active{background:var(--surface);color:var(--text);box-shadow:0 1px 2px rgba(9,9,11,.08)}
    .pl-board{display:flex;flex-direction:column;gap:14px}
    /* pipelineBoardHtml()'s rows are click targets (openStageDrawer), but
       boardRow() already emits its own style="border-inline-start-color:..."
       on the element — a browser keeps only the first `style` attribute, so
       a smuggled style="cursor:pointer" from the caller was silently dropped.
       Real CSS rule instead, scoped to the pipeline board only. */
    .pl-board .board-row{cursor:pointer}
    /* The whole row is LTR, not just the rail. With an RTL row the phase name
       landed at the far right and a 2-stage phase left a dead gap between the
       label and the tiles it labels. One direction for the entire process line
       keeps name, rail and count in reading order and the gap at the end where
       it belongs. The Hebrew name still renders RTL inside its own cell —
       bidi handles a pure-Hebrew run regardless of the container. */
    .pl-phase {
      display: grid;
      grid-template-columns: 84px 1fr 40px;
      align-items: center;
      gap: 10px;
      direction: ltr;
    }
    .pl-phase__name {
      font-size: var(--fs-100);
      color: var(--text-2);
      text-align: right;
      /* Isolated so "SEO ופרסום" keeps its Hebrew base direction inside the
         LTR row — without this, bidi resolves the label against the row and
         flips the Latin run to the wrong end of the phrase. */
      direction: rtl;
      unicode-bidi: isolate;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    .pl-phase__count {
      font-size: 11px;
      font-weight: 600;
      text-align: left;
      font-variant-numeric: tabular-nums;
    }
    /* A grid, not a flex row, and always six columns — the longest phase.
       flex:1 sized every segment against its own phase, so a 2-stage phase
       drew tiles three times the width of a 6-stage phase and the rows could
       not be compared to each other. Fixed columns make stage position mean
       the same thing on every row. */
    .pl-rail {
      display: grid;
      grid-template-columns: repeat(6, minmax(0, 1fr));
      gap: 3px;
      direction: ltr;
      min-width: 0;
    }

    /* Latin/identifier utility classes — a skill or script name (business-
       research, flash_content_factory.py) sitting inside an RTL popover gets
       its punctuation reordered by the bidi algorithm without these, the same
       defect this file already fixes for phone numbers and shell commands
       elsewhere. .mono is Courier-less on purpose: this page has no monospace
       webfont loaded, so it borrows the system stack already used on .pl-seg. */
    .ltr { direction: ltr; unicode-bidi: isolate; display: inline-block; }
    .mono { font-family: ui-monospace, SFMono-Regular, monospace; }

    .pl-seg {
      position: relative;   /* anchors .pl-tip */
      min-width: 0;
      height: 34px;
      border-radius: 4px;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 0 4px;
      font-size: 11px;
      font-weight: 600;
      letter-spacing: -.005em;
      line-height: 1.15;
      text-align: center;
      border: 1px solid transparent;
      /* The QC verdict rides on the bottom edge — its own channel, so a run
         result and a review result can never be read as the same fact. */
      border-bottom-width: 2px;
      /* pointer, not default. The segment carries onclick="openStageDrawer(...)"
         and a matching Enter/Space keydown, so it IS interactive — `default`
         was left over from when the .pl-tip popover was the only payload and
         hovering was the whole interaction. On a phone .pl-tip is display:none
         (see the pointer:coarse block below), which made the rail 23 tab stops
         that showed a colour and nothing else; the drawer is the replacement,
         and a cursor that says "not clickable" is the last thing hiding it. */
      cursor: pointer;
      transition:transform var(--dur-base, var(--dur-base)) var(--ease-out), filter    var(--dur-base, var(--dur-base)) var(--ease-out);
    }
    /* Left unguarded on purpose: the @media (hover:none) block further down
       already resets transform and filter for .pl-seg:hover along with six
       other selectors. Wrapping this one in @media (hover:hover) as well would
       be a second mechanism for the same job, and the two would drift. */
    .pl-seg:hover { transform: translateY(-2px); filter: brightness(1.07); }
    .pl-seg:focus-visible { outline: none; }   /* the popover itself is the focus signal */
    .pl-seg__label {
      display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
      overflow: hidden;
    }

    /* Rich hover/focus popover — replaces a native `title`, which is one
       plain-text line and cannot show "which skill / script / engine" as
       separate, scannable facts the way Asaf asked for. Pure CSS: no JS
       show/hide, so it can never desync from the DOM it describes. */
    .pl-tip {
      position: absolute;
      bottom: calc(100% + 8px);
      left: 50%;
      transform: translateX(-50%) translateY(4px);
      width: max-content;
      max-width: 240px;
      background: var(--surface);
      border: 1px solid var(--border-strong);
      border-radius: var(--r-md);
      box-shadow: var(--sh-lg);
      padding: 10px 12px;
      text-align: right;
      font-size: 11px;
      font-weight: 500;
      line-height: 1.5;
      color: var(--text-2);
      opacity: 0;
      visibility: hidden;
      pointer-events: none;
      transition:opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
      z-index: var(--z-dropdown);
    }
    .pl-tip b { display: block; color: var(--text); font-size: 11.5px; margin-bottom: 4px; }
    .pl-tip__status { color: var(--text-3); margin-bottom: 6px; padding-bottom: 6px; border-bottom: 1px solid var(--border); }
    .pl-tip__row { display: flex; justify-content: space-between; gap: 8px; white-space: nowrap; }
    .pl-tip__row .ltr { color: var(--text-3); font-size: 11px; overflow: hidden; text-overflow: ellipsis; max-width: 165px; }
    .pl-seg:hover .pl-tip, .pl-seg:focus-visible .pl-tip {
      opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0);
      pointer-events: auto;
    }

    /* Segment text is the status colour pulled 20% toward --text. The raw
       status colour on its own 15% tint measured 4.24:1 (done) — under AA for
       11px text — and --text-3 on the --surface-3 well 4.47:1 (pending). The
       mix keeps the hue and lands >=5:1 in both themes (dark: toward the
       light ink, so it brightens instead). */
    .pl-seg.done {
      background: color-mix(in srgb, var(--status-done) 15%, transparent);
      color: color-mix(in srgb, var(--status-done) 80%, var(--text));
      border-color: color-mix(in srgb, var(--status-done) 30%, transparent);
    }
    .pl-seg.running {
      background: color-mix(in srgb, var(--status-running) 18%, transparent);
      color: color-mix(in srgb, var(--status-running) 80%, var(--text));
      border-color: color-mix(in srgb, var(--status-running) 45%, transparent);
      animation: pulse-dot 2s infinite;
    }
    .pl-seg.fail {
      background: color-mix(in srgb, var(--status-fail) 15%, transparent);
      color: color-mix(in srgb, var(--status-fail) 80%, var(--text));
      border-color: color-mix(in srgb, var(--status-fail) 32%, transparent);
    }
    /* Hatched, not solid. A stage that crashed and a stage that ran clean and
       was rejected for its content are different problems with different
       fixes, and drawing them in the same flat red says they are the same. */
    .pl-seg.rejected {
      background: repeating-linear-gradient(135deg,
        color-mix(in srgb, var(--status-fail) 26%, transparent) 0 4px,
        color-mix(in srgb, var(--status-fail)  7%, transparent) 4px 9px);
      color: var(--status-fail);
      border-color: color-mix(in srgb, var(--status-fail) 45%, transparent);
    }
    .pl-seg.warn,
    .pl-seg.needs_writer,
    .pl-seg.redone {
      background: color-mix(in srgb, var(--status-warn) 15%, transparent);
      color: color-mix(in srgb, var(--status-warn) 80%, var(--text));
      border-color: color-mix(in srgb, var(--status-warn) 32%, transparent);
    }
    .pl-seg.pending {
      background: var(--surface-3);
      color: var(--text-2);
      border-color: var(--border);
    }
    .pl-seg.skipped {
      background: transparent;
      color: var(--text-3);
      border: 1px dashed var(--border-strong);
      opacity: .65;
    }
    .pl-seg.qc-ok  { border-bottom-color: var(--status-done); }
    .pl-seg.qc-bad { border-bottom-color: var(--status-fail); }

    .pl-legend {
      display: flex;
      align-items: center;
      gap: 14px;
      flex-wrap: wrap;
      margin-top: 14px;
      padding-top: 11px;
      border-top: 1px solid var(--border);
      font-size: 11px;
      color: var(--text-2);
    }
    .pl-legend span { display: inline-flex; align-items: center; gap: 5px; }
    /* Blog preview rendered as real HTML (openContentPreview) instead of
       flattened plain text -- overrides the plain-text default's
       white-space:pre-wrap, which would otherwise render the HTML source's
       own indentation as visible gaps. Sizes follow this file's real type
       scale (--fs-*) rather than unstyled browser heading defaults. */
    /* ── Schedule tab rows ───────────────────────────────────────────────
       Grid, not a bare flex row: the text cell is 1fr with min-width:0 and
       its children truncate, so a long Hebrew title or a long Latin slug
       shrinks instead of pushing the controls out of the row or overlapping
       them. Controls are auto-width and never shrink. Pure white surface,
       1px hairline separation, teal only for active states. */
    /* flex-wrap, not a fixed grid: rows carry a VARIABLE number of controls
       (a pending row has an extra approve button), and a grid with a fixed
       column count overflows as soon as the row is narrower than its columns
       need — which a viewport media query does not catch, because the row can
       be narrow inside a wide window. Wrapping responds to the width the row
       actually has, so nothing can escape it at any size. */
    .sched-row {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: var(--sp-3);
      padding: var(--sp-3);
      background: var(--surface);
      border: 1px solid var(--border);
      border-radius: var(--r-md);
    }
    /* Grows to fill, shrinks to nothing, and is the first thing to give up
       space — so the controls stay whole and the text truncates instead. */
    .sched-cell { flex: 1 1 200px; }
    .sched-cell { min-width: 0; }
    .sched-title {
      font-size: var(--fs-200); font-weight: var(--fw-semi); color: var(--text);
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .sched-sub {
      font-size: var(--fs-100); color: var(--text-3); margin-top: 2px;
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .sched-input {
      padding: 6px 9px; border: 1px solid var(--border); border-radius: var(--r-sm);
      font-size: var(--fs-100); background: var(--surface); color: var(--text);
      font-family: 'Rubik', sans-serif; min-width: 0;
    }
    .sched-input:focus-visible { outline: none; box-shadow: var(--sh-focus); border-color: var(--accent); }
    .sched-btn { flex: none; white-space: nowrap; }
    /* Phone: give the controls the full row each, so a wrapped layout reads as
       deliberate stacking rather than ragged leftovers. */
    @media (max-width: 640px) {
      .sched-row .sched-input, .sched-row .sched-btn { width: 100%; max-width: none; }
    }

    /* ── Schedule tab: content-type grouping + bulk select ────────────────
       Sixteen identical rows in one flat list (no grouping, no bulk action,
       a repeated per-row control set) was the actual complaint. The fix is
       information density, not colour: group by content type — the one
       identity every schedulable item always has exactly one of — and let a
       checkbox stand in for the ten-click "select every caption, set the
       same time on each" case.

       The group icon carries the one colour cue in this block on purpose.
       Repeating it as a rail on every row under an already-labelled,
       already-coloured header is decoration, not information — spend it
       once, where it identifies the group, not sixteen times where it
       would only repeat what the header already said. */
    .sched-group-hdr {
      display: flex; align-items: center; gap: 8px;
      padding: 2px 2px var(--sp-2);
    }
    .sched-group-ic {
      width: 22px; height: 22px; border-radius: var(--r-sm); flex: none;
      display: grid; place-items: center;
    }
    .sched-group-name {
      font-size: var(--fs-100); font-weight: var(--fw-semi); color: var(--text-2);
      text-transform: uppercase; letter-spacing: .05em;
    }
    .sched-group-count {
      font-size: var(--fs-100); color: var(--text-3);
      font-variant-numeric: tabular-nums;
    }
    .sched-chk { flex: none; width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }
    /* The 16px box is what you look at; the label around it is what a thumb
       hits (it measured 16x16 with no wrapper at 390 and 768). Negative block
       margins keep the row height it had; the inline margin sits inside the
       row's 12px padding. */
    .sched-chk-hit {
      flex: none; display: inline-flex; align-items: center; justify-content: center;
      min-width: 44px; min-height: 44px; margin-block: -14px; margin-inline: -12px;
      cursor: pointer;
    }
    .sched-row.is-checked { background: var(--accent-soft); border-color: transparent; }

    /* Sticky rather than static: with sixteen rows across three groups the
       bar the operator needs — "N selected, schedule them" — would otherwise
       scroll off before the selection it describes does. Hidden by default
       and only raised on a real selection, so an untouched list shows
       nothing that implies there is something to clear. */
    .sched-bulk {
      position: sticky; top: 8px; z-index: 3;
      display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-3);
      background: var(--text); color: var(--text-inverse);
      border-radius: var(--r-lg); box-shadow: var(--sh-md);
      /* Collapsed, not merely invisible. opacity:0 alone left the bar in
         layout, so an untouched list opened with a ~40px blank band above it
         (about 100px on a phone, where the bar's five items wrapped). It now
         takes no space until something is selected. */
      max-height: 0; padding-block: 0; padding-inline: var(--sp-4); margin-bottom: 0;
      overflow: hidden; transform: translateY(-8px); opacity: 0; pointer-events: none;
      transition: transform var(--dur-base) var(--ease-out), opacity var(--dur-base) ease,
                  max-height var(--dur-base) var(--ease-out), margin var(--dur-base) var(--ease-out);
    }
    .sched-bulk.is-on {
      max-height: 200px; padding-block: var(--sp-2); margin-bottom: var(--sp-3);
      transform: translateY(0); opacity: 1; pointer-events: auto;
    }
    .sched-bulk b { font-variant-numeric: tabular-nums; }
    .sched-bulk .sp { flex: 1; }
    .sched-bulk input[type="datetime-local"] {
      font: inherit; font-size: var(--fs-100); border: 0; border-radius: var(--r-sm);
      padding: 6px 10px; background: rgba(255,255,255,.14); color: var(--text-inverse);
      color-scheme: dark;
    }
    @media (prefers-reduced-motion: reduce) {
      .sched-bulk { transition: none; }
    }

    /* ── Media thumbnail caption ─────────────────────────────────────────
       Two real defects this replaces, both measured rather than guessed:

       1. The caption used color:var(--text) (#0a2540, the page's near-black
          ink) on a rgba(0,0,0,.82) gradient — 1.35:1. Near-black on
          near-black: the text was there and effectively unreadable. This is
          a fixed-dark surface whatever the theme does, so the colour is
          fixed light rather than a themed token.
       2. There was no length limit. A long Hebrew caption grew the overlay
          upward until it covered the image it was captioning. Clamped to two
          lines; the full text is still reachable in the lightbox. */
    .media-thumb-cap {
      position: absolute; inset-inline: 0; bottom: 0;
      padding: 7px 8px; pointer-events: none;
      background: linear-gradient(transparent, rgba(0,0,0,.86));
    }
    .media-thumb-cap-txt {
      font-size: 11px; line-height: 1.35; color: #ffffff;
      direction: rtl; font-family: 'Rubik', sans-serif;
      display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
      overflow: hidden;
      text-shadow: 0 1px 2px rgba(0,0,0,.6);   /* survives a bright photo edge */
    }

    /* ── Strategy tab ────────────────────────────────────────────────────
       Pure white surfaces, 1px hairlines, teal only for the selected state.
       Inputs and chips clear the 44px touch floor via the shared rule above;
       the explicit min-height here covers the desktop case too, since these
       are long-form fields an operator types real sentences into. */
    .strat-field { display: block; margin-bottom: var(--sp-5); }
    .strat-label {
      display: block; font-size: var(--fs-100); font-weight: var(--fw-semi);
      color: var(--text-2); margin-bottom: var(--sp-2);
      letter-spacing: var(--tracking-caps); text-transform: uppercase;
    }
    .strat-input {
      width: 100%; min-height: 44px; padding: 10px 12px;
      background: var(--surface); color: var(--text);
      border: 1px solid var(--border); border-radius: var(--r-md);
      font-family: 'Rubik', sans-serif; font-size: var(--fs-200);
      line-height: 1.7; resize: vertical;
    }
    .strat-input:focus-visible {
      outline: none; border-color: var(--accent); box-shadow: var(--sh-focus);
    }
    .strat-hint {
      display: block; font-size: var(--fs-100); color: var(--text-3);
      margin-top: var(--sp-2); line-height: 1.6;
    }
    .strat-chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
    .strat-chip {
      display: inline-flex; align-items: center; gap: var(--sp-2);
      min-height: 44px; padding: 0 var(--sp-4);
      border: 1px solid var(--border); border-radius: var(--r-full);
      background: var(--surface); color: var(--text-2);
      font-size: var(--fs-200); cursor: pointer;
      transition:border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
    }
    .strat-chip input { accent-color: var(--accent); width: 16px; height: 16px; }
    .strat-chip.is-on { border-color: var(--accent); color: var(--accent); font-weight: var(--fw-semi); }
    /* min(260px, 100%) not a bare 260px: auto-fit honours the minimum even when
       the container is narrower than it, so a bare 260px overflows a narrow
       column by exactly (260 - container). Measured: a 229px container pushed
       every persona card 31px outside it. The min() lets the track collapse to
       the container when there is not room, which is what auto-fit is for. */
    .strat-personas { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); gap: var(--sp-3); }
    .strat-persona {
      background: var(--surface); border: 1px solid var(--border);
      border-radius: var(--r-md); padding: var(--sp-4); min-width: 0;
    }
    .strat-persona-top { display: flex; align-items: baseline; gap: var(--sp-2); margin-bottom: var(--sp-2); }
    .strat-persona-name { font-size: var(--fs-200); font-weight: var(--fw-semi); color: var(--text); }
    .strat-persona-age { font-size: var(--fs-100); color: var(--text-3); }
    .strat-persona-row { font-size: var(--fs-100); color: var(--text-2); line-height: 1.7; margin-top: 2px; }
    .strat-persona-row b { color: var(--text-3); font-weight: var(--fw-semi); }

    /* ── New Client / intake tab ──────────────────────────────────────────
       web/dashboard/intake.js builds this markup and has done since it
       shipped — el('div','intake-field'), el('input','intake-input'), and so
       on through fourteen more class names — but never carried its own CSS,
       and none of the three stylesheets this page links (dashboard-tokens,
       dashboard.css, monday-vibe) had a single `.intake-` rule. Measured:
       zero matches across all three. So the tab an operator uses to onboard
       a paying client rendered as bare, unstyled <input>/<select>/<button>
       elements — default browser chrome dropped into a themed dashboard,
       which is indistinguishable at a glance from something failing to load.

       Mirrors .strat-* (renderStrategy's own form, same field/label/input/
       hint shape) rather than inventing a second form language, and .ea-card
       for the queue cards, for the same reason .strat-* already gives: one
       visual vocabulary for "a form on this dashboard", not two.

       #tab-intake's two mounted children (`queue`, `form` in dashboard.js)
       are plain unclassed <div>s — renderIntakeQueue() and
       renderIntakeForm() take a bare mount element and were never given a
       wrapper class of their own. Positional selectors below are what let
       this be CSS-only: nothing in intake.js changes. */
    #tab-intake { padding: var(--sp-6) var(--sp-5); }
    #tab-intake > div { max-width: 640px; }
    #tab-intake > div + div { margin-top: var(--sp-8); padding-top: var(--sp-8);
      border-top: 1px solid var(--border); }

    .intake-head { margin-bottom: var(--sp-5); }
    .intake-title {
      font-size: var(--fs-300); line-height: var(--lh-300); font-weight: var(--fw-semi);
      color: var(--text); margin: 0 0 var(--sp-2);
    }
    .intake-sub { font-size: var(--fs-200); color: var(--text-3); margin: 0; }

    .intake-status {
      font-size: var(--fs-200); line-height: 1.6; margin-bottom: var(--sp-4);
      min-height: 0; /* collapses to nothing when empty, so an unused status
                        banner does not sit as a blank gap above the form */
    }
    .intake-status:empty { display: none; }
    .intake-status--error, .intake-status--ok {
      padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md);
    }
    .intake-status--error { background: var(--status-fail-bg); color: var(--status-fail); }
    .intake-status--ok    { background: var(--status-done-bg); color: var(--status-done); }

    .intake-form { display: block; }
    .intake-section {
      font-size: var(--fs-100); font-weight: var(--fw-semi); color: var(--text-2);
      text-transform: uppercase; letter-spacing: var(--tracking-caps);
      margin: var(--sp-6) 0 var(--sp-3);
      padding-top: var(--sp-5); border-top: 1px solid var(--border);
    }
    .intake-section:first-of-type { margin-top: var(--sp-5); padding-top: 0; border-top: 0; }

    .intake-field { display: block; margin-bottom: var(--sp-5); }
    .intake-label {
      display: block; font-size: var(--fs-100); font-weight: var(--fw-semi);
      color: var(--text-2); margin-bottom: var(--sp-2);
      letter-spacing: var(--tracking-caps); text-transform: uppercase;
    }
    .intake-req { color: var(--status-fail); font-weight: var(--fw-bold); }
    .intake-input {
      width: 100%; min-height: 44px; padding: 10px 12px; box-sizing: border-box;
      background: var(--surface); color: var(--text);
      border: 1px solid var(--border); border-radius: var(--r-md);
      font-family: 'Rubik', sans-serif; font-size: var(--fs-200);
      line-height: 1.7; resize: vertical;
    }
    .intake-input:focus-visible {
      outline: none; border-color: var(--accent); box-shadow: var(--sh-focus);
    }
    /* The client-id field alone sets dir=ltr in intake.js — an id is never
       RTL — so its help text and error line up under it rather than under
       the RTL default this rule would otherwise give every other field. */
    #intake_client_id { text-align: left; }
    .intake-help {
      display: block; font-size: var(--fs-100); color: var(--text-3);
      margin-top: var(--sp-2); line-height: 1.6;
    }
    .intake-error {
      display: block; font-size: var(--fs-100); color: var(--status-fail);
      margin-top: var(--sp-2); line-height: 1.5; min-height: 0;
    }
    .intake-error:empty { display: none; }

    .intake-btn {
      min-height: 44px; padding: 0 var(--sp-5);
      background: var(--surface); color: var(--text);
      border: 1px solid var(--border); border-radius: var(--r-md);
      font-family: 'Rubik', sans-serif; font-size: var(--fs-200); font-weight: var(--fw-semi);
      cursor: pointer;
      transition: border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
    }
    .intake-btn:hover { border-color: var(--border-strong); }
    .intake-btn:disabled { opacity: .6; cursor: default; }
    .intake-btn--primary {
      background: var(--accent); color: var(--on-accent); border-color: transparent;
    }
    .intake-btn--primary:hover:not(:disabled) { background: var(--accent-hover); }

    /* Queue cards — same surface/border/radius/shadow as .ea-card, spelled
       out rather than shared: intake.js builds these with its own class,
       and duplicating four declarations here costs less than making a
       generative-form file depend on a class name owned by dashboard.js. */
    .intake-card {
      background: var(--surface); border: 1px solid var(--border);
      border-radius: var(--r-lg); box-shadow: var(--sh-xs);
      padding: var(--sp-4); margin-bottom: var(--sp-3);
    }
    .intake-card-head {
      font-size: var(--fs-200); font-weight: var(--fw-semi); color: var(--text);
      margin-bottom: var(--sp-2);
    }
    .intake-card-brand { font-weight: var(--fw-regular); color: var(--text-3); }
    .intake-meta { font-size: var(--fs-100); color: var(--text-2); line-height: 1.7; }
    .intake-meta--dim { color: var(--text-3); }
    .intake-run-row {
      display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-3);
    }
    .intake-run-row .intake-btn { padding: 0 var(--sp-4); font-size: var(--fs-100); }

    /* Optional fields, collapsed per section (see intake.js). A native
       <details>: keyboard, screen-reader and find-in-page behaviour for free. */
    .intake-optional {
      margin: 0 0 var(--sp-5); border: 1px solid var(--border); border-radius: var(--r-md);
      background: var(--surface);
    }
    .intake-optional-sum {
      display: flex; align-items: center; min-height: 44px; padding: 0 var(--sp-4);
      cursor: pointer; list-style: none; user-select: none;
      font-size: var(--fs-200); font-weight: var(--fw-semi); color: var(--text-2);
    }
    .intake-optional-sum::-webkit-details-marker { display: none; }
    .intake-optional-sum::after {
      content: ''; margin-inline-start: auto; width: 7px; height: 7px;
      border-inline-end: 2px solid currentColor; border-bottom: 2px solid currentColor;
      transform: rotate(45deg); transition: transform var(--dur-fast) var(--ease-out);
    }
    .intake-optional[open] > .intake-optional-sum { color: var(--text); margin-bottom: var(--sp-3); }
    .intake-optional[open] > .intake-optional-sum::after { transform: rotate(-135deg); }
    .intake-optional-sum:focus-visible { outline: none; box-shadow: var(--sh-focus); border-radius: var(--r-md); }
    .intake-optional > .intake-field { padding: 0 var(--sp-4); }
    @media (prefers-reduced-motion: reduce) { .intake-optional-sum::after { transition: none; } }

    /* ── Classes dashboard.js emits that no stylesheet defined ────────────
       Found by diffing every class="…" / el(tag,'…') / classList in
       dashboard.js, intake.js, index.html and ea-dashboard.js against every
       selector in every .css file AND every rule embedded in a JS/HTML
       <style> block (the second half matters: a first pass over .css files
       alone flagged the whole media-library grid, which is defined inside
       dashboard.js). What remained, and had a visible effect:

       .cal-*        the Analytics calendar heatmap. cal-day-none/low/mid/high
                     and cal-day-today were being set on every cell and none
                     of them existed, so the month rendered as a column of
                     bare day numbers with no heat colours at all. Levels
                     mirror the legend swatches renderCalendar() draws:
                     surface-2 / done 25% / done 55% / solid done.
       .rule-chip    Agent Rules allow/deny chips. `.allow` was undefined
                     too, so an allowed and a denied term looked identical
                     apart from a ✓ or ✗ glyph.
       .n8n-spinner  swapped in for the run button's icon while an agent
                     executes — an empty inline span, i.e. no feedback.
       .cs-tile-s    the sub-label under a client-status stat tile.
       .ea-btn--sm / --ghost   size and ghost modifiers on Sales Health's
                     Refresh button. Doubled selector because .ea-btn is
                     defined later in this file and would otherwise win. */
    /* Analytics layout (2026-10-23). Ring + content bars on top, stage strip
       beside the calendar. Heights are fixed boxes: Chart.js sized the pie to
       its card's width, 530px tall, and the card beside it stretched to
       match around one sentence. */
    .an-top, .an-mid { display: grid; gap: var(--sp-6); margin-bottom: var(--sp-6); align-items: start; }
    .an-top { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .an-mid { grid-template-columns: minmax(0, 1fr) minmax(0, 460px); }
    @media (max-width: 960px) { .an-top, .an-mid { grid-template-columns: minmax(0, 1fr); } }
    .an-ring { display: flex; align-items: center; gap: var(--sp-5); min-height: 150px; }
    .an-ring-box { position: relative; width: 150px; height: 150px; flex: none; }
    .an-ring-num { display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-100); color: var(--text-3); }
    .an-ring-num b { font-size: 40px; line-height: 1; font-weight: var(--fw-bold); color: var(--text); font-variant-numeric: tabular-nums; }
    .an-bars { position: relative; width: 100%; min-height: 58px; }
    .an-empty { padding: 28px 8px; text-align: center; color: var(--text-3); font-size: 12px; line-height: 1.7; }
    .an-phases { display: flex; flex-direction: column; gap: var(--sp-3); }
    .an-phase { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: var(--sp-3); align-items: start; }
    .an-phase-hd { display: flex; flex-direction: column; gap: 2px; padding-top: 6px; font-size: var(--fs-100); color: var(--text-2); font-weight: var(--fw-semi); }
    .an-phase-hd b { color: var(--text-3); font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; }
    .an-phase.is-done .an-phase-hd b { color: var(--status-done); }
    @media (max-width: 560px) { .an-phase { grid-template-columns: minmax(0, 1fr); gap: 6px; } .an-phase-hd { flex-direction: row; justify-content: space-between; padding-top: 0; } }
    /* Volume cells in the keyword tables: a bar behind the number, filled to
       the row's share of the largest volume on the card, from the right. */
    .kw-vol { display: block; min-width: 128px; padding: 2px 6px; border-radius: 4px;
      background: linear-gradient(to left, color-mix(in srgb, var(--accent) 22%, transparent) var(--v), transparent var(--v)); }
    .kw-more > summary { cursor: pointer; list-style-position: inside; }
    .kw-more > summary > div { display: inline-block; }
    .an-stages { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px; }
    .an-stage {
      display: flex; align-items: center; gap: 8px; min-width: 0; padding: 7px 10px;
      border-radius: var(--r-sm); border: 1px solid var(--border); background: var(--surface);
      font-size: var(--fs-100); color: var(--text-3);
    }
    .an-stage i {
      flex: none; width: 16px; height: 16px; border-radius: 50%; display: grid; place-items: center;
      font-style: normal; font-size: 10px; font-weight: var(--fw-bold);
      border: 1.5px solid var(--chip); color: var(--on-accent, #fff);
    }
    .an-stage.is-done { color: var(--text-2); }
    /* Next in line: one chip outlined in its state colour, with a badge, and
       the same answer as a line above the phases. */
    .an-stage.is-next { border-color: var(--next); box-shadow: inset 0 0 0 1px var(--next); color: var(--text); flex-wrap: wrap; }
    .an-next-badge { flex: none; margin-inline-start: auto; padding: 1px 7px; border-radius: 99px; font-style: normal;
      font-size: 11px; font-weight: var(--fw-semi); color: var(--next); background: color-mix(in srgb, var(--next) 12%, transparent); }
    .an-next { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; margin-bottom: var(--sp-3); padding: 8px 12px;
      border-radius: var(--r-sm); border-inline-start: 3px solid var(--next); background: color-mix(in srgb, var(--next) 8%, transparent);
      font-size: var(--fs-100); color: var(--text-2); }
    .an-next > span:first-child { color: var(--next); font-weight: var(--fw-semi); }
    .an-next b { color: var(--text); font-variant-numeric: tabular-nums; }
    .an-stage.is-done i { background: var(--chip); }
    .an-stage b { flex: none; font-weight: var(--fw-semi); color: var(--text); font-variant-numeric: tabular-nums; }
    .an-stage span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .cal-grid {
      display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
      gap: 4px; max-width: 420px;
    }
    .cal-day {
      aspect-ratio: 1 / 1; display: grid; place-items: center;
      border-radius: var(--r-sm); background: var(--surface-2); color: var(--text-2);
      font-size: var(--fs-100); font-variant-numeric: tabular-nums;
    }
    .cal-day-empty { background: transparent; }
    /* --surface-2 is pure #fff in this theme, so an idle day is white on a
       white card — no figure/ground. A hairline keeps the month readable as
       a grid without inventing a tint the legend swatch would then disagree
       with. Active levels carry their own fill and need no edge. */
    .cal-day-none { box-shadow: inset 0 0 0 1px var(--border); }
    .cal-day-low   { background: color-mix(in srgb, var(--status-done) 25%, transparent); color: var(--text); }
    .cal-day-mid   { background: color-mix(in srgb, var(--status-done) 55%, transparent); color: var(--text); }
    .cal-day-high  { background: var(--status-done); color: var(--on-accent); }
    .cal-day-today { outline: 2px solid var(--accent); outline-offset: 1px; font-weight: var(--fw-bold); }

    .rule-chip {
      display: inline-flex; align-items: center; gap: 4px; margin: 2px;
      padding: 3px 10px; border-radius: var(--r-full); cursor: pointer;
      font-size: var(--fs-100); font-weight: var(--fw-semi);
      background: var(--status-fail-bg); color: var(--status-fail);
      border: 1px solid color-mix(in srgb, var(--status-fail) 25%, transparent);
      transition: border-color var(--dur-fast) var(--ease-out),
                  transform var(--dur-fast) var(--ease-out),
                  opacity var(--dur-fast) var(--ease-out);
      transform-origin: center;
    }
    /* renderAgentIntelligence() replaces the whole panel's innerHTML on every
       add/remove (it re-fetches and re-renders, not a per-chip DOM patch),
       so every chip is a freshly-inserted node each time — @starting-style
       is what fires here, no JS needed, and it correctly covers both an add
       and a remove (the shortened list resettles). Group-entrance tier:
       occasional (editing rules, not tens-of-times/day), decorative, never
       blocks interaction. found-animation-opportunities, 2026-09-23. */
    @starting-style {
      .rule-chip { opacity: 0; transform: scale(0.95); }
    }
    @media (prefers-reduced-motion: reduce) {
      .rule-chip { transition: border-color var(--dur-fast) var(--ease-out); }
      @starting-style { .rule-chip { opacity: 1; transform: none; } }
    }
    .rule-chip.allow {
      background: var(--status-done-bg); color: var(--status-done);
      border-color: color-mix(in srgb, var(--status-done) 25%, transparent);
    }
    .rule-chip:hover { border-color: currentColor; }

    .n8n-spinner {
      display: inline-block; width: 14px; height: 14px; border-radius: 50%;
      border: 2px solid color-mix(in srgb, currentColor 30%, transparent);
      border-top-color: currentColor; vertical-align: -2px;
      animation: spin .8s linear infinite;
    }
    @media (prefers-reduced-motion: reduce) { .n8n-spinner { animation-duration: 2.4s; } }

    .cs-tile-s { font-size: var(--fs-100); color: var(--text-3); margin-top: 2px; line-height: 1.4; }

    .ea-btn.ea-btn--sm { min-height: 32px; padding: 0 var(--sp-3); font-size: var(--fs-100); }
    .ea-btn.ea-btn--ghost { background: transparent; border-color: transparent; color: var(--text-2); }
    .ea-btn.ea-btn--ghost:hover { background: var(--surface-2); color: var(--text); }

    /* .btn / .btn-sm / .input are emitted by the ads-publishing and calendar-
       sync panels inside Integrations and by the workspace ticket actions
       (className: 'btn btn-sm', className: 'input') and had no rule at all, so
       every one of those controls rendered as a raw browser button or field.
       Measured by rendering every tab in the real app and flagging controls
       whose computed border-style is still the UA's outset/inset. Neutral
       secondary look, matching .btn-secondary; there is no primary variant to
       key off, so "approve and publish" looks like its neighbours — a markup
       change if that should stand out. 44px floor kept, as everywhere else. */
    .btn {
      display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
      min-height: 44px; padding: 0 var(--sp-4); box-sizing: border-box;
      background: var(--surface); color: var(--text);
      border: 1px solid var(--border-strong); border-radius: var(--r-md);
      font-family: 'Rubik', sans-serif; font-size: var(--fs-200); font-weight: var(--fw-semi);
      cursor: pointer;
      transition: background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
    }
    .btn:hover:not(:disabled) { background: var(--surface-2); border-color: var(--border-control); }
    .btn:focus-visible { outline: none; box-shadow: var(--sh-focus); }
    .btn:disabled { opacity: .6; cursor: default; }
    .btn.btn-sm { padding: 0 var(--sp-3); font-size: var(--fs-100); }
    .input {
      min-height: 44px; padding: 8px 12px; box-sizing: border-box;
      background: var(--surface); color: var(--text);
      border: 1px solid var(--border-strong); border-radius: var(--r-md);
      font-family: 'Rubik', sans-serif; font-size: var(--fs-200);
    }
    .input:focus-visible { outline: none; border-color: var(--accent); box-shadow: var(--sh-focus); }

    #modal-content-body.modal-body-rendered { white-space: normal; }
    #modal-content-body.modal-body-rendered h2 {
      font-size: var(--fs-300); line-height: var(--lh-300); font-weight: var(--fw-semi);
      color: var(--text); margin: var(--sp-6) 0 var(--sp-2);
    }
    #modal-content-body.modal-body-rendered h3 {
      font-size: var(--fs-200); line-height: var(--lh-200); font-weight: var(--fw-semi);
      color: var(--text); margin: var(--sp-5) 0 var(--sp-2);
    }
    #modal-content-body.modal-body-rendered p { margin: 0 0 var(--sp-3); }
    #modal-content-body.modal-body-rendered h2:first-child,
    #modal-content-body.modal-body-rendered h3:first-child { margin-top: 0; }
    .pl-key {
      width: 9px; height: 9px; border-radius: 2px;
      display: inline-block; flex-shrink: 0;
    }
    .pl-key.done     { background: color-mix(in srgb, var(--status-done) 55%, transparent); }
    .pl-key.running  { background: color-mix(in srgb, var(--status-running) 55%, transparent); }
    .pl-key.fail     { background: color-mix(in srgb, var(--status-fail) 55%, transparent); }
    .pl-key.rejected {
      background: repeating-linear-gradient(135deg,
        color-mix(in srgb, var(--status-fail) 70%, transparent) 0 2px,
        color-mix(in srgb, var(--status-fail) 12%, transparent) 2px 5px);
    }
    .pl-key.warn     { background: color-mix(in srgb, var(--status-warn) 55%, transparent); }
    .pl-key.redone   { background: color-mix(in srgb, var(--status-warn) 55%, transparent); }
    .pl-key.pending  { background: var(--surface-3); border: 1px solid var(--border); }

    .pl-cmd {
      margin-top: 12px;
      padding: 8px 10px;
      background: var(--surface-2);
      border: 1px solid var(--border);
      border-radius: 6px;
      font-family: ui-monospace, SFMono-Regular, monospace;
      font-size: 11px;
      color: var(--text-2);
      direction: ltr;            /* same LTR-command-in-RTL-page rule as .code-block */
      text-align: left;
      overflow-x: auto;
      min-width: 0;
      direction: ltr;
      text-align: left;
      overflow-x: auto;
      white-space: nowrap;
    }

    /* ── Quality-gate panel ──────────────────────────────────────────────── */
    /* Logical radii: the verdict stripe sits on the inline-start edge, so the
       square corners must follow the writing direction rather than being
       pinned to the right by a physical shorthand. */
    .qc-row {
      padding: 9px 11px;
      background: var(--surface-2);
      border-start-start-radius: 0;
      border-end-start-radius: 0;
      border-start-end-radius: var(--r-sm);
      border-end-end-radius: var(--r-sm);
    }
    .qc-row__hd { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
    .qc-row__id {
      font-family: ui-monospace, SFMono-Regular, monospace;
      font-size: 11px;
      font-weight: 700;
      color: var(--text-2);
    }
    .qc-row__label { font-size: var(--fs-100); color: var(--text); }
    .qc-row__when  { font-size: 11px; color: var(--text-3); margin-inline-start: auto; }
    .qc-row__why {
      margin-top: 6px;
      font-size: 11px;
      line-height: 1.5;
      color: var(--status-fail);
    }
    /* The quote is the evidence the verdict rests on. It is set apart because
       it is the artefact's own words, not the reviewer's — a verdict with no
       quote is a rubber stamp, and the --none variant says exactly that. */
    .qc-row__quote {
      margin-top: 6px;
      padding-inline-start: 9px;
      border-inline-start: 2px solid var(--border-strong);
      font-size: 11px;
      line-height: 1.55;
      color: var(--text-2);
    }
    .qc-row__quote--none { color: var(--text-3); font-style: italic; }
    .qc-unjudged {
      display: flex;
      flex-wrap: wrap;
      gap: 4px 10px;
      margin-top: 12px;
      padding-top: 11px;
      border-top: 1px solid var(--border);
      font-size: 11px;
    }

    /* Under ~640px an 84px label column plus six tiles leaves the tiles too
       narrow to read, so the label and count take a line of their own and the
       rail gets the full width beneath them. `order` is what keeps the count
       on the label's line — grid alone puts it after the full-width rail. */
    @media (max-width: 640px) {
      .pl-phases { gap: 13px; }
      .pl-phase  { grid-template-columns: 1fr auto; gap: 5px 8px; }
      .pl-phase__name  { order: 1; text-align: left; }
      .pl-phase__count { order: 2; }
      .pl-rail   { order: 3; grid-column: 1 / -1; }
      .pl-seg    { height: 30px; }
    }



    /* ── Responsive grid utilities ──────────────────────────────────────── */
    /* Every track is minmax(0,1fr), never bare 1fr. A bare 1fr resolves to
       minmax(auto,1fr) — its floor is the content's min-content width, so a
       long unbroken string (a stage label, a URL) pushes the track wider than
       its share and the whole grid overflows its container. That is the entire
       cause of the 113px of horizontal scroll measured at 982px, and of the
       KPI tiles collapsing to 88px at 820px while the row still overflowed.
       Fixing it here fixes every call site at once, with no markup changes.

       .rg-5 additionally becomes auto-fit so it reflows on its own rather than
       waiting for a breakpoint to rescue it.

       .rg-4 deliberately does NOT use auto-fit. It always holds four KPI tiles,
       and auto-fit resolves to whatever count fits — which at the real content
       width (700px, once the work-plan rail and sidebar take 480px) is three.
       Four tiles in three columns orphans the fourth onto its own row, which is
       exactly what was on screen: a 3-up row with a stray card beneath it.
       Raising the floor only moves the breakage to a different width, because
       auto-fit cannot express "never three when I hold four".

       So the column count is stated explicitly and skips 3 entirely: 4 across
       when there is genuinely room, otherwise a balanced 2×2, and 1 on phones.
       A 2×2 is never lopsided, and at this width its tiles are far more legible
       than four cramped 157px ones would have been. */
    .rg-4   { display:grid; grid-template-columns:repeat(2,minmax(0,1fr));           gap:var(--sp-4); margin-bottom:var(--sp-6) }
    /* Four across from 1280px, not 1560. At 1440 the content column is ~1096px
       after the 248px sidebar and 2x48 padding, so four tiles land at ~256px —
       and the old threshold meant a 1440px laptop, the common case here, showed
       four measurements as a 2x2 block eating ~280px of height. The tiles are
       their own dense component now (.kpi) rather than generic padded cards, so
       they no longer need the room the old threshold was reserving. */
    @media (min-width:1280px){ .rg-4 { grid-template-columns:repeat(4,minmax(0,1fr)) } }
    .rg-3s  { display:grid; grid-template-columns:repeat(3,minmax(0,1fr));            gap:var(--sp-2)                            }
    .rg-3m  { display:grid; grid-template-columns:repeat(3,minmax(0,1fr));            gap:var(--sp-3); margin-bottom:var(--sp-4) }
    .rg-3w  { display:grid; grid-template-columns:repeat(3,minmax(0,1fr));            gap:var(--sp-3); margin-bottom:var(--sp-4) }
    .rg-2   { display:grid; grid-template-columns:repeat(2,minmax(0,1fr));            gap:var(--sp-6); margin-bottom:var(--sp-6) }
    .rg-2x  { display:grid; grid-template-columns:repeat(2,minmax(0,1fr));            gap:var(--sp-6)                            }
    .ct-full { margin-bottom: var(--sp-6); }
    .ct-pair { align-items: start; }
    .rg-main{ display:grid; grid-template-columns:minmax(0,1fr) minmax(0,340px);      gap:var(--sp-6); margin-bottom:var(--sp-6) }
    .rg-auto{ display:grid; grid-template-columns:repeat(auto-fill,minmax(180px,1fr)); gap:var(--sp-4)                           }
    .rg-5   { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:var(--sp-3)                            }
    .rg-yt2 { display:grid; grid-template-columns:repeat(2,minmax(0,1fr));            gap:var(--sp-5)                            }

    /* Table scroll wrapper */
    .tbl-scroll { overflow-x:auto; -webkit-overflow-scrolling:touch }
    .tbl-scroll .dash-table { min-width:480px }

    /* Pipeline scroll wrapper */
    .pipe-wrap { overflow-x:auto; -webkit-overflow-scrolling:touch; padding-bottom:4px }

    /* Mobile tab bar */
    /* A bottom bar, not a top strip.
       Four destinations plus More now, so it no longer needs to scroll — the
       twenty-four-item scroller it replaced put 1338px of navigation off-screen
       at 390px. Bottom because that is where a thumb is: on a 844px phone the
       top of the screen is the hardest place to reach one-handed, and this is
       the only navigation under 768px.
       inset-inline, not left/right — the dashboard is Hebrew. */
    #mobile-tabs {
      display: none;
      position: fixed;
      inset-inline: 0;
      bottom: 0;
      z-index: 29;
      /* Translucent material, not an opaque bar: content can be seen (and
         still legible, via vibrancy on --text/--text-2) scrolling underneath
         for the instant this bar is visible during a tab transition. --glass-
         strong (76% white), not --glass (58%) — a persistent structural nav
         reads as a thicker material than a transient overlay. Falls back to
         solid --surface + no blur under prefers-reduced-transparency below. */
      /* 97% of the theme surface, not --glass-strong (76%). At 76% the page
         text under the bar stayed legible through it: measured on WebKit at
         390px, "מה אתם מוכרים" and a paragraph line ran straight through the
         tab labels, because the blur below did not take effect in that
         capture — a blur cannot be the thing that keeps labels readable.
         Built on --surface so dark mode follows the theme. The solid line
         first is the fallback for a browser without color-mix(). */
      background: var(--surface);
      border-top: 1px solid var(--border);
      /* One track per destination. No count is written here: the bar renders
         whatever renderMobileTabBar() gives it, which is the operator's own
         first four plus More. A hardcoded repeat() is what put eight columns
         under four tabs in the customer portal.

         `display` is NOT set here. It is `none` three lines up, and a second
         display in the same rule silently wins — which showed the phone bar on
         a 1024px desktop. The mobile breakpoint turns it into a grid. */
      grid-auto-flow: column;
      grid-auto-columns: 1fr;
      /* Clear of the home indicator; 0 where there is no inset. */
      padding-bottom: var(--safe-bottom, 0px);
      box-shadow: 0 -2px 18px rgb(0 0 0 / .06);
    }

    /* Keyboard users get the focus ring inside the fade, not under it. */
    #mobile-tabs .mob-tab:focus-visible { outline:2px solid var(--accent); outline-offset:-2px }

    .mob-tab {
      /* Icon over label, the shape a thumb reads at a glance. Stacked rather
         than inline because a five-across bar gives each destination ~78px at
         390px, and an icon beside a Hebrew label does not fit that twice. */
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 3px;
      padding: 6px 4px;
      /* min-height, not height: with #sidebar display:none !important at 768px
         this bar is the ONLY navigation on a phone, and 42px is under the
         44px touch floor this file enforces everywhere else. A fixed height
         also clips a wrapped label instead of growing. */
      min-height: 52px;
      font-size: var(--fs-100, 11px);
      font-weight: 600;
      color: var(--text-2);
      background: none;
      border: none;
      cursor: pointer;
      /* The active marker moved to the top edge with the bar. A bottom border
         on a bottom bar sits under the home indicator where nobody sees it. */
      border-top: 2px solid transparent;
      white-space: nowrap;
      transition:color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out),
        transform var(--dur-fast) var(--ease-out);
    }
    .mob-tab-ico { display:grid; place-items:center; width:20px; height:20px; line-height:1 }
    .mob-tab-ico svg { width:20px; height:20px; display:block }
    .mob-tab-lbl { max-width:100%; overflow:hidden; text-overflow:ellipsis }
    .mob-tab:hover { color: var(--text) }
    .mob-tab.active { color: var(--accent); border-top-color: var(--accent) }
    .mob-tab:focus-visible { outline:2px solid var(--accent); outline-offset:-2px }
    /* This bar is the only navigation a phone has, and until now tapping it
       gave zero feedback until the tab had actually switched — a real render
       delay read as a dead button. Respond on press, same convention
       .flow-card:active already uses (scale(0.97)); a touch target this
       small reads better a little more compressed. */
    .mob-tab:active { transform: scale(0.93); }

    /* The rest of the navigation, inside the sheet this file already has. */
    .nav-sheet-list { display:flex; flex-direction:column; gap:2px }

    /* Section headers inside the overflow sheet. On a phone the strip carries
       four tabs and this panel carries the other twenty-one, so this list is
       the navigation and it needed the same six sections the sidebar has.

       No hairline here, unlike .nav-group-label in the sidebar: the sheet rows
       are full-bleed and a rule running to the panel edge reads as a divider
       between two lists rather than a label for the one below it. Space and
       weight do the same job with nothing to align. */
    .nav-sheet-group {
      padding: 14px 12px 4px;
      font-size: var(--fs-100);
      font-weight: 600;
      color: var(--text-3);
    }

    /* The first header sits directly under the sheet title, which brings its
       own spacing. */
    .nav-sheet-group:first-child { padding-block-start: 2px; }
    .nav-sheet-item {
      display:flex; align-items:center; gap:12px; width:100%;
      min-height:48px; padding:10px 12px; border-radius:10px;
      border:0; background:none; cursor:pointer; text-align:start;
      font-size:var(--fs-200); font-weight:500; color:var(--text);
      font-family:inherit;
    }
    .nav-sheet-item:hover { background:var(--surface-2, rgb(0 0 0 / .04)) }
    .nav-sheet-item.active { color:var(--accent); font-weight:600 }
    .nav-sheet-item:focus-visible { outline:2px solid var(--accent); outline-offset:-2px }
    .nav-sheet-ico { display:grid; place-items:center; width:20px; height:20px; flex:none }
    .nav-sheet-ico svg { width:20px; height:20px; display:block }
    .nav-sheet-customise { margin-top:6px; border-top:1px solid var(--border); border-radius:0; padding-top:14px }

    /* ── Mobile breakpoint ───────────────────────────────────────────────── */
    @media (max-width: 768px) {
      /* Layout chrome */
      #sidebar     { display:none !important }
      /* grid, matching the base rule — one track per destination. `flex` here
         beat `display:grid` above on !important, so the bar laid itself out
         as a 754px-tall column instead of a five-across bar. */
      #mobile-tabs { display:grid !important }
      #topbar      { left:0 !important; right:0 !important }
      #content-wrap {
        margin-left: 0 !important;
        margin-right: 0 !important;
        /* The nav moved to the bottom, so the content no longer starts 42px
           below the header — it ends above the bar instead.

           One shorthand, deliberately. `padding-bottom` used to be declared
           here and then `padding:16px !important` on the next line reset it:
           same selector, same importance, shorthand last, so the shorthand
           won and the reservation silently evaluated to 16px. Measured in
           Chromium at 390px: computed padding-bottom was 16px against a 54px
           fixed bar, so the bar covered the last ~38px of every page on every
           phone. Keep this as ONE declaration — a longhand next to a
           shorthand is exactly how it broke. */
        margin-top: var(--header-h) !important;
        padding: 16px 16px calc(var(--mobile-nav-h) + 12px) !important;
      }

      /* Collapse 2-col / main layouts → single column */
      .rg-2, .rg-2x, .rg-main, .rg-yt2 {
        grid-template-columns: minmax(0, 1fr) !important;
        gap: 12px !important;
        margin-bottom: 16px !important;
      }

      /* 4-col → 2-col (KPIs, platform cards, media stats) */
      .rg-4 { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap:12px !important }
      /* .rg-3* was the one family this block never rewrote. Three columns at
         375px is ~107px each — narrower than the KPI tiles that were already
         judged unreadable at 88px. Two columns, same as .rg-4 beside it. */
      .rg-3s, .rg-3m, .rg-3w { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap:10px !important }
      /* minmax(0,1fr) stopped .cs-tiles overflowing, but three tracks in 375px
         is 119px each — measured. This file already treats 88px tiles as
         unreadable; 119px is the same problem with a smaller number. */
      .cs-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)) !important }

      /* 5-col → 2-col */
      .rg-5 { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap:10px !important }

      /* Auto-fill: tighter minimum */
      .rg-auto { grid-template-columns:repeat(auto-fill,minmax(140px,1fr)) !important; gap:12px !important }

      /* Card padding */
      .ea-card-pad { padding:16px !important }

      /* Typography */
      .page-hdr { margin-bottom:16px !important }
      .page-hdr h1 { font-size:var(--fs-300) !important }
      .kpi-num { font-size:var(--fs-400) !important }

      /* Agent row: wrap, hide long action text */
      .agent-row { flex-wrap:wrap; gap:6px; padding:12px 0 }
      .agent-action-text { display:none !important }

      /* Run Swarm: hide label, show icon only */
      #btn-run-label { display:none !important }

      /* Header: tighter padding */
      #topbar { padding:0 14px !important }

      /* Modals: tighter */
      #modal-inner { border-radius:10px }
    }

    /* ── Tablet: touch, but wide enough to clear the phone breakpoint ──────
       Measured at 820px (iPad Air portrait): nothing above fires here (it
       all stops at max-width:768px), so a touch tablet fell straight through
       to the desktop layout — a 208px fixed sidebar with 20 densely-packed
       nav rows, no bottom tab bar, on a screen with no mouse to work it
       precisely. A phone never gets a sidebar at all; a tablet got one and
       nothing else.

       Chrome only — NOT the grid-collapsing/typography-shrinking rules
       above. Those exist because a phone genuinely lacks the width for a
       4-column KPI grid; an 820-1024px touch screen does not have that
       problem, so .rg-4 etc. stay exactly as the desktop rules leave them.

       Keyed on pointer:coarse AND width, deliberately, matching the existing
       convention a few hundred lines down (see the touch-target-floor
       comment there): pointer:coarse alone would also fire for width, so
       min-width:769px keeps this from double-applying under the 768px block
       above; requiring pointer:coarse (not width alone) keeps an ordinary
       narrow DESKTOP browser window — mouse, no coarse pointer — on its
       sidebar, since that user has the precision a fixed 208px rail needs
       and did not ask for a phone-style bottom bar. */
    @media (pointer:coarse) and (min-width:769px) and (max-width:1024px) {
      #sidebar     { display:none !important }
      #mobile-tabs { display:grid !important }
      #topbar      { left:0 !important; right:0 !important }
      #content-wrap {
        margin-left: 0 !important;
        margin-right: 0 !important;
        margin-top: var(--header-h) !important;
        padding: 16px 16px calc(var(--mobile-nav-h) + 12px) !important;
      }
    }

    /* .rg-4 states its columns explicitly (2 by default, 4 above 1280px), so
       this override is what drops it to a single column on the narrowest
       phones.

       Moved 400px → 360px. The 400px threshold was chosen when .kpi-num was
       32px everywhere, and it catches the two commonest phones in service —
       a 390pt iPhone and a 393pt Pixel both fall under it. Measured at 390px:
       the "מדדים" row stacked its four tiles into 642px, pushing every widget
       after the KPIs off an 844px screen, and that was a large part of why
       the Overview ran to twenty screens. .kpi-num is already --fs-400 (24px)
       below 768px, so a ~170px tile is not the cramped case this threshold
       was protecting against — 642px of stacked tiles is the worse one.
       Below 360px (a 320pt SE) one column is still right. */
    @media (max-width: 360px) {
      .rg-4 { grid-template-columns:minmax(0, 1fr) !important }
    }

    /* ── Tooltip system ─────────────────────────────────────────────── */
    .tt-btn {
      width: 17px; height: 17px;
      border-radius: 50%;
      background: var(--surface-2);
      border: 1px solid var(--border-2);
      color: var(--text-3);
      font-size: var(--fs-100);
      font-weight: 700;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      flex-shrink: 0;
      position: relative;
      transition:background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
      line-height: 1;
      vertical-align: middle;
    }
    .tt-btn:hover {
      background: rgba(14,165,233,.12);
      color: var(--accent);
      border-color: var(--accent);
    }
    .tt-wrap { display:inline-flex; align-items:center; gap:8px; position:relative; }
    .tt-card {
      display: none;
      position: absolute;
      right: 0;
      top: calc(100% + 7px);
      z-index: 200;
      background: var(--surface-2);
      border: 1px solid var(--border-2);
      border-radius: 8px;
      padding: 10px 12px;
      font-size: var(--fs-100);
      line-height: 1.6;
      color: var(--text-2);
      box-shadow: 0 8px 32px rgba(0,0,0,.55);
      width: 280px;
      pointer-events: none;
      font-weight: 400;
      text-transform: none;
      letter-spacing: 0;
    }
    .tt-wrap:hover .tt-card,
    .tt-wrap:focus-within .tt-card { display: block; }
    .tt-banner {
      margin: -10px 0 16px;
      padding: 10px 12px;
      background: rgba(14,165,233,.06);
      border: 1px solid rgba(14,165,233,.15);
      border-radius: 7px;
      font-size: var(--fs-200);
      line-height: 1.6;
      color: var(--text-2);
      font-weight: 400;
      text-transform: none;
      letter-spacing: 0;
    }
    @keyframes tt-in {
      from { opacity:0; transform:translateY(-4px); }
      to   { opacity:1; transform:translateY(0); }
    }
    .tt-banner.open { animation: tt-in .16s ease; }

    /* Hebrew content container */
    .he-content {
      direction: rtl;
      font-family: 'Rubik', sans-serif;
      text-align: right;
      unicode-bidi: embed;
    }

    /* warm / purple / midnight theme blocks removed — light only. */

    /* ── LAYOUT: PREMIUM MINIMALIST (Apple) ──────────────────────────── */
    body.layout-premium { letter-spacing:-.01em; }
    body.layout-premium .card {
      border:none !important;
      box-shadow:0 0 0 1px var(--surface-2), 0 8px 32px rgba(0,0,0,.35) !important;
      border-radius:18px !important;
      padding:28px !important;
    }
    body.layout-premium .agent-grid { gap:20px !important; }
    body.layout-premium .card-title { font-size:var(--fs-200) !important; font-weight:500 !important; letter-spacing:-.025em !important; }
    body.layout-premium .section-label { font-size:var(--fs-100) !important; letter-spacing:.12em !important; text-transform:uppercase !important; opacity:.5 !important; }
    body.layout-premium h2,body.layout-premium h3 { font-weight:300 !important; }

    /* ── LAYOUT: COMPACT ─────────────────────────────────────────────── */
    body.layout-compact .card { padding:10px 12px !important; border-radius:6px !important; }
    body.layout-compact .card-title { font-size:var(--fs-100) !important; }
    body.layout-compact .agent-grid { gap:5px !important; grid-template-columns:repeat(auto-fill,minmax(180px,1fr)) !important; }
    body.layout-compact .section-label { font-size:var(--fs-100) !important; margin-bottom:6px !important; }
    body.layout-compact .stage-card { padding:6px 8px !important; font-size:var(--fs-100) !important; }

    /* ── MOBILE DROPDOWN FIX ─────────────────────────────────────────── */
    @media (max-width:768px) {
      .client-dropdown {
        position:fixed !important;
        top:58px !important;
        left:12px !important;
        right:12px !important;
        width:auto !important;
        z-index:9999 !important;
        max-height:55vh;
        overflow-y:auto;
        -webkit-overflow-scrolling:touch;
      }
      .client-selector { position:static !important; }
      /* No min-width. It was written for the horizontal scroller, where a wider
         tab simply pushed the next one along. The bar is a five-column grid
         now, so a 72px floor demands 360px and overflows a 320px phone — the
         same arithmetic that put eight 64px tracks under four tabs in the
         customer portal. 320/5 = 64px per destination, which clears the 44px
         touch floor on its own. */
      .mob-tab { padding:8px 4px !important; }
    }

    /* ── CHARTS ──────────────────────────────────────────────────────── */
    .ea-chart-wrap { position:relative; display:flex; align-items:center; justify-content:center; }
    .ea-donut-label { position:absolute; text-align:center; pointer-events:none; }
    .ea-bar-row { display:flex; align-items:center; gap:8px; margin-bottom:6px; }
    .ea-bar-bg { flex:1; height:6px; border-radius:var(--r-xs); background:var(--surface-3); overflow:hidden; }
    .ea-bar-fill { height:100%; border-radius:3px; transition:width .6s cubic-bezier(.4,0,.2,1); }

    /* .card had zero standalone usages — every hit was ea-card/dna-card etc.
       Its two rules also paired a hairline with a wide diffuse shadow and used
       var(--surface-2), a dark-theme value invisible on white. Deleted;
       .ea-card owns card elevation. */
    .stat-big { font-size:var(--fs-400); font-weight:700; letter-spacing:-.04em; line-height:1; }
    .stat-label { font-size:var(--fs-100); color:var(--text-3); margin-top:3px; letter-spacing:.04em; text-transform:uppercase; }


    /* ── PREMIUM MOBILE ACCOUNT SWITCHER ─────────────────────────────── */
    #mob-client-bar {
      display: none;               /* hidden on desktop */
    }
    @media (max-width: 768px) {
      #mob-client-bar {
        display: flex;
        align-items: center;
        flex: 1;
        justify-content: center;
        padding: 0 4px;
      }

      /* Wrapper gives us the pill shape + glass bg */
      .mob-switcher-wrap {
        position: relative;
        display: flex;
        align-items: center;
        width: 100%;
        max-width: 260px;
        height: 44px;
        background: var(--surface-2);
        border: 1px solid rgba(255,255,255,.10);
        border-radius: 14px;
        overflow: hidden;
        transition:border-color var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out);
      }
      .mob-switcher-wrap:focus-within {
        border-color: var(--accent, var(--status-running));
        background: rgba(255,255,255,.11);
      }

      /* Arrow icon on the right */
      .mob-switcher-wrap::after {
        content: '';
        position: absolute;
        right: 14px;
        top: 50%;
        transform: translateY(-50%);
        width: 0;
        height: 0;
        border-left: 4px solid transparent;
        border-right: 4px solid transparent;
        border-top: 5px solid var(--text-2, var(--text-3));
        pointer-events: none;
      }

      /* The actual select — invisible chrome, fills wrapper */
      /* #mob-client-select is a <button> now, not a <select> — a native
         <option> can only render text (plus, on some platforms, an emoji
         glyph), so there was no way to show a real client photo in it. The
         button opens #mob-client-dropdown instead, same real-photo-or-
         initials tile as the roster's own client cards. */
      .mob-switcher-btn {
        -webkit-appearance: none;
        appearance: none;
        width: 100%;
        height: 100%;
        display: flex;
        align-items: center;
        gap: 8px;
        background: transparent;
        border: none;
        outline: none;
        padding: 0 36px 0 14px;
        font-size: var(--fs-200);
        font-weight: 600;
        font-family: 'Rubik', -apple-system, sans-serif;
        color: var(--text, var(--text));
        cursor: pointer;
        letter-spacing: -.01em;
        text-align: start;
        /* Remove default mobile styling */
        -webkit-tap-highlight-color: transparent;
      }
      .mob-switcher-label {
        flex: 1;
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      /* Hide desktop client selector & sidebar on mobile (topbar carries the switcher) */
      #sb-client-wrap { display: none !important; }

      /* Hide desktop topbar left text on mobile, show the switcher instead */
      #hdr-left { display: none !important; }
    }

    /* ── CLIENT ONBOARDING MODAL ─────────────────────────────────────── */
    #onboard-modal {
      position: fixed; inset: 0; z-index: 200;
      background: rgba(12,18,17,.6);
      display: flex; align-items: center; justify-content: center;
      padding: 20px;
    }
    #onboard-modal.hidden { display: none; }
    #onboard-inner {
      background: var(--surface, #111113);
      border: 1px solid var(--border, #27272a);
      border-radius: 18px;
      padding: 28px;
      width: 100%;
      max-width: 480px;
      max-height: 92vh;
      overflow-y: auto;
    }
    .ob-title {
      font-size: var(--fs-300); font-weight: 700; color: var(--text, var(--text));
      margin-bottom: 4px;
    }
    .ob-sub {
      font-size: var(--fs-200); color: var(--text-3, var(--text-2));
      margin-bottom: 20px;
    }
    .ob-field { margin-bottom: 14px; }
    .ob-label {
      display: block; font-size: var(--fs-100); font-weight: 600;
      color: var(--text-2, var(--text-3)); margin-bottom: 5px;
      text-transform: uppercase; letter-spacing: .05em;
    }
    .ob-input, .ob-select {
      width: 100%; height: 42px; padding: 0 12px;
      background: var(--surface);
      border: 1px solid var(--border-control);
      border-radius: var(--r-lg);
      color: var(--text);
      font-size: var(--fs-200); font-family: inherit;
      outline: none;
      transition:border-color var(--dur-base) var(--ease-out);
      box-sizing: border-box;
    }
    .ob-input:focus, .ob-select:focus {
      border-color: var(--accent, var(--status-running));
    }
    .ob-select { -webkit-appearance: none; cursor: pointer; }
    .ob-row { display: flex; gap: 10px; }
    .ob-row .ob-field { flex: 1; }
    .ob-submit-btn {
      width: 100%; height: 46px;
      background: var(--accent, var(--status-running));
      color: var(--on-accent); border: none; border-radius: 12px;
      font-size: var(--fs-200); font-weight: 700; font-family: inherit;
      cursor: pointer; margin-top: 6px;
      transition:opacity var(--dur-base) var(--ease-out);
    }
    .ob-submit-btn:disabled { opacity: .5; cursor: default; }
    .ob-cancel {
      display: block; text-align: center;
      font-size: var(--fs-200); color: var(--text-3, var(--text-2));
      margin-top: 12px; cursor: pointer;
    }
    .ob-cancel:hover { color: var(--text-2, var(--text-3)); }



    /* ── Clients tab ───────────────────────────────────────────────────────
       Customer + client management. The backend has had full CRUD since
       lib/accounts.py landed (/api/admin/clients, /api/admin/customers,
       /api/admin/invites) and this dashboard had no UI for any of it — the
       markup lived in client_dashboard.js, a file Flask never serves. */
    .cl-grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(300px,1fr))}
    .cl-card{
      background:var(--surface);border:1px solid var(--border-2);border-radius:14px;
      padding:16px;display:flex;flex-direction:column;gap:10px;
      transition:border-color var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
      /* Same entrance stagger as .dna-card, same reasoning: fires once per
         render of the grid, never rapidly re-triggered. */
      animation: ea-card-in var(--dur-slow) var(--ease-out) both;
    }
    .cl-card:hover{border-color:var(--accent);box-shadow:0 6px 20px rgba(9,9,11,.07)}
    .cl-grid > .cl-card:nth-child(1) { animation-delay: 0ms; }
    .cl-grid > .cl-card:nth-child(2) { animation-delay: 35ms; }
    .cl-grid > .cl-card:nth-child(3) { animation-delay: 70ms; }
    .cl-grid > .cl-card:nth-child(4) { animation-delay: 105ms; }
    .cl-grid > .cl-card:nth-child(5) { animation-delay: 140ms; }
    .cl-grid > .cl-card:nth-child(6) { animation-delay: 175ms; }
    .cl-grid > .cl-card:nth-child(7) { animation-delay: 210ms; }
    .cl-grid > .cl-card:nth-child(n+8) { animation-delay: 245ms; }
    @media (prefers-reduced-motion: reduce) {
      .cl-card { animation: none; }
    }
    /* Real hero_bg media asset from 06_media_manifest.json, fetched lazily
       per card. No stock photo ever fills this slot — a client with no
       generated media renders no .cl-cover at all, not a placeholder image. */
    .cl-cover{
      margin:-16px -16px 0;border-radius:14px 14px 0 0;overflow:hidden;
      aspect-ratio:16/6;background:var(--surface-2);
    }
    .cl-cover img{width:100%;height:100%;object-fit:cover;display:block}
    .cl-top{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
    /* Deterministic per-client color + initials — same "verified mark, else
       initials, never a guess" rule the platform brand marks use. There is
       no logo field in config.json, so this is the honest default, not a
       stand-in for one. */
    /* Same tile as .cl-avatar/.cl-cover, sized for the switcher rows (the
       mobile trigger button and the .client-opt dropdown rows on both
       surfaces) rather than the wider client cards. */
    .sw-avatar{
      flex:none;width:22px;height:22px;border-radius:7px;object-fit:cover;
    }
    .sw-avatar--txt{
      display:flex;align-items:center;justify-content:center;
      font-size:11px;font-weight:700;color:var(--cl-hue,var(--viz-1));
      background:color-mix(in srgb, var(--cl-hue,var(--viz-1)) 16%, var(--surface));
    }
    .cl-avatar{
      flex:none;width:38px;height:38px;border-radius:10px;display:flex;
      align-items:center;justify-content:center;font-size:var(--fs-200);
      font-weight:700;color:color-mix(in srgb, var(--cl-hue,var(--viz-1)) 80%, var(--text));
      background:color-mix(in srgb, var(--cl-hue,var(--viz-1)) 16%, var(--surface));
    }
    .cl-top-main{display:flex;align-items:flex-start;gap:10px;min-width:0}
    .cl-name{font-size:var(--fs-200);font-weight:700;color:var(--text);line-height:1.3}
    .cl-meta{font-size:var(--fs-200);color:var(--text-3);margin-top:2px}
    /* An ID is one unbreakable token: at the 11px floor a 17-char ID is 113px
       against a 110px board column on a phone. Wrap it anywhere rather than
       ellipsize — the tail is what tells altman from altman2. */
    .cl-id{font-family:ui-monospace,Menlo,monospace;font-size:var(--fs-100);color:var(--text-3);overflow-wrap:anywhere}
    .cl-bar{height:6px;border-radius:99px;background:var(--border-2);overflow:hidden}
    .cl-bar>i{display:block;height:100%;background:var(--accent);border-radius:99px}
    .cl-stats{display:flex;gap:14px;font-size:var(--fs-200);color:var(--text-2);flex-wrap:wrap}
    .cl-stats b{color:var(--text);font-variant-numeric:tabular-nums}
    .cl-acts{display:flex;gap:6px;flex-wrap:wrap;margin-top:2px}

    /* Monday-style board: grouped, colored-band rows replacing the card grid. */
    .board-group{margin-bottom:18px}
    .board-group__hdr{display:flex;align-items:center;gap:8px;margin-bottom:8px;padding:0 4px}
    .board-group__dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
    .board-group__title{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-2)}
    .board-group__count{font-size:11px;color:var(--text-3)}
    .board-group__rows{display:flex;flex-direction:column;gap:6px}
    .board-row{
      display:flex;align-items:center;gap:12px;flex-wrap:wrap;
      background:var(--surface);border:1px solid var(--border-2);
      border-inline-start:3px solid var(--text-3);border-radius:10px;padding:10px 14px;
      transition:box-shadow var(--dur-fast) var(--ease-out);
    }
    .board-row:hover{box-shadow:0 4px 14px rgba(9,9,11,.06)}
    .board-row__main{display:flex;align-items:center;gap:10px;flex:1 1 240px;min-width:min(240px,100%)} /* floor: actions wrap below, the name is never crushed */
    .board-row__primary{display:flex;align-items:center;gap:10px;min-width:0}
    .board-row__secondary{font-size:var(--fs-100);color:var(--text-3)}
    .board-row__meta,.board-row__pill,.board-row__actions{flex-shrink:0}
    .board-row__actions{display:flex;gap:6px;flex-wrap:wrap}
    .board-row__expanded{margin:-4px 0 6px;padding:10px 14px;background:var(--surface-2);border-radius:0 0 10px 10px}
    @media (max-width:640px){
      .board-row{flex-direction:column;align-items:stretch}
      .board-row__meta,.board-row__pill,.board-row__actions{width:100%}
    }

    /* Account rows inside the expanded client */
    .acct-row{
      display:flex;align-items:center;gap:10px;padding:9px 0;
      border-top:1px solid var(--border-2);font-size:var(--fs-200);
    }
    .acct-row:first-of-type{border-top:0}
    .acct-mail{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;
      white-space:nowrap;direction:ltr;text-align:start;color:var(--text)}

    /* Forms */
    .f-row{display:flex;flex-direction:column;gap:5px;margin-bottom:12px}
    .f-row label{font-size:var(--fs-200);font-weight:600;color:var(--text-2)}
    .f-row input,.f-row select{
      height:38px;padding:0 11px;border-radius:9px;
      border:1px solid var(--border-control);background:var(--surface);color:var(--text);
      font-family:inherit;font-size:var(--fs-200);width:100%;
    }
    .f-row input:focus,.f-row select:focus{
      outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
    .f-row .hint{font-size:var(--fs-100);color:var(--text-3)}
    .f-err{color:var(--r);font-size:var(--fs-200);margin:6px 0 0;min-height:16px}

    .ea-btn{
      /* Without this, a <button type="submit"> that is a form's :default
         gets native OS chrome instead of the CSS below — on macOS/WebKit
         that's System Indigo (#5e5ce6), which is exactly why the login
         screen's "כניסה" button rendered purple/indigo while every other
         .ea-btn on the page (never a form default) rendered correctly. */
      appearance:none;-webkit-appearance:none;
      height:34px;padding:0 13px;border-radius:9px;cursor:pointer;
      border:1px solid var(--border);background:var(--surface);color:var(--text);
      font-family:inherit;font-size:var(--fs-200);font-weight:600;
      display:inline-flex;align-items:center;gap:6px;
      transition:background var(--dur-fast) var(--ease-out), transform var(--dur-base) var(--ease-out);
    }
    .ea-btn:hover{background:var(--surface-2)}
    .ea-btn:active:not(:disabled){transform:scale(0.97)}
    .ea-btn--primary{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
    .ea-btn--primary:hover{opacity:.9;background:var(--accent)}
    .ea-btn--danger{color:var(--r);border-color:var(--r)}
    .ea-btn:disabled{opacity:.5;cursor:not-allowed}

    /* Slide-over used for every form here. Overlay is a real <div> so a click
       outside closes it, and Escape is bound in JS — a form you cannot dismiss
       with the keyboard is a form people learn to avoid. */
    .sheet-back{
      position:fixed;inset:0;background:rgba(9,9,11,.42);z-index:120;
      opacity:0;visibility:hidden;transition:opacity var(--dur-base) var(--ease-out), visibility var(--dur-base) var(--ease-out);
    }
    .sheet-back.open{opacity:1;visibility:visible}
    .sheet{
      position:fixed;top:0;inset-inline-end:0;height:100%;width:min(420px,100%);
      background:var(--surface);border-inline-start:1px solid var(--border-2);
      z-index:121;display:flex;flex-direction:column;
      transform:translateX(var(--sheet-out,100%));transition:transform var(--dur-base) var(--ease-drawer);
      box-shadow:-12px 0 40px rgba(9,9,11,.12);
    }
    .sheet.sheet--customer-layout{width:min(720px,100%)}
    html[dir="rtl"] .sheet{--sheet-out:-100%}
    .sheet.open{transform:translateX(0)}
    .sheet-hd{display:flex;align-items:center;gap:10px;padding:16px 18px;
      border-bottom:1px solid var(--border-2)}
    .sheet-hd h3{margin:0;font-size:var(--fs-200);font-weight:700;flex:1;color:var(--text)}
    .sheet-bd{padding:18px;overflow-y:auto;flex:1}
    .sheet-ft{padding:14px 18px;border-top:1px solid var(--border-2);
      display:flex;gap:8px;justify-content:flex-end}

    /* Customer-home composition is edited as a compact ordered document.
       The controls describe real presentation choices; arrow buttons remain
       keyboard-safe without adding a drag-and-drop dependency. */
    .customer-layout-loading,.customer-layout-error{
      min-height:180px;display:grid;place-items:center;text-align:center;
      color:var(--text-3);font-size:var(--fs-200)
    }
    .customer-layout-error{color:var(--r)}
    .customer-layout-intro{
      padding:14px 15px;border:1px solid var(--border-2);border-radius:12px;
      background:var(--surface-2);margin-bottom:14px
    }
    .customer-layout-intro b{display:block;color:var(--text);font-size:var(--fs-200)}
    .customer-layout-intro p{margin:5px 0 7px;color:var(--text-2);font-size:var(--fs-200);line-height:1.6}
    .customer-layout-intro span{color:var(--text-3);font-size:var(--fs-100)}
    .customer-layout-list{display:flex;flex-direction:column;gap:9px}
    .customer-layout-row{
      display:grid;grid-template-columns:auto minmax(150px,.7fr) minmax(260px,1.3fr);
      gap:12px;align-items:start;padding:12px;border:1px solid var(--border-2);
      border-radius:12px;background:var(--surface);transition:opacity var(--dur-fast) var(--ease-out)
    }
    .customer-layout-row.is-hidden{opacity:.56;background:var(--surface-2)}
    .customer-layout-order{display:flex;flex-direction:column;gap:4px}
    .customer-layout-order button{
      width:28px;height:25px;border:1px solid var(--border-control);border-radius:7px;
      background:var(--surface);color:var(--text-2);cursor:pointer;font:700 13px/1 system-ui
    }
    .customer-layout-order button:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}
    .customer-layout-order button:disabled{opacity:.3;cursor:default}
    .customer-layout-toggle{display:flex;align-items:center;gap:8px;min-height:31px;
      color:var(--text);font-size:var(--fs-200);font-weight:700;cursor:pointer}
    .customer-layout-toggle input{accent-color:var(--accent);width:16px;height:16px}
    .customer-layout-toggle small{font-size:11px;color:var(--text-3);font-weight:600}
    .customer-layout-fields{display:grid;grid-template-columns:minmax(0,1fr) minmax(110px,.55fr);gap:8px}
    .customer-layout-fields label{font-size:11px;font-weight:650;color:var(--text-3)}
    .customer-layout-fields input,.customer-layout-fields select,.customer-layout-fields textarea{
      display:block;width:100%;margin-top:4px;border:1px solid var(--border-control);
      border-radius:8px;background:var(--surface);color:var(--text);font:inherit;font-size:12px
    }
    .customer-layout-fields input,.customer-layout-fields select{height:33px;padding:0 9px}
    .customer-layout-fields textarea{min-height:64px;padding:8px;resize:vertical;line-height:1.45}
    .customer-layout-fields :is(input,select,textarea):focus{
      outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)
    }
    .customer-layout-wide{grid-column:1/-1}

    /* Launch intelligence on the agency overview. This is an operational
       brief: what is launching, which tension it answers, and what remains. */
    .agency-launch-card{border-color:color-mix(in srgb,var(--accent) 34%,var(--border-2));
      background:var(--surface)}
    .agency-launch-head{display:flex;justify-content:space-between;align-items:flex-start;gap:18px}
    .agency-launch-head h2{margin:3px 0 0;font-size:21px;letter-spacing:-.02em;color:var(--text)}
    .agency-launch-head small{display:block;margin-top:4px;color:var(--text-3);font-size:var(--fs-100)}
    .agency-launch-kicker{font-size:11px;font-weight:800;letter-spacing:.06em;color:var(--accent)}
    .agency-launch-actions{display:flex;align-items:center;justify-content:flex-end;gap:7px;flex-wrap:wrap}
    .agency-launch-brief{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:16px}
    .agency-launch-brief>div{padding:11px 12px;border:1px solid var(--border-2);border-radius:10px;background:var(--surface)}
    .agency-launch-brief b{display:block;font-size:11px;color:var(--text-3);margin-bottom:4px}
    .agency-launch-brief span{font-size:var(--fs-200);line-height:1.55;color:var(--text-2)}
    .agency-launch-outcomes{display:flex;gap:7px;flex-wrap:wrap;margin-top:11px}
    .agency-launch-outcomes span{padding:5px 9px;border-radius:99px;background:var(--surface);
      border:1px solid var(--border-2);font-size:11px;color:var(--text-2)}
    .agency-launch-foot{display:flex;gap:14px;justify-content:space-between;margin-top:13px;padding-top:11px;
      border-top:1px solid var(--border-2);font-size:var(--fs-100);color:var(--text-3)}
    .agency-launch-foot .is-warn{color:var(--status-warn)}
    @media (max-width:680px){
      .customer-layout-row{grid-template-columns:auto minmax(0,1fr)}
      .customer-layout-fields{grid-column:2;grid-template-columns:1fr}
      .customer-layout-wide{grid-column:auto}
      .agency-launch-head,.agency-launch-foot{flex-direction:column}
      .agency-launch-actions{justify-content:flex-start}
      .agency-launch-brief{grid-template-columns:1fr}
    }

    /* ── Stage detail drawer ─────────────────────────────────────────────
       Reuses .sheet/.sheet-back wholesale; only the inner list is new. This
       is the progressive-disclosure surface for the flow grid — the grid
       itself stays exactly as the reference composes it and everything
       per-stage opens here. */
    .sd-list{margin:0;display:flex;flex-direction:column;gap:0}
    .sd-row{
      display:flex;gap:12px;align-items:baseline;
      padding:9px 0;border-bottom:1px solid var(--card-line);
    }
    .sd-row:last-child{border-bottom:0}
    .sd-row dt{flex:0 0 116px;font-size:var(--fs-100);color:var(--text-3)}
    .sd-row dd{margin:0;flex:1;min-width:0;font-size:var(--fs-200);color:var(--text);
      word-break:break-word}
    .sd-row code{
      font-family:ui-monospace,Menlo,monospace;font-size:12px;
      background:var(--surface-2);padding:2px 6px;border-radius:4px;
      unicode-bidi:isolate;
    }
    .sd-unknown{color:var(--text-3);font-style:italic}
    /* Status is carried by a word, not only by the colour behind it. */
    .sd-badge{
      font-size:var(--fs-100);font-weight:600;padding:3px 9px;border-radius:99px;
      border:1px solid var(--card-line);color:var(--text-2);white-space:nowrap;
    }
    .sd-badge.is-done{color:var(--g);border-color:color-mix(in srgb,var(--g) 40%,var(--card-line))}
    .sd-badge.is-fail{color:var(--r);border-color:color-mix(in srgb,var(--r) 40%,var(--card-line))}
    .sd-badge.is-running{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 40%,var(--card-line))}
    .sd-badge.is-warn{color:var(--o);border-color:color-mix(in srgb,var(--o) 40%,var(--card-line))}
    .sd-badge.is-needs_writer{color:var(--o);border-color:color-mix(in srgb,var(--o) 40%,var(--card-line))}
    .sd-badge.is-redone{color:var(--o);border-color:color-mix(in srgb,var(--o) 40%,var(--card-line))}
    .sd-err{
      margin-top:14px;padding:12px;border-radius:10px;
      background:color-mix(in srgb,var(--r) 6%,var(--surface));
      border:1px solid color-mix(in srgb,var(--r) 30%,var(--card-line));
    }
    .sd-err strong{display:block;font-size:var(--fs-100);color:var(--r);margin-bottom:5px}
    .sd-err p{margin:0;font-size:12px;color:var(--text-2);white-space:pre-wrap;word-break:break-word}
    .sd-note{margin-top:16px;font-size:11.5px;color:var(--text-3);line-height:1.7}

    /* Visually hidden, still announced. Used by the flow filter's live region:
       the match count has to reach a screen-reader user, but printing it on
       screen would add a line the reference composition does not have.
       Not display:none — that removes it from the accessibility tree too. */
    .sr-only{
      position:absolute;width:1px;height:1px;padding:0;margin:-1px;
      overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
    }

    /* ── Codex usage (CodexBar) ───────────────────────────────────────────
       The sidebar row is a real button so it is reachable by keyboard, but it
       must sit flush with the non-interactive .sh-row siblings above it — a
       button that looks like a row and a row that looks like a button are
       both worse than one that simply matches. */
    /* Resets the button chrome ONLY. display/grid-template/gap are inherited
       from .sh-row, which a `display:block` button reset would have destroyed
       along with the three-column alignment the strip depends on. */
    .sh-row--btn{
      width:100%;font:inherit;color:inherit;background:none;border:0;
      padding:0;margin:0;cursor:pointer;text-align:inherit;
      appearance:none;-webkit-appearance:none;border-radius:6px;
    }
    .sh-row--btn:disabled{cursor:default;opacity:.65}
    .sh-row--btn:not(:disabled):hover{background:var(--surface-2)}
    .cx-win{margin-bottom:14px}
    .cx-win-hd{
      display:flex;justify-content:space-between;align-items:baseline;gap:10px;
      font-size:var(--fs-100);color:var(--text-2);margin-bottom:5px;
    }
    .cx-win-hd b{color:var(--text);font-size:var(--fs-200)}
    .cx-reset{font-size:11px;color:var(--text-3);margin-top:4px}
    .cx-note{
      margin:0 0 14px;padding:10px 12px;border-radius:10px;
      background:var(--surface-2);border:1px solid var(--card-line);
      font-size:12px;line-height:1.7;color:var(--text-2);
    }
    .cx-note code{
      display:block;margin-top:6px;font-family:ui-monospace,Menlo,monospace;
      font-size:11px;unicode-bidi:isolate;word-break:break-all;
    }

    /* Filter miss. role=status on the element itself, so a screen reader is
       told the grid emptied rather than being left on a silent page. */
    .flow-filter-note{
      margin-top:16px;padding:14px;text-align:center;
      font-size:var(--fs-200);color:var(--text-3);
      border:1px dashed var(--card-line);border-radius:12px;
    }

    /* One-time secret reveal. Deliberately loud: it is shown once and never
       retrievable, so it must not look like ordinary body copy. */
    .secret{
      background:var(--surface-2);border:1px dashed var(--accent);border-radius:10px;
      padding:12px;margin-top:12px;
    }
    .secret code{
      display:block;font-family:ui-monospace,Menlo,monospace;font-size:var(--fs-300);
      font-weight:700;color:var(--accent);direction:ltr;text-align:center;
      margin:8px 0;letter-spacing:.5px;user-select:all;
    }
    .secret .warn{font-size:var(--fs-100);color:var(--o)}

    /* Client search. Sits in the tab header, not a floating overlay — a search
       that moves the layout when it opens makes the list under it unreadable. */
    .cl-search{position:relative;display:flex;align-items:center}
    .cl-search input{
      height:34px;width:min(280px,52vw);padding:0 30px 0 30px;
      border:1px solid var(--border-control);border-radius:9px;
      background:var(--surface);color:var(--text);
      font-family:inherit;font-size:var(--fs-200);
    }
    .cl-search input:focus{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}
    .cl-search input::-webkit-search-cancel-button{display:none}
    .cl-search-ico{
      position:absolute;inset-inline-start:10px;font-size:var(--fs-200);color:var(--text-3);
      pointer-events:none;line-height:1;
    }
    .cl-search-x{
      position:absolute;inset-inline-end:7px;width:19px;height:19px;padding:0;
      border:0;border-radius:50%;cursor:pointer;
      background:var(--border-2);color:var(--text-2);font-size:var(--fs-100);line-height:1;
    }
    .cl-search-x:hover{background:var(--text-3);color:var(--surface)}

    /* ── Package menu, in the header ───────────────────────────────────────
       The tier cards used to be pinned in the left rail, on screen always for
       a decision made once. Here they cost a click. <details> gives the open
       and close behaviour, so nothing below is a state machine. */
    .tier-menu{ position:relative }
    .tier-summary{
      display:flex; align-items:center; gap:7px; cursor:pointer;
      padding:4px 10px; border:1px solid var(--border); border-radius:999px;
      background:var(--surface); list-style:none; user-select:none;
      font-size:var(--fs-200); line-height:1.3;
    }
    .tier-summary::-webkit-details-marker{ display:none }
    .tier-summary:hover{ border-color:var(--text-3) }
    .tier-name{ color:var(--text-2); font-weight:500 }
    .tier-price{ color:var(--text); font-weight:700; font-variant-numeric:tabular-nums }
    .tier-summary::after{
      content:'▾'; font-size:11px; color:var(--text-3); margin-inline-start:1px;
    }
    .tier-menu[open] .tier-summary::after{ content:'▴' }

    .tier-list{
      position:absolute; top:calc(100% + 6px); inset-inline-start:0; z-index:60;
      min-width:230px; display:flex; flex-direction:column; gap:2px; padding:6px;
      background:var(--surface); border:1px solid var(--border);
      border-radius:var(--r-lg, 12px); box-shadow:var(--shadow-md);
      /* inset-inline-start, not left: in RTL the menu hangs from the name's
         start edge, which is its right side. */
    }
    .tier-opt{
      display:flex; flex-direction:column; gap:2px; width:100%;
      padding:8px 10px; border:1px solid transparent; border-radius:8px;
      background:none; cursor:pointer; text-align:start;
      font-family:inherit; font-size:var(--fs-200);
    }
    .tier-opt:hover{ background:var(--bg) }
    .tier-opt.is-current{ border-color:var(--accent) }
    .tier-opt-head{ display:flex; align-items:baseline; justify-content:space-between; gap:12px }
    .tier-opt-name{ color:var(--text); font-weight:600 }
    .tier-opt-price{ color:var(--text); font-weight:700; font-variant-numeric:tabular-nums }
    .tier-opt-sub{ color:var(--text-3); font-size:var(--fs-100, 11px); line-height:1.4 }

    /* At 1024 and below the sidebar narrows (it was holding a fixed 220px
       all the way down to 768, squeezing content to 336px at 820px) and the
       page gutters step down, together. */
    @media (max-width:1024px){
      :root{ --sidebar-w: 184px; }
      #content-wrap{ padding: var(--sp-6) var(--sp-6); }
      .rg-main{ grid-template-columns: minmax(0,1fr); }
    }

    /* Tab picker */
    .tp-open{
      display:flex;align-items:center;gap:7px;width:calc(100% - 16px);margin:6px 8px 10px;
      padding:7px 10px;border:1px dashed var(--border);border-radius:9px;cursor:pointer;
      background:none;color:var(--text-3);font-family:inherit;font-size:var(--fs-200);font-weight:600;
      transition:color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
    }
    .tp-open:hover{color:var(--accent);border-color:var(--accent)}
    .tp-open-ico{font-size:var(--fs-200);font-weight:800;line-height:1}
    /* The copy renderMobileTabBar() appends to the strip. Not inside a media
       query, and it does not need one: #mobile-tabs is display:none above
       768px, so this can only render where the strip renders.

       It USED to sit in the ≤640px block, which left 641-768px — where
       #sidebar is already display:none !important, so this strip is the only
       navigation — falling back to the sidebar-rail sizing above. Measured at
       700px with both rules removed: 113x44 with the label showing instead of
       30x44 icon-only, and margin 6px 8px 10px against tabs that have none, so
       it sat off the strip's vertical centre.

       Not "it pushed the tabs off screen", which is what this comment claimed
       until the mutation test was run: width:calc(100% - 16px) is a flex basis
       here, flex-shrink squeezes it to min-content, and the strip scrolls
       anyway (scrollWidth 1857 at 700px). The defect was a mis-sized,
       mis-aligned control, not an overflow.

       #mobile-tabs .tp-open outranks .tp-open on specificity, so source order
       here is not load-bearing. */
    #mobile-tabs .tp-open{
      width:auto;margin:0 4px;padding:0 10px;flex:none;
      min-height:44px;border-radius:10px;align-self:center;
    }
    #mobile-tabs .tp-open span:last-child{display:none}  /* icon only */
    .tp-row{
      display:flex;align-items:center;gap:10px;padding:10px 2px;
      border-bottom:1px solid var(--border-2);font-size:var(--fs-200);color:var(--text);
    }
    .tp-row.is-dragging{opacity:.4}
    .tp-handle{cursor:grab;color:var(--text-3);font-size:var(--fs-200);line-height:1;user-select:none;touch-action:none}
    .tp-handle:active{cursor:grabbing}
    .tp-check{display:flex;align-items:center;gap:10px;flex:1;cursor:pointer}
    .tp-row input{width:16px;height:16px;accent-color:var(--accent);cursor:pointer}
    .tp-row.is-locked .tp-check{cursor:default;color:var(--text-3)}
    .tp-label{flex:1}
    .tp-lock{font-size:var(--fs-200)}
    /* Eye button — real health check, not decoration. Gray = untested,
       amber pulse = testing, green = the tab rendered, red = it didn't. */
    .tp-eye{
      display:flex;align-items:center;gap:6px;border:1px solid var(--border);border-radius:7px;
      background:none;padding:4px 8px;font-size:var(--fs-200);cursor:pointer;color:var(--text-3);
      transition:border-color var(--dur-fast) var(--ease-out);
    }
    .tp-eye:hover{border-color:var(--accent)}
    .tp-eye-dot{width:8px;height:8px;border-radius:50%;background:var(--text-3);flex-shrink:0}
    .tp-eye--testing .tp-eye-dot{background:var(--o, #f59e0b);animation:tpPulse 1s ease-in-out infinite}
    .tp-eye--ok .tp-eye-dot{background:var(--g, var(--status-done))}
    .tp-eye--fail .tp-eye-dot{background:var(--r, #dc2626)}
    @keyframes tpPulse{0%,100%{opacity:1}50%{opacity:.35}}

    /* ── Flow tab ─────────────────────────────────────────────────────────
       Status colours ride the verified tokens (--g/--o/--r/--accent), not new
       hex. Cards are buttons: the whole surface is the click target, which is
       what makes them usable on touch. */
    /* 190px, was 164px. A card is designed for 190-220px; at a 164px floor the
       wider content area (narrower sidebars + 32px padding) fitted SIX columns
       of ~168px, under that range. Raising the floor lands 5 columns at the
       desktop width this dashboard is used at, without pinning the count — a
       hard `repeat(5, ...)` would still be 5 columns at 1024px, i.e. ~92px
       cards, which is worse than reflowing. */
    .flow-cards{display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(190px,1fr))}
    .flow-card{
      display:flex;flex-direction:column;gap:4px;align-items:flex-start;
      padding:16px;border-radius:12px;cursor:pointer;text-align:start;
      background:var(--surface);border:1px solid var(--card-line);
      font-family:inherit;min-height:76px;
      box-shadow:0 1px 3px rgba(15,23,42,.04);
      transition:border-color var(--dur-fast) var(--ease-out), transform var(--dur-base) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out);
    }
    .flow-card:not(:disabled):hover{border-color:var(--accent);transform:translateY(-1px);
      box-shadow:0 6px 18px rgba(15,23,42,.08)}
    .flow-card:not(:disabled):active{transform:translateY(-1px) scale(0.97)}
    .flow-card:disabled{cursor:default;opacity:.75}
    /* Zone-filter chips in the media tab are built as inline `style=""`
       strings in dashboard.js (transition:all var(--dur-base) — every property var(--ease-out), not the
       one that changes). Rewriting ~dozens of generated-string call sites is
       a separate, riskier change; a class rule adds real press feedback today
       without touching them — inline style can't express a pseudo-class, so
       there's nothing to fight for specificity here. */
    .mf-btn{transition:border-color var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out)}
    .mf-btn:active{transform:scale(0.97)}
    .flow-num{font-family:ui-monospace,Menlo,monospace;font-size:var(--fs-100);color:var(--text-3)}
    .flow-name{font-size:var(--fs-200);font-weight:700;color:var(--text);line-height:1.3}
    .flow-state{font-size:var(--fs-100);font-weight:600;color:var(--text-3)}
    /* How much the stage produced, riding the status line rather than adding a
       row. The card is already at its ceiling — the note further down records a
       previous extra line box pushing it to 143px against a 105-120px target —
       so this deliberately introduces no new line box.

       It does NOT inherit .flow-state's status colour. .flow-state goes green
       when done and red when failed; the count is neutral in every state (a
       failed stage that still wrote 3 articles should read "✗ נכשל · 3 מאמרים",
       not paint the 3 red as though the articles were the failure). Hence the
       explicit --text-3 and the lighter weight: status first, volume second.

       Separator is a ::before pseudo so it exists only when the span does —
       no dangling "·" on the ~9 stages that report no count. margin-inline-start
       (not left) because this grid is RTL. */
    .fc-vol{font-weight:500;color:var(--text-3);unicode-bidi:isolate}
    .fc-vol::before{content:"·";margin-inline:4px;opacity:.55;font-weight:600}
    /* Done cards keep a WHITE ground. They used to carry a 6% green wash, which
       on a grid where most stages are complete tinted 11 of 20 cards and made
       the page read as a status board rather than a mostly-white workspace.
       The green ✓ in .flow-state and a soft green border still carry the state
       — the wash was the third encoding of the same fact. */
    .flow-card.is-done{border-color:color-mix(in srgb, var(--g) 34%, var(--card-line))}
    .flow-card.is-done .flow-state{color:var(--g)}
    /* Eye = open this stage's own output file. Only rendered when the file
       exists, so it is always green — its presence is the signal, and a gray
       state would just duplicate .flow-state. Absolutely positioned so adding
       it never reflows the card's stack.
       Bottom inline-end, not top: the top row now belongs to the stage number
       and the icon disc (opposite edges), and the sparkline is deliberately
       82px so this corner of the bottom row is free. */
    .flow-card{position:relative}
    .flow-eye{
      position:absolute;inset-inline-end:10px;bottom:9px;
      display:inline-flex;align-items:center;justify-content:center;
      width:22px;height:22px;border-radius:6px;cursor:pointer;line-height:1;
      color:var(--g);background:color-mix(in srgb, var(--g) 10%, transparent);
      border:1px solid color-mix(in srgb, var(--g) 30%, transparent);
      transition:background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
    }
    .flow-eye:hover{background:color-mix(in srgb, var(--g) 24%, transparent);transform:scale(1.08)}
    .flow-eye:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
    /* Reduced motion means fewer and gentler animations, not zero — opacity
       and color transitions that aid comprehension stay; transform-based
       movement (press feedback, hover lift, drawer slides) is what actually
       triggers motion sickness, so that's what this strips. Covers every
       :active/transform rule added in this pass plus the pre-existing
       .flow-eye rule it replaces (same intent, narrower scope). */
    @media (prefers-reduced-motion:reduce){
      .ea-btn, .nav-item, .flow-card, .mf-btn, .flow-eye, .tp-eye, .sheet, .mob-tab, .agy-row {
        transition-property: opacity, background, background-color, border-color, color !important;
      }
      .ea-btn:active, .nav-item:active, .flow-card:active, .mf-btn:active,
      .flow-card:hover, .flow-eye:hover, .mob-tab:active, .agy-row:active {
        transform: none !important;
      }
      /* #ea-toast is excluded from the blanket transform:none above: its
         transform carries translateX(-50%) horizontal centering, set inline
         by _showToast(), alongside the translateY entrance/exit. Zeroing the
         whole property here would win over the inline style (!important
         beats inline without it) and strip the centering too, shoving the
         toast to the page's left edge. Its own transition-duration is short
         enough (260ms/160ms) that leaving the translateY in place is fine;
         only the color animation below is worth guaranteeing explicitly. */
      #ea-toast { transition-property: opacity, background !important; }
    }
    .flow-card.is-running{border-color:var(--accent)}
    .flow-card.is-running .flow-state{color:var(--accent)}
    .flow-card.is-fail{border-color:var(--r)}
    .flow-card.is-fail .flow-state{color:var(--r)}
    .flow-card.is-warn .flow-state{color:var(--o)}
    .flow-card.is-redone .flow-state{color:var(--o)}
    .flow-sys{margin-top:20px}
    .flow-sys-hd{font-size:var(--fs-200);font-weight:var(--fw-semi);color:var(--text-2);margin-bottom:10px}
    .flow-sys-hd span{font-weight:var(--fw-regular,400);color:var(--text-3);margin-inline-start:8px}
    .flow-card.is-skipped{opacity:.55}

    /* ── Flow card anatomy ────────────────────────────────────────────────
       number · tinted icon disc · title · state · sparkline. The card was a
       three-line text stack; the disc is what makes 22 of them scannable
       without reading every label. */
    /* Stage number and icon share ONE row, at opposite inline edges. They used
       to stack (number absolutely positioned, icon on its own line below),
       which forced 30px of padding-top to keep them apart and pushed the card
       to 143px — 23px over the 105-120px the design calls for. One row removes
       the clearance AND the extra line box. */
    /* 16px on all four sides, set 2026-08-08. min-height is now inert at
       desktop — the natural stack (icon row + title + status + sparkline)
       plus 32px of vertical padding already exceeds it — and is kept only
       as a floor for cards whose title wraps to nothing. */
    .flow-card{gap:0;padding:16px;min-height:112px;justify-content:flex-start}
    .fc-top{
      display:flex;align-items:center;justify-content:space-between;
      width:100%;gap:8px;margin-bottom:3px;
    }
    /* unicode-bidi:isolate, NOT dir="ltr". A stage id ("10a", "11b") is already
       made of LTR characters, so isolating it is enough to render it correctly
       inside this RTL card — while dir="ltr" would additionally flip how this
       element resolves its own logical properties. */
    /* No opacity: --text-3 is already the quietest step that passes, and .7 on
       top of it measured 2.85:1 light / 3.33:1 dark. */
    .flow-card .flow-num{unicode-bidi:isolate;flex-shrink:0}
    .fc-ico{
      display:inline-flex;align-items:center;justify-content:center;
      width:30px;height:30px;border-radius:50%;flex-shrink:0;
      transition:transform var(--dur-base) var(--ease-out);
    }
    .fc-ico svg{width:16px;height:16px}
    /* Categorical hues — which phase of the pipeline, not what state it is in.
       Kept desaturated on purpose: 22 discs at full chroma is noise, and the
       status colours (border + .flow-state) have to stay the loudest thing on
       the card. color-mix against --surface so both themes stay legible. */
    .fc-ico.t-violet{color:#7c5cf6;background:color-mix(in srgb,#7c5cf6 11%,var(--surface))}
    .fc-ico.t-blue  {color:#2f7fd4;background:color-mix(in srgb,#2f7fd4 11%,var(--surface))}
    .fc-ico.t-amber {color:#c07c12;background:color-mix(in srgb,#c07c12 13%,var(--surface))}
    .fc-ico.t-teal  {color:var(--accent);background:color-mix(in srgb,var(--accent) 11%,var(--surface))}
    .fc-ico.t-green {color:#15845f;background:color-mix(in srgb,#15845f 11%,var(--surface))}
    .fc-ico.t-pink  {color:#c2568c;background:color-mix(in srgb,#c2568c 11%,var(--surface))}
    .flow-card:not(:disabled):hover .fc-ico{transform:scale(1.06)}
    .flow-card .flow-name{margin-bottom:2px}
    /* Full card width, matching the reference. Height is reserved whether or
       not a sparkline was drawn, so a row of cards where only some stages
       have recorded spend still lines up.
       Only a card that actually carries an eye button gives up the inline-end
       corner for it — .has-eye is set by the renderer on exactly those cards,
       so the common (no-eye) case keeps the reference's full-bleed line
       instead of every card paying for a button most of them do not have. */
    .fc-spark{display:block;width:100%;height:16px;margin-top:auto;opacity:.85}
    .fc-spark .spark{width:100%;height:16px;display:block}
    .fc-spark path{stroke-width:1.5}
    .flow-card.has-eye .fc-spark{width:calc(100% - 28px)}
    .flow-card:not(:disabled):hover .fc-spark{opacity:1}

    /* Heading block stacks: title, sub, then a full-bleed progress track.
       The track used to be a flex sibling of the title capped at 320px, which
       put it beside the heading; the reference runs it the full width of the
       workspace underneath. Full width also makes the fill readable at low
       percentages — at 320px, 5% was 16px of teal. */
    .flow-hd{display:block;margin-bottom:16px}
    .flow-hd-bar{margin-top:12px;width:100%}
    .flow-hd-title{font-size:var(--fs-500,20px);font-weight:700;color:var(--text);margin:0;line-height:1.25}
    .flow-hd-sub{font-size:var(--fs-200);color:var(--text-3);margin-top:3px}
    .flow-foot{font-size:11.5px;color:var(--text-3);margin-top:16px;line-height:1.7;max-width:74ch}

    /* ── Flow analytics panel ─────────────────────────────────────────────
       Four sections on one row at desktop, wrapping to two then one. Uses
       flex-wrap rather than a fixed grid so the two chart columns can claim
       the slack the two stat columns don't need. */
    .flow-analytics{
      display:flex;flex-wrap:wrap;gap:8px 24px;align-items:stretch;
      padding:16px 18px;margin-top:18px;
    }
    .fa-col{display:flex;flex-direction:column;min-width:0;padding:6px 0}
    .fa-col--stat{flex:0 1 148px}
    .fa-col--stats{flex:0 1 300px}
    .fa-col--chart{flex:3 1 320px}
    .fa-col--donut{flex:1 1 200px;align-items:center}
    /* 2x2 of figures. auto-fit rather than a hard repeat(2) so the block
       collapses to a single column on a narrow screen instead of squeezing
       four numbers into 150px. */
    .fa-grid{
      display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));
      gap:14px 20px;align-content:start;
    }
    .fa-col + .fa-col{border-inline-start:1px solid var(--border-2);padding-inline-start:28px}
    .fa-big{font-size:26px;font-weight:700;color:var(--text);line-height:1.1;letter-spacing:-.01em}
    .fa-cap{font-size:var(--fs-100);color:var(--text-3);margin-top:4px}
    .fa-alert{font-size:var(--fs-100);color:var(--r);font-weight:600;margin-top:8px}
    .fa-hd{font-size:11px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;
      color:var(--text-3);margin-bottom:10px;align-self:flex-start}
    .linechart{width:100%;height:118px;display:block;overflow:visible}
    /* Axis labels live in HTML beside/below the plot, never inside the SVG —
       .linechart stretches with preserveAspectRatio="none" and would stretch
       any text with it. */
    .lc-wrap{display:flex;gap:8px;align-items:stretch}
    .lc-plot{flex:1;min-width:0}
    .lc-y{
      display:flex;flex-direction:column;justify-content:space-between;
      font-size:11px;color:var(--text-3);text-align:end;
      height:118px;flex-shrink:0;line-height:1;
    }
    .lc-x{
      display:flex;justify-content:space-between;
      font-size:11px;color:var(--text-3);margin-top:5px;line-height:1;
    }
    /* Muted, not removed: the line stays on the plot so the shape of the other
       series is still read in context, it just stops competing. */
    .lc-path{transition:opacity var(--dur-fast) var(--ease-out)}
    .lc-path.is-muted{opacity:.16}
    .lc-plot{position:relative}
    .lc-tip{
      position:absolute;top:2px;transform:translateX(-50%);
      background:var(--surface);border:1px solid var(--border-2);border-radius:8px;
      box-shadow:0 6px 18px rgba(15,23,42,.1);
      padding:6px 9px;font-size:11px;line-height:1.6;color:var(--text);
      pointer-events:none;white-space:nowrap;z-index:2;
    }
    .lc-tip b{display:block;color:var(--text-3);font-weight:600;margin-bottom:2px}
    .lc-tip span{display:flex;align-items:center;gap:5px}
    .lc-tip i{width:8px;height:8px;border-radius:2px;flex-shrink:0}

    .lc-legend{display:flex;gap:16px;flex-wrap:wrap;margin-top:10px}
    /* A real <button> now — it toggles the series. Reset the UA button skin so
       it still reads as a legend key rather than a form control. */
    .lc-key{
      display:inline-flex;align-items:center;gap:6px;font-size:var(--fs-100);
      color:var(--text-3);background:none;border:0;padding:2px 4px;margin:0;
      font-family:inherit;cursor:pointer;border-radius:6px;
      appearance:none;-webkit-appearance:none;
    }
    .lc-key:hover{background:var(--surface-2)}
    .lc-key[aria-pressed="true"]{opacity:.45}
    .lc-key[aria-pressed="true"] i{outline:1px solid var(--border-2);outline-offset:1px}
    .lc-key i{width:9px;height:3px;border-radius:2px;flex-shrink:0}
    .lc-key em{font-style:normal;color:var(--text-2);font-weight:600}
    .donut{display:block;margin:2px auto 12px}
    .fa-legend{display:flex;flex-direction:column;gap:7px;width:100%;max-width:180px}
    .fa-lg{display:flex;align-items:center;gap:8px;font-size:var(--fs-100);color:var(--text-3)}
    .fa-lg i{width:9px;height:9px;border-radius:3px;flex-shrink:0}
    .fa-lg span{flex:1;min-width:0}
    .fa-lg b{color:var(--text);font-weight:600}

    @media (max-width:1180px){
      .fa-col--chart{flex-basis:100%}
      .fa-col--chart{border-inline-start:0;padding-inline-start:0;
        border-top:1px solid var(--border-2);padding-top:18px;margin-top:8px}
    }
    @media (max-width:760px){
      .flow-analytics{gap:0;padding:16px}
      .fa-col + .fa-col{border-inline-start:0;padding-inline-start:0;
        border-top:1px solid var(--border-2);padding-top:16px;margin-top:16px}
      .fa-col--donut{align-items:flex-start}
      .fa-legend{max-width:none}
      .flow-card{min-height:106px}
    }
    @media (prefers-reduced-motion:reduce){
      .flow-card:not(:disabled):hover .fc-ico{transform:none}
      .fc-ico{transition-property:opacity,background,color}
    }

    /* ── Responsive ───────────────────────────────────────────────────────
       Three real widths: phone (<640), tablet (640-1024), desktop. The
       sidebar is the main casualty on small screens — it collapses to a
       horizontal scroll strip instead of eating a third of a phone.
       Touch targets: every nav item and button ≥44px on coarse pointers. */
    @media (pointer:coarse){
      .nav-item,.ea-btn,.flow-card,.tp-row,.btn-run{min-height:44px}
      .cl-search input{height:40px}
    }

    /* The primary action must not scroll itself out of sight.

       #hdr-right is a horizontal scroller (measured on a 375px phone:
       clientWidth 181, scrollWidth 245, direction rtl, scrollLeft 0) and
       #btn-run-swarm was the LAST of its five children — so "הפעל סוכנים", the
       button that runs the whole pipeline, sat at left:-50px. Half of it was
       off the screen and nothing indicated the strip scrolled, so the way to
       start a run was to discover a sideways drag on a header.

       `order:-1`, not `position:sticky`. Sticky did keep it on screen at every
       scroll offset — measured — but at rest it has to pin somewhere, and the
       only place available was on top of the sibling next to it. Trading an
       invisible primary action for an occluded secondary one is not a fix.
       Ordering it first puts it where it is naturally visible and lets the
       controls that matter less be the ones that scroll away.

       flex-shrink:0 stops the squeeze that had it at 36px wide; min-width
       completes the 44px floor in the axis min-height does not cover, because
       a 36x44 target is still under it. */
    @media (pointer:coarse), (max-width:768px){
      /* The rest of the header's controls, measured on the same 375px screen:
         #mob-client-select 42px, #spotlight-input 36px, four .view-btn at 30px.
         The floor rule two blocks up lists .nav-item, .ea-btn, .flow-card,
         .tp-row and .btn-run — every control in this header is absent from it,
         which is why the enforcement kept reading as "already done" while the
         header itself met none of it. Width is left alone: these sit in a row
         that already scrolls, and forcing 44px in both axes would push more of
         it off-screen than it rescued. */
      #mob-client-select, #spotlight-input, .view-btn{ min-height:44px }
      /* .btn-close is 28px and every modal's only dismissal. It read as 42px
         when measured with getBoundingClientRect, which is within rounding of
         the floor and so looked nearly fine — but .modal-inner carries
         transform:scale(0.96), and that method returns TRANSFORMED boxes.
         offsetHeight, the layout height, says 28. A sibling .btn-secondary
         measured 42 the same way and is genuinely 44; only one of the two was
         ever a defect. Audit touch targets with offsetHeight. */
      .btn-close{ min-height:44px; min-width:44px }

      /* .tt-btn is a 17x17 help dot and .cmd-fold's summary is a 23px text
         row. Measured on the real dashboard at 390x844 with has_touch: both
         were reachable at 1 of the 5 points a 44px box needs — a finger aimed
         anywhere but dead centre missed.
         Neither is in the allowlist two blocks up, which is the same way the
         header controls were missed: the floor is an allowlist, so a control
         is covered only if somebody remembered to name it.

         The dot is NOT inflated. A 44px badge is a different design, and the
         accessible size and the painted size do not have to be the same
         number. A transparent ::after extends the hit area to 45px around a
         circle that still paints at 17px; .tt-btn already carries
         position:relative, so it anchors without another rule. The summary is
         a text row with room to grow, so that one just takes the floor. */
      .tt-btn::after{
        content:'';
        position:absolute;
        inset:-14px;               /* 17 + 14*2 = 45px, just over the floor */
      }

      /* #ea-pw-toggle is the show/hide eye on the login form — 30x30, measured
         on the live page at 375px, reachable at 1 of the 5 points a 44px box
         needs. It is the first control an admin touches from a phone and the
         only way to check a password typed on a soft keyboard.

         Hit area again, not size. It cannot simply grow: the field reserves
         44px of padding-inline-end and the button sits 6px inside that, so a
         44px-wide button would overlap the text beside it. The inline styles
         in dashboard.js already set position:absolute, so ::after anchors to
         the button without another rule. inset:-7px puts the hit box at 44px
         exactly; the eye still paints at 30 and the icon at 19. */
      #ea-pw-toggle::after{
        content:'';
        position:absolute;
        inset:-7px;                /* 30 + 7*2 = 44px, the floor exactly */
      }
      .cmd-fold > summary{
        min-height:44px;
        display:flex;
        align-items:center;
      }

      /* Found by tests/test_touch_floor_sweep.py, which walks every
         interactive control instead of naming them one at a time — the first
         three entries in this block were each found the hard way, one bug
         report at a time, because a floor written as an allowlist only covers
         what somebody remembered to list.

         Measured at 390x844 with touch:
           .dna-ref > summary   358x35   the agent glossary, on the agents tab
           .nba-cta             322x36   "המשך זרימה", the flow tab's next action
           .flow-eye             22x22   the per-stage preview control

         The first two are wide enough and short — text rows — so min-height
         is the whole fix. .flow-eye is not: growing it to 44x44 made it cover
         the card's status line ("✓ הושלם · 6 מאמרים") and long step names on
         a phone, because it is pinned to the card's bottom corner. It takes
         the hit-area trick the 17px dot above uses instead: it still paints at
         22px in the sparkline row, which .has-eye already shortens for it, and
         a transparent ::after makes the tap box 44px. */
      .dna-ref > summary{
        min-height:44px;
        display:flex;
        align-items:center;
      }
      .nba-cta{ min-height:44px }
      .flow-eye{ bottom:14px; inset-inline-end:13px }  /* keeps the whole tap box inside the card */
      .flow-eye::after{
        content:'';
        position:absolute;
        inset:-12px;               /* 22 + 12*2 = 46px, just over the floor */
      }

      #btn-run-swarm{
        order:-1;
        flex-shrink:0;
        min-width:44px;
        min-height:44px;
        justify-content:center;
      }
      /* Ordered with the run button so the scroll strip cannot hide it. */
      .hdr-claude{ order:-1; min-width:44px; min-height:44px; justify-content:center }
      .hdr-ops, .ops-item{ min-height:44px }
      /* Icon-only on phone, pinned beside Claude: as text it fell off the strip. */
      .hdr-ops{ order:-1; min-width:44px; justify-content:center }
      .hdr-claude{ padding-inline:4px; gap:4px }
      .hdr-ops .hdr-ops-label{ display:none }
    }

    /* Touch-target floor. Added 2026-08-06: the accordion summaries became the
       primary way to navigate this dashboard once every section moved behind a
       fold, and they measured 20px tall on a phone — under half the 44px floor.
       The pointer:coarse rule above predates them, so they were never covered.
       Measured at a real 375px viewport: 57 controls were under 44px.

       Keyed on WIDTH as well as pointer, deliberately. pointer:coarse alone
       does not match a desktop browser narrowed to phone width — which is how
       this gets reviewed most of the time, and it is also why the first version
       of this fix silently did nothing when tested. A 44px control on a narrow
       desktop window is harmless; an unreachable one on a phone is not. */
    /* Hover on a touch screen is not a state, it is a stain. A tap sets :hover
       and nothing clears it until the next tap elsewhere, so a phone user is
       left with a lifted, brightened element that looks selected and is not.
       64 hover rules exist in this file and none is guarded.

       Neutralised here rather than by rewriting all 64 into @media (hover:hover):
       one reviewable block, no risk of missing one, and the desktop rules stay
       exactly as written. Only the properties that visibly persist are reset —
       transform and filter. A background or colour shift is harmless enough that
       undoing it would cost more churn than it saves. */
    @media (hover:none){
      .pl-seg:hover, .flow-card:hover, .flow-eye:hover,
      .ea-btn:hover, .nav-item:hover, .mob-tab:hover, .cs-row:hover{
        transform:none;
        filter:none;
      }
    }

    @media (pointer:coarse), (max-width:768px){
      /* .pl-seg is here because it became interactive: it carries onclick=
         "openStageDrawer(...)" and .pl-tip is display:none on touch, so tapping
         a segment is now the ONLY way to read a stage's status on a phone.
         It was 30px (the max-width:640px rule above), and min-height wins over
         an explicit height when it is the larger of the two, so that rule stays
         as the desktop-narrow value and this raises it on touch.
         Width needed no change: .pl-rail is repeat(6, minmax(0,1fr)) per phase,
         not one row of 23, so at 375px a segment is already ~55px wide. */
      /* .lib-trash, .lib-row-del and the library toolbar's select-all label are
         here for the same reason .pl-seg is: they are the only way to reach a
         destructive action on a phone, and a 30px hit area on a control that
         permanently deletes content is the wrong control to make people aim
         at. The per-card checkbox is not in this list on purpose — a 44px
         input[type=checkbox] renders as an enormous box; .lib-check-hit wraps
         it with the touch target instead, at its own rule above. */
      .ov-fold-sum, .pro-accordion > summary,
      .sched-btn, .sched-input,
      .btn-secondary, .tp-open, .cs-row, .mf-btn, .pl-seg,
      .lib-trash, .lib-row-del, .lib-toolbar > label{
        min-height:44px;
      }
      /* .lib-row-del is an icon button, so height alone leaves it 38px wide —
         measured. The target is 44 in BOTH axes, and it is the one control on
         a card that permanently deletes the card. */
      .lib-row-del{ min-width:44px; }
      /* min-height alone leaves the label pinned to the top of the taller box. */
      .ov-fold-sum, .cs-row{ align-items:center }
    }

    /* Horizontal page overflow on phones — measured, not assumed: the document
       scrolled to 434px inside a 375px viewport.
       Cause: .pl-tip, the pipeline stage popovers. They are position:absolute,
       240px wide and centred on their cell, so a tooltip on a right-edge stage
       reaches 438px. They are visibility:hidden until hover — but a
       visibility:hidden element STILL occupies layout and still counts toward
       scrollWidth, so they widened the page while invisible.
       They are a hover affordance, and a touch device has no hover, so they can
       never be shown there. display:none removes them from layout entirely,
       which both fixes the overflow and drops something that was dead weight on
       touch. Desktop behaviour is untouched. */
    @media (pointer:coarse), (max-width:768px){
      .pl-tip{ display:none !important }
      /* Defence in depth: nothing absolutely-positioned added later should be
         able to blow out the page width again. The scrollers that legitimately
         need to overflow (.tbl-scroll, .pl-rail) do so inside themselves. */
      #content-wrap{ overflow-x:hidden }
    }
    @media (max-width:1024px){
      .cl-grid{grid-template-columns:repeat(auto-fill,minmax(240px,1fr))}
      /* 176px, was 146px. The old floor packed 5 columns of ~146px into the
         tablet content width — narrower than the phone layout's own cards, and
         too tight for the number + icon header row a card now carries. This
         reflows to 3-4 comfortable columns instead of 5 cramped ones. */
      .flow-cards{grid-template-columns:repeat(auto-fill,minmax(176px,1fr))}
    }
    @media (max-width:640px){
      :root{--sidebar-w:0px}
      /* The #sidebar and #sb-nav rules that were here are gone for the same
         reason as the block below: <nav id="sb-nav"> lives inside
         <aside id="sidebar"> (dashboard.html:120,170), and the 768px block
         hides that aside with !important. Styling the children of a hidden
         parent is dead weight — it described a bottom nav bar that has never
         appeared on any phone. #mobile-tabs is the strip that actually shows.
         --sidebar-w:0px stays: the layout still reads it. */
      /* DELETED, not revived: #sidebar{display:flex} here never rendered. The
         768px block above sets #sidebar{display:none !important}, both queries
         match at 375px, and !important wins — so this rule and the .tp-open
         sizing under it have never been on a screen. The comment that used to
         sit here said the customiser "stays reachable on phones"; it has not
         been reachable at any width below 768px for as long as both rules have
         coexisted.

         Reviving 28 lines of CSS nobody has ever seen render, in the same
         change as a release, is two risks at once. #mobile-tabs is the strip
         that actually shows, so the customiser moves into it instead — see
         `#mobile-tabs .tp-open` beside the base .tp-open rule, hoisted out of
         this block so it also covers 641-768px. */
      main,.main,#main{margin-inline-start:0 !important;padding-bottom:84px}
      .flow-cards{grid-template-columns:repeat(2, minmax(0, 1fr))}
      /* One column, not two: a client card carries an avatar, name, meta line,
         ID, progress and two buttons. At two per row it was 172px wide with a
         42px text column, so "Food & Restaurant" wrapped a word a line and the
         client ID (126px) spilled out of the card. Flow tiles are small enough
         for two; these are not. */
      .cl-grid{grid-template-columns:minmax(0, 1fr)}
      .sheet{width:100%}
      .cl-search input{width:100%}
    }

    /* ── Content quality funnel ─────────────────────────────────────────────
       Declared last on purpose. .tp-open shipped broken because .ovw-open was
       written ~900 lines above it and lost on source order while carrying the
       same specificity; every selector below is a new .fnl-* class that nothing
       else in this file declares, and it sits after all of them, so neither
       half of that failure can repeat here.

       Built from flex + percentage inline-size rather than an SVG viewBox: the
       bars have to reflow at every width between 320px and 1440px, and a fixed
       viewBox would either letterbox or shrink the Hebrew labels below legible
       size. The SVG primitives in dashboard.js (.spark, .pro-chart) stay where
       they are — they draw continuous series, which is the case a viewBox is
       right for.

       EVERY box-model property here is logical (inline-size, margin-inline,
       padding-inline, border-inline-*). In an RTL document `left`/`width` would
       pin the funnel's growth direction to the wrong edge. */
    .fnl-card { margin-bottom: var(--sp-6); }
    .fnl-lede {
      font-size: var(--fs-200); color: var(--text-2); line-height: var(--lh-200);
      margin: calc(var(--sp-4) * -1) 0 var(--sp-5);
    }

    .fnl-stage + .fnl-stage { margin-block-start: 0; }
    .fnl-hd {
      display: flex; align-items: baseline; gap: var(--sp-2);
      margin-block-end: var(--sp-2);
    }
    .fnl-name {
      font-size: var(--fs-200); font-weight: var(--fw-semi); color: var(--text);
    }
    /* The measurement, at the weight a measurement deserves. dir="ltr" is on
       the span in the JS: a bare numeral at an RTL boundary reorders against
       the label next to it. */
    .fnl-n {
      font-size: var(--fs-300); font-weight: var(--fw-bold); color: var(--text);
      letter-spacing: var(--tracking-tight);
    }
    .fnl-sub { font-size: var(--fs-100); color: var(--text-3); }

    /* The track is full width and centres its bar, so the second stage being
       narrower reads as a taper instead of as a bar that failed to fill. */
    .fnl-track { display: flex; justify-content: center; }
    .fnl-bar {
      display: flex; block-size: 26px; border-radius: var(--r-sm);
      overflow: hidden; background: var(--surface-3);
    }
    .fnl-seg {
      display: block; block-size: 100%; flex: 0 0 auto;
      /* A single item out of a few dozen is a legitimate ~2% segment. Without a
         floor it renders sub-pixel and the type silently disappears from a
         chart whose entire job is naming which type dropped. */
      min-inline-size: 3px;
      transition:filter var(--dur-fast) var(--ease-out);
    }
    .fnl-seg:hover { filter: brightness(1.12); }
    /* A type that lost items keeps its own hue — recolouring it to the fail
       colour would break the legend — and is marked with a fail-coloured edge
       so the failing segment is identifiable inside the bar, not only in the
       strip below it. */
    .fnl-seg.is-lossy { border-inline-end: 3px solid var(--status-fail); }

    /* The funnel wall between the two bars. The strip carries a fail tint and
       the trapezoid on top of it carries the card's own surface, so the only
       tint left showing is the two side wedges — the items that dropped, at
       their true proportion. A plain --surface-3 trapezoid was measured at
       1.05:1 against the white card and was effectively invisible; this reads
       because the LOSS is what gets the colour, which is also the honest way
       round. Nothing dropped ⇒ --l is 0% ⇒ the trapezoid covers the strip and
       no tint appears at all. */
    .fnl-gap { block-size: 16px; background: color-mix(in srgb, var(--status-fail) 18%, transparent); }
    .fnl-taper {
      block-size: 100%; background: var(--surface);
      clip-path: polygon(0 0, 100% 0, var(--r) 100%, var(--l) 100%);
    }

    .fnl-legend {
      display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
      margin-block-start: var(--sp-4);
    }
    .fnl-key { display: inline-flex; align-items: center; gap: var(--sp-2); }
    .fnl-swatch {
      inline-size: 10px; block-size: 10px; border-radius: var(--r-xs);
      flex-shrink: 0; display: inline-block;
    }
    .fnl-key-l { font-size: var(--fs-100); color: var(--text-2); }
    .fnl-key-n {
      font-size: var(--fs-100); color: var(--text-3);
      font-variant-numeric: tabular-nums;
    }

    .fnl-drop {
      display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
      margin-block-start: var(--sp-4); padding-block-start: var(--sp-3);
      border-block-start: 1px solid var(--border);
    }
    .fnl-drop-hd {
      font-size: var(--fs-200); font-weight: var(--fw-semi); color: var(--status-fail);
    }
    .fnl-drop-chip {
      display: inline-flex; align-items: center; gap: var(--sp-2);
      padding: 2px var(--sp-2); border-radius: var(--r-full);
      border: 1px solid var(--border); background: var(--surface-2);
      font-size: var(--fs-100); color: var(--text-2);
    }
    .fnl-drop-chip b { color: var(--text); font-variant-numeric: tabular-nums; }

    .fnl-det { margin-block-start: var(--sp-3); }
    .fnl-det > summary {
      cursor: pointer; font-size: var(--fs-100); color: var(--text-3);
      list-style: none;
    }
    .fnl-det > summary::-webkit-details-marker { display: none; }
    /* ◂ not ▸. The marker sits at the inline START, which in this RTL document
       is the right edge, so a right-pointing triangle points away from the text
       it is supposed to introduce. */
    .fnl-det > summary::before { content: '◂ '; }
    .fnl-det[open] > summary::before { content: '▾ '; }
    .fnl-det > summary:hover { color: var(--accent); }
    .fnl-det-bd { margin-block-start: var(--sp-3); }
    .fnl-det-grp + .fnl-det-grp { margin-block-start: var(--sp-4); }
    .fnl-det-ttl {
      display: flex; align-items: center; gap: var(--sp-2);
      font-size: var(--fs-100); font-weight: var(--fw-semi); color: var(--text-2);
      margin-block-end: var(--sp-2);
    }
    /* Four columns: what it was, what it measured, the unit, what was required.
       The item title is the only one that can wrap; the three numeric columns
       are sized to their content so the numbers stay in a readable column. */
    .fnl-det-row {
      display: grid;
      grid-template-columns: minmax(0, 1fr) auto auto auto;
      align-items: baseline; gap: var(--sp-2);
      padding-block: 5px;
      border-block-start: 1px solid var(--border);
      font-size: var(--fs-100);
    }
    .fnl-det-item {
      color: var(--text-2); min-width: 0; overflow: hidden;
      text-overflow: ellipsis; white-space: nowrap;
    }
    .fnl-det-num {
      color: var(--status-fail); font-weight: var(--fw-semi);
      font-variant-numeric: tabular-nums;
    }
    .fnl-det-unit { color: var(--text-3); }
    .fnl-det-req  { color: var(--text-3); }

    /* Stands in for a bar with nothing in it — see the note at the stage()
       helper in dashboard.js. */
    .fnl-none {
      font-size: var(--fs-100); color: var(--status-fail);
      padding-block: var(--sp-2);
    }
    .fnl-clean, .fnl-note {
      font-size: var(--fs-100); color: var(--text-3);
      line-height: var(--lh-100); margin-block-start: var(--sp-3);
    }
    .fnl-clean {
      color: var(--status-done);
      padding-block-start: var(--sp-3); border-block-start: 1px solid var(--border);
    }

    /* Narrow widths. The bar keeps working down to 320px because it is
       percentage-based, but the header runs out of room first: the stage name,
       the number and the rate share one line and the name is the first thing to
       be squeezed. Below the phone breakpoint the rate moves to its own line. */
    @media (max-width: 640px) {
      .fnl-bar { block-size: 22px; }
      .fnl-hd  { flex-wrap: wrap; row-gap: 2px; }
      .fnl-n   { font-size: var(--fs-200); }
      .fnl-legend { gap: var(--sp-2) var(--sp-3); }
      /* The required-range column is the least useful of the four on a phone
         and the widest after the title; the measured value stays. */
      .fnl-det-row { grid-template-columns: minmax(0, 1fr) auto auto; }
      .fnl-det-req { display: none; }
    }

    /* ── Platform brand marks ───────────────────────────────────────────────
       Colours live here rather than in dashboard.js so both themes are decided
       in one place. These ARE raw hex and are meant to be: they are each
       platform's own brand value, not this design system's — a token would
       imply they follow the theme, which is exactly what a brand mark must not
       do. The one exception is TikTok, whose mark is #010101 and disappears on
       the dark ground; it falls back to --text there, which is the same
       treatment the platform's own dark-mode guidance uses. */
    .pbrand {
      display: inline-flex; align-items: center; justify-content: center;
      inline-size: 18px; block-size: 18px; flex-shrink: 0;
    }
    .pbrand svg { inline-size: 100%; block-size: 100%; display: block; }
    .pbrand[data-p="instagram"] { color: #E4405F; }
    .pbrand[data-p="facebook"]  { color: #1877F2; }
    .pbrand[data-p="tiktok"]    { color: #010101; }
    :root[data-theme="dark"] .pbrand[data-p="tiktok"] { color: var(--text); }
    /* Platforms with no verified mark in this repo get their initials in a
       neutral chip rather than an invented path or an emoji. Deliberately not
       guessed: a wrong logo is worse than no logo. */
    .pbrand--txt {
      border-radius: var(--r-xs); background: var(--surface-3);
      color: var(--text-2); font-size: 11px; font-weight: var(--fw-bold);
      inline-size: auto; min-inline-size: 18px; padding-inline: 3px;
      letter-spacing: .02em;
    }
    /* ── Leads ────────────────────────────────────────────────────────────
       Logical properties throughout (inline-start, not left) so the RTL
       layout is the default rather than a mirror applied afterwards. */
    .lead-panel { margin-block: var(--sp-4); }

    .lead-form {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
      gap: var(--sp-3);
      margin-block: var(--sp-3);
    }
    .lead-form label {
      display: flex; flex-direction: column; gap: var(--sp-1);
      font-size: var(--fs-100); color: var(--text-2);
    }
    .lead-form input, .lead-form select {
      padding: var(--sp-2);
      border: 1px solid var(--border);
      border-radius: 6px;
      background: var(--bg);
      color: var(--text);
      font-size: var(--fs-200);
      font-family: inherit;
      min-width: 0;             /* or a long option string blows out the grid */
    }
    .lead-form select:disabled, .lead-form option:disabled { opacity: .5; }

    .lead-actions {
      display: flex; flex-wrap: wrap; align-items: center;
      gap: var(--sp-3); margin-block-start: var(--sp-3);
    }
    .lead-est { font-size: var(--fs-100); color: var(--text-3); }

    .lead-warn, .lead-ok {
      font-size: var(--fs-100);
      padding: var(--sp-2) var(--sp-3);
      border-radius: 6px;
      margin-block-end: var(--sp-2);
    }
    .lead-warn { color: var(--status-warn); border: 1px solid var(--status-warn); }
    .lead-ok   { color: var(--text-3); }

    .lead-msg { margin-block-start: var(--sp-3); font-size: var(--fs-100); color: var(--text-3); }
    .lead-msg.is-ok   { color: var(--status-done); }
    .lead-msg.is-warn { color: var(--status-warn); }

    /* The table scrolls inside its own box. Without this the whole page
       scrolls sideways on mobile, which breaks every other panel too. */
    .lead-table-wrap { overflow-x: auto; margin-block-start: var(--sp-3); }
    .lead-table { width: 100%; min-width: 760px; border-collapse: collapse; }
    .lead-table th, .lead-table td {
      padding: var(--sp-2) var(--sp-3);
      text-align: start;
      border-block-end: 1px solid var(--border);
      font-size: var(--fs-100);
      vertical-align: top;
    }
    .lead-table th { color: var(--text-3); font-weight: 600; white-space: nowrap; }
    .lead-table td[dir="ltr"] { text-align: start; unicode-bidi: isolate; }
    .lead-opener { max-width: 34ch; color: var(--text-2); }

    @media (max-width: 640px) {
      .lead-form { grid-template-columns: 1fr; }
      .lead-actions { flex-direction: column; align-items: stretch; }
    }

/* ── Client invitations ──────────────────────────────────────────────────────
   The invitation link is never rendered in a list — only its safe state is.
   These styles cover the row, and the one-time result panel that shows the
   link once and destroys it on close (see closeSheet in dashboard.js). */
.inv-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3, 12px);
  flex-wrap: wrap;
  padding: var(--sp-3, 12px);
  border: 1px solid var(--border, #e6ebf1);
  border-radius: var(--r-lg, 12px);
  background: var(--surface, #fff);
}
.inv-row-main {
  display: flex;
  align-items: center;
  gap: var(--sp-2, 8px);
  flex-wrap: wrap;
  min-width: 0;
}
.inv-meta {
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 0.08em;
  color: var(--text-3, #697386);
  /* Dates and operator identifiers are Latin runs inside an RTL row; without
     isolation bidi moves their punctuation to the wrong end. */
  unicode-bidi: isolate;
}
.inv-note {
  margin-top: var(--sp-2, 8px);
  font-size: 11px;
  line-height: 16px;
  color: var(--text-3, #697386);
}
.inv-once {
  font-size: 14px;
  line-height: 21px;
  font-weight: 600;
  color: var(--text, #0a2540);
  margin: 0 0 var(--sp-3, 12px);
}
.inv-link {
  /* Inherits Rubik rather than introducing a monospace stack DESIGN.md does
     not declare. The link wraps and is select-all, which is what manual
     copying actually needs. */
  font-size: 11px;
  line-height: 16px;
  /* Wraps rather than clipping: a link the operator cannot fully see is a
     link they cannot copy manually when the clipboard is denied. */
  overflow-wrap: anywhere;
  user-select: all;
  padding: var(--sp-3, 12px);
  border: 1px solid var(--border-strong, #d5dbe3);
  border-radius: var(--r-md, 8px);
  background: var(--surface-3, #eef2f7);
  color: var(--text, #0a2540);
}
.inv-pending {
  display: inline-block; margin-top: 4px; padding: 2px 8px; font-size: 11px; font-weight: 600;
  border-radius: 999px; color: var(--status-running, #1d4ed8);
  background: color-mix(in srgb, var(--status-running, #1d4ed8) 10%, transparent);
}
.inv-label { display: block; font-size: 12px; font-weight: 600; margin-bottom: 6px; }
.inv-select {
  width: 100%; height: 42px; padding: 0 12px; font: inherit; color: var(--text);
  background: var(--surface); border: 1px solid var(--border-control); border-radius: var(--r-lg);
}
.ea-btn.is-copied {
  background: var(--status-done, #15803d);
  border-color: var(--status-done, #15803d);
  color: var(--text-inverse, #fff);
}
@media (max-width: 640px) {
  /* Stacked, so the action stays reachable instead of being pushed off-row. */
  .inv-row { align-items: stretch; flex-direction: column; }
  .inv-row .ea-btn { width: 100%; }
}
@media (prefers-reduced-motion: reduce) {
  .ea-btn.is-copied { transition:none; }
}

/* Non-blocking notice inside the sheet: the action succeeded, something
   secondary did not. Distinct from .f-err, which means the action failed. */
.f-warn { font-size: 11px; line-height: 16px; color: var(--status-warn, #a16207); }

/* ── Operational pulse ─────────────────────────────────────────────────────
   A single compact row of facts that appear nowhere else on the tab: health,
   last activity, spend. Sits between the header and the focus card, so the
   reading order top-to-bottom is "how is it" -> "what do I do" -> "the detail".

   Sized to stay one line on desktop and to wrap without overflow in RTL. All
   spacing is logical (inline/block), never left/right: the tab renders under
   dir="rtl" and a physical padding-left would land on the wrong edge.

   The tone class colours ONLY the dot and the inline-start rule. Text stays
   --text so nothing here depends on a hue to be readable, and the health
   label is a word ("דורש טיפול"), not a colour — it survives greyscale, a
   colour-blind reader and a screen reader unchanged. */
.fl-pulse {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 28px;
  align-items: center;
  margin-block-start: 16px;
  padding: 12px 16px;
  border-inline-start: 3px solid var(--status-idle);
}
.fl-pulse.is-fail { border-inline-start-color: var(--status-fail); }
.fl-pulse.is-warn { border-inline-start-color: var(--status-warn); }
.fl-pulse.is-run  { border-inline-start-color: var(--status-running); }
.fl-pulse.is-done { border-inline-start-color: var(--status-done); }

.flp-tile { min-width: 0; }
.flp-cap {
  font-size: 11.5px;
  line-height: 16px;
  color: var(--text-3);
  white-space: nowrap;
}
/* Numbers and money are LTR runs inside an RTL line; isolate keeps a value
   like "$1.42" from reordering against the Hebrew caption beside it. */
.flp-val {
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  color: var(--text);
  unicode-bidi: isolate;
  display: flex;
  align-items: center;
  gap: 6px;
}
/* "no runs recorded" is an absence, not a measurement — it reads at caption
   weight so it cannot be mistaken for a value at a glance. */
.flp-val--none { font-weight: 400; font-size: 13px; color: var(--text-3); }

.flp-dot {
  width: 7px; height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--status-idle);
}
.is-fail .flp-dot { background: var(--status-fail); }
.is-warn .flp-dot { background: var(--status-warn); }
.is-run  .flp-dot { background: var(--status-running); }
.is-done .flp-dot { background: var(--status-done); }

/* The health tile leads, so it keeps its own column on narrow screens while
   the remaining tiles wrap beneath it rather than squeezing to one word each. */
@media (max-width: 640px) {
  .fl-pulse { gap: 10px 20px; }
  .flp-tile--health { flex-basis: 100%; }
}

/* ── Next best action ──────────────────────────────────────────────────────
   One card, above the grid, naming the single thing to do now. It renders
   only when there IS something — see nextBestAction() for why an "all clear"
   state deliberately produces no card.

   The severity colour lives on an inline-start border, not a filled
   background. A filled red/amber panel at the top of the page competes with
   the status dots on the 23 cards below it, and those dots are the actual
   per-stage truth; this card is a pointer to one of them, so it stays
   quieter than the thing it points at. Border-inline-start (not -left) so
   it stays on the reading edge in RTL. */
.nba {
  display: flex; align-items: center; gap: 16px;
  padding: 14px 16px; margin-bottom: 16px;
  background: var(--surface);
  border: 1px solid var(--card-line);
  border-inline-start: 3px solid var(--status-idle, var(--text-3));
  border-radius: var(--r-md);
}
.nba--fail { border-inline-start-color: var(--status-fail, #dc2626); }
.nba--warn { border-inline-start-color: var(--status-warn, #b45309); }
.nba--run  { border-inline-start-color: var(--status-running, #0369a1); }
.nba--idle { border-inline-start-color: var(--text-3); }

.nba-body  { flex: 1; min-width: 0; }
.nba-title { font-size: 14px; font-weight: 600; color: var(--text); }
.nba-text  { font-size: 13px; color: var(--text-2); margin-top: 2px; }

.nba-cta {
  flex: none;
  padding: 8px 14px;
  font: inherit; font-size: 13px; font-weight: 500;
  /* --on-accent, not #fff: dark mode's accent is #5eead4, and white on it
     measured 1.48:1. --on-accent follows the theme (white / ink). */
  color: var(--on-accent); background: var(--accent);
  border: 0; border-radius: var(--r-sm);
  cursor: pointer;
  transition:opacity var(--dur-fast, var(--dur-fast)) var(--ease-out);
}
.nba-cta:hover  { opacity: .88; }
.nba-cta:focus-visible {
  outline: 2px solid var(--select-ring); outline-offset: 2px;
}

/* The card is a status region that can appear mid-session, so it animates in
   — but only the entrance, and only for users who accept motion. */
@media (prefers-reduced-motion: no-preference) {
  .nba { animation: nba-in var(--dur-base, 160ms) var(--ease-out); }
  @keyframes nba-in { from { opacity: 0; transform: translateY(-4px); } }
}

@media (max-width: 640px) {
  .nba { flex-direction: column; align-items: stretch; gap: 12px; }
  .nba-cta { width: 100%; }
}

/* ── Recent activity feed ──────────────────────────────────────────────────
   The grid answers "what state is everything in"; it has no time axis, so it
   cannot answer "what moved, and when". This panel does, from the same
   per-stage `modified` timestamps the completion chart already plots — so the
   two can never disagree about when a stage finished.

   Rows are buttons into the same drawer a card opens. Nothing here is a new
   surface to learn: same icons, same status vocabulary, same destination. */
.fl-panel { margin-top: 16px; padding: 16px; }

.fl-hd {
  display: flex; align-items: baseline; gap: 10px;
  flex-wrap: wrap; margin-bottom: 10px;
}
.fl-hd h3 { margin: 0; font-size: 14px; font-weight: 600; color: var(--text); }
/* States the provenance rather than leaving the reader to assume the feed is
   a live event log. It is derived from file mtimes, which is a weaker claim. */
.fl-hd-sub { font-size: 11.5px; color: var(--text-3); }

.fl-feed { list-style: none; margin: 0; padding: 0; }
.fl-feed li + li { border-top: 1px solid var(--card-line); }

.fl-row {
  display: flex; align-items: center; gap: 12px;
  width: 100%; padding: 9px 6px;
  font: inherit; text-align: start;
  background: none; border: 0; border-radius: var(--r-sm);
  cursor: pointer;
  transition:background var(--dur-fast, var(--dur-fast)) var(--ease-out);
}
.fl-row:hover { background: var(--surface-2); }
.fl-row:focus-visible { outline: 2px solid var(--select-ring); outline-offset: -2px; }

/* Same disc as the grid card, one size down — the icon is a recognition cue
   carried over, not a second visual language. */
.fl-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%; flex: none;
}
.fl-ico svg { width: 14px; height: 14px; }
.fl-ico.t-violet { color: #7c5cf6; background: color-mix(in srgb, #7c5cf6 11%, var(--surface)); }
.fl-ico.t-blue   { color: #2f7fd4; background: color-mix(in srgb, #2f7fd4 11%, var(--surface)); }
.fl-ico.t-amber  { color: #c07c12; background: color-mix(in srgb, #c07c12 13%, var(--surface)); }
.fl-ico.t-teal   { color: var(--accent); background: color-mix(in srgb, var(--accent) 11%, var(--surface)); }
.fl-ico.t-green  { color: #15845f; background: color-mix(in srgb, #15845f 11%, var(--surface)); }
.fl-ico.t-pink   { color: #c2568c; background: color-mix(in srgb, #c2568c 11%, var(--surface)); }

.fl-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.fl-txt b     { font-size: 13px; font-weight: 600; color: var(--text);
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fl-txt small { font-size: 11.5px; color: var(--text-3); }

.fl-tag {
  flex: none; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 500;
  color: var(--text-2); background: var(--surface-2);
  border: 1px solid var(--card-line);
}
.fl-tag.is-done    { color: var(--g); border-color: color-mix(in srgb, var(--g) 30%, var(--card-line)); }
.fl-tag.is-running { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 34%, var(--card-line)); }
.fl-tag.is-fail    { color: var(--r); border-color: color-mix(in srgb, var(--r) 30%, var(--card-line)); }
.fl-tag.is-warn    { color: var(--o); border-color: color-mix(in srgb, var(--o) 30%, var(--card-line)); }
.fl-tag.is-needs_writer { color: var(--o); border-color: color-mix(in srgb, var(--o) 30%, var(--card-line)); }
.fl-tag.is-skipped { opacity: .7; }

.fl-empty { margin: 0; padding: 6px 2px; font-size: 12.5px; color: var(--text-3); }

@media (max-width: 640px) {
  .fl-tag { display: none; }   /* the row is already colour-coded by its icon */
}

/* No dark override for the tag hues here on purpose. --g/--o/--r are aliased
   to the dark --status-* values in dashboard-tokens.css, which already clear
   AA on all three dark grounds; a second per-component lift would be a
   duplicate source of truth for the same three colours and would wash them
   out on top of a fix that already landed. The tags inherit and pass. */

/* ── Content library: selection and permanent deletion ────────────────────────
   The library grew a destructive action, so it grew the two things a
   destructive action needs to be safe on a screen: a selection state you can
   see without reading, and a confirmation you cannot dismiss by accident.

   Colour is never the only signal. A selected card gets a ring AND a tinted
   ground AND a checked box; the trash button carries an icon AND the word
   "מחק"; the confirm button is red AND says what it does. Each of those alone
   fails somebody. */

.lib-toolbar{
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  padding:10px 12px; margin-bottom:16px;
  background:var(--surface-2); border:1px solid var(--border);
  border-radius:8px;
}

/* The visual box stays 18px; .lib-check-hit carries the touch target. The
   negative margin keeps the card's header on the same baseline it had before
   the checkbox existed. */
.lib-check{ width:18px; height:18px; flex-shrink:0; cursor:pointer; accent-color:var(--accent); }
.lib-check-hit{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:44px; min-height:44px; margin:-13px -13px -13px 0; flex-shrink:0;
}
.lib-check:focus-visible, #lib-select-all:focus-visible{
  outline:none; box-shadow:var(--sh-focus); border-radius:3px;
}

.lib-card-sel{
  border-color:var(--accent) !important;
  box-shadow:0 0 0 1px var(--accent) inset;
  background:color-mix(in srgb, var(--accent) 6%, var(--surface));
}

.lib-trash{
  /* inline-start, not left: this bar is RTL, and margin-left:auto pushed the
     destructive button to the READING start of the row rather than its end. */
  margin-inline-start:auto; display:inline-flex; align-items:center; gap:6px;
  padding:7px 14px; border-radius:6px; cursor:pointer;
  font-size:var(--fs-200); font-weight:600; font-family:'Rubik',sans-serif;
  color:var(--status-fail); background:transparent;
  border:1px solid color-mix(in srgb, var(--status-fail) 40%, transparent);
  transition:background var(--dur-fast) var(--ease-out);
}
.lib-trash:disabled{
  /* Disabled by state, not by styling: the button is genuinely inert with
     nothing selected, and it says so to a screen reader through the disabled
     attribute rather than only by looking faded. */
  opacity:.45; cursor:not-allowed; color:var(--text-3);
  border-color:var(--border);
}
.lib-trash:focus-visible, .lib-row-del:focus-visible, .lib-del-confirm:focus-visible{
  outline:none; box-shadow:var(--sh-focus);
}

.lib-row-del{
  margin-inline-start:6px; padding:2px 8px; border-radius:6px; cursor:pointer;
  background:transparent; border:1px solid transparent;
  font-size:var(--fs-100); line-height:1.6; color:var(--text-3);
  transition:color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}

/* Hover-only affordances, behind a hover query. On a touch screen :hover
   latches after a tap and leaves the row action stuck in its danger colour on
   a card the operator merely opened. */
@media (hover:hover){
  .lib-trash:hover:not(:disabled){ background:color-mix(in srgb, var(--status-fail) 12%, transparent); }
  .lib-row-del:hover{ color:var(--status-fail); border-color:color-mix(in srgb, var(--status-fail) 35%, transparent); }
}

.lib-del-overlay{
  position:fixed; inset:0; z-index:100000;
  display:flex; align-items:center; justify-content:center; padding:20px;
  background:color-mix(in srgb, #000 55%, transparent);
}
.lib-del-dialog{
  width:100%; max-width:460px; max-height:88vh; overflow:auto;
  padding:22px; border-radius:12px; direction:rtl; text-align:right;
  font-family:'Rubik',sans-serif;
  /* Canvas/CanvasText as fallbacks, which no other card in this file bothers
     with. They are here because this one card is a destructive confirmation:
     if the token sheet ever fails to load, every other surface renders
     transparent and looks broken, while THIS one would render an invisible
     dialog on top of the posts it is about to delete — unreadable, but still
     clickable. Canvas follows the OS light/dark setting, so the fallback is
     correct in both themes rather than a hardcoded white. */
  background:var(--surface, Canvas); color:var(--text, CanvasText);
  border:1px solid var(--border); box-shadow:0 24px 60px rgba(0,0,0,.4);
}
.lib-del-confirm{
  padding:9px 18px; border-radius:6px; cursor:pointer;
  font-size:var(--fs-200); font-weight:600; font-family:'Rubik',sans-serif;
  color:var(--on-accent); background:var(--status-fail);
  border:1px solid var(--status-fail);
}
.lib-del-confirm:disabled{ opacity:.5; cursor:not-allowed; }

@media (max-width:640px){
  /* The two choices stack, and the safe one stays first in the DOM so it is
     also first in the tab order and first under the thumb. */
  .lib-del-dialog{ padding:18px; }
  .lib-del-dialog .btn-secondary, .lib-del-confirm{ width:100%; }
  .lib-toolbar{ gap:8px; }
  .lib-trash{ margin-left:0; width:100%; justify-content:center; }
}

/* ── Copy Studio ────────────────────────────────────────────────────────────
   The platform-aware editor (renderCopyStudio in dashboard.js). Every colour
   and size here is a token from shared/dashboard-tokens.css, so the panel
   follows the theme switch without a second palette to keep in sync.

   Severity is never carried by colour alone: each finding has a glyph and a
   Hebrew word ("חוסם" / "אזהרה") beside the tint, and the character meter has
   its number printed above it. WCAG 1.4.1. */

.copy-bar{
  display:flex; flex-wrap:wrap; gap:var(--sp-3);
  align-items:center; justify-content:space-between; margin-bottom:var(--sp-4);
}
.copy-chips{ display:flex; flex-wrap:wrap; gap:var(--sp-2); }
.copy-loc{ display:flex; gap:var(--sp-2); }

.copy-chip{
  padding:var(--sp-2) var(--sp-3); border-radius:var(--r-full);
  border:1px solid var(--border-2); background:var(--surface);
  color:var(--text-2); font-size:var(--fs-100); line-height:var(--lh-100);
  font-weight:var(--fw-medium); font-family:'Rubik',sans-serif; cursor:pointer;
  transition:background .15s var(--ease-out), color .15s var(--ease-out);
}
.copy-chip:hover{ background:var(--accent-soft); color:var(--text); }
.copy-chip.is-on{
  background:var(--accent); border-color:var(--accent); color:var(--on-accent);
}
.copy-chip:focus-visible{ outline:2px solid var(--select-ring); outline-offset:2px; }

/* Editor beside its report on a desk, stacked on a phone. The report comes
   SECOND in the DOM so a screen reader meets the text it describes first. */
.copy-grid{ display:grid; grid-template-columns:1fr 1fr; gap:var(--sp-4); align-items:start; }
@media (max-width:900px){ .copy-grid{ grid-template-columns:1fr; } }

.copy-label{
  display:block; margin-bottom:var(--sp-2);
  font-size:var(--fs-100); line-height:var(--lh-100);
  letter-spacing:var(--tracking-caps); text-transform:uppercase;
  font-weight:var(--fw-semi); color:var(--text-3);
}
.copy-text{
  width:100%; min-height:280px; resize:vertical;
  padding:var(--sp-3); border-radius:var(--r-md);
  border:1px solid var(--border-2); background:var(--surface); color:var(--text);
  font-size:var(--fs-200); line-height:var(--lh-200); font-family:'Rubik',sans-serif;
}
.copy-text:focus-visible{ outline:2px solid var(--select-ring); outline-offset:1px; }

.copy-verdict{
  display:flex; align-items:center; gap:var(--sp-3); flex-wrap:wrap;
  padding:var(--sp-3); border-radius:var(--r-md); margin-bottom:var(--sp-4);
  font-size:var(--fs-200); line-height:var(--lh-200);
  border:1px solid var(--border-2);
}
.copy-verdict.is-ok{ color:var(--status-done); border-color:var(--status-done); }
.copy-verdict.is-bad{ color:var(--status-fail); border-color:var(--status-fail); }
.copy-verdict span{ color:var(--text-2); }

.copy-counts{ display:grid; grid-template-columns:repeat(4,1fr); gap:var(--sp-2); }
.copy-count{
  padding:var(--sp-3) var(--sp-2); border-radius:var(--r-md);
  background:var(--surface-2); border:1px solid var(--card-line); text-align:center;
}
.copy-count-v{
  font-size:var(--fs-300); line-height:var(--lh-300);
  font-weight:var(--fw-bold); color:var(--text); font-variant-numeric:tabular-nums;
}
.copy-count-x{ font-size:var(--fs-100); color:var(--text-3); font-weight:var(--fw-regular); }
.copy-count-l{
  margin-top:var(--sp-1); font-size:var(--fs-100); line-height:var(--lh-100);
  color:var(--text-3);
}

.copy-meter{
  height:6px; border-radius:var(--r-full); background:var(--surface-3, var(--surface-2));
  border:1px solid var(--card-line); overflow:hidden; margin-top:var(--sp-3);
}
.copy-meter-fill{
  height:100%; background:var(--accent);
  transition:width .18s var(--ease-out);
}
.copy-meter-fill.is-over{ background:var(--status-fail); }

.copy-finds{ list-style:none; padding:0; margin:var(--sp-4) 0 0; display:grid; gap:var(--sp-2); }
.copy-find{
  display:flex; gap:var(--sp-2); align-items:flex-start;
  padding:var(--sp-2) var(--sp-3); border-radius:var(--r-sm);
  font-size:var(--fs-200); line-height:var(--lh-200);
  border:1px solid var(--card-line); background:var(--surface-2); color:var(--text-2);
}
.copy-find-b{
  flex:0 0 auto; width:18px; height:18px; border-radius:var(--r-full);
  display:grid; place-items:center;
  font-size:var(--fs-100); font-weight:var(--fw-bold); color:var(--on-accent);
}
.copy-find.sev-error   .copy-find-b{ background:var(--status-fail); }
.copy-find.sev-warning .copy-find-b{ background:var(--status-warn); }
.copy-find.sev-info    .copy-find-b{ background:var(--status-idle); }
.copy-find b{ color:var(--text); }

.copy-preview{
  margin-top:var(--sp-4); padding:var(--sp-3);
  border-radius:var(--r-md); border:1px solid var(--card-line); background:var(--surface-2);
}
.copy-preview-h{
  font-size:var(--fs-100); line-height:var(--lh-100); color:var(--text-3);
  letter-spacing:var(--tracking-caps); text-transform:uppercase;
  font-weight:var(--fw-semi); margin-bottom:var(--sp-2);
}
.copy-preview-b{
  font-size:var(--fs-200); line-height:var(--lh-200); color:var(--text);
  white-space:pre-wrap; word-break:break-word;
}
/* Everything past the platform's cutoff is dimmed rather than hidden — the
   writer needs to see what the reader will not. */
.copy-fold-mark{ color:var(--text-3); font-weight:var(--fw-semi); }
.copy-folded{ color:var(--text-3); opacity:.7; }

.copy-rules{ margin:var(--sp-4) 0 0; display:grid; gap:var(--sp-1); }
.copy-rule{ display:flex; gap:var(--sp-2); justify-content:space-between; align-items:baseline; }
.copy-rule dt{ font-size:var(--fs-100); line-height:var(--lh-100); color:var(--text-3); }
.copy-rule dd{
  margin:0; font-size:var(--fs-100); line-height:var(--lh-100);
  color:var(--text-2); font-weight:var(--fw-medium); text-align:end;
}

.copy-empty{ padding:var(--sp-8) var(--sp-4); text-align:center; }
.copy-empty-t{ font-size:var(--fs-200); line-height:var(--lh-200); color:var(--text); font-weight:var(--fw-semi); }
.copy-empty-s{ margin-top:var(--sp-2); font-size:var(--fs-100); line-height:var(--lh-100); color:var(--text-3); }

.copy-skipped{ margin-top:var(--sp-4); font-size:var(--fs-100); line-height:var(--lh-100); color:var(--text-3); }
.copy-skipped summary{ cursor:pointer; color:var(--text-2); }
.copy-skipped ul{ margin:var(--sp-2) 0 0; padding-inline-start:var(--sp-4); }
.copy-note{ margin:var(--sp-2) 0 0; color:var(--text-3); }
.copy-prov{
  margin-top:var(--sp-4); padding-top:var(--sp-2); border-top:1px solid var(--card-line);
  font-size:var(--fs-100); line-height:var(--lh-100); color:var(--text-3);
}

@media (prefers-reduced-motion:reduce){
  .copy-chip, .copy-meter-fill{ transition:none; }
}

/* ── Content library ─────────────────────────────────────────────────────────
   Rebuilt from an inline-style grid of badges into a channel-first surface.
   Every value below is a token: the old cards carried ~30 literal sizes and
   colours in dashboard.js, which is why the library never picked up a theme
   change the rest of the dashboard got.

   Logical properties throughout (inline-start, not left), so RTL is the
   layout rather than a mirror applied to an LTR one. */

.lib-fold-label{
  font-size:var(--fs-100); font-weight:var(--fw-semi);
  letter-spacing:.08em; text-transform:uppercase; color:var(--text-3);
}
.lib-sum{ font-size:var(--fs-100); line-height:var(--lh-100); color:var(--text-3); }
.lib-sum-sep{ color:var(--border-2); margin-inline:var(--sp-1); }
.lib-sum-n[data-st="draft"]{ color:var(--text-3); }
.lib-sum-n[data-st="approved"]{ color:var(--status-done); }
.lib-sum-n[data-st="published"]{ color:#14b8a6; }

/* Said before anything is selected, not after a confirmation dialog. */
.lib-notice{
  display:flex; flex-wrap:wrap; gap:var(--sp-1);
  padding:var(--sp-3) var(--sp-4); margin-block-end:var(--sp-4);
  border-radius:var(--r-md);
  border:1px solid color-mix(in srgb, var(--status-warn) 40%, transparent);
  background:color-mix(in srgb, var(--status-warn) 10%, transparent);
  font-size:var(--fs-100); line-height:var(--lh-200); color:var(--text-2);
}

/* ── Controls row ─────────────────────────────────────────────────────────── */
.lib-controls{
  display:flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap;
  margin-block-end:var(--sp-3);
}
.lib-search{
  flex:1 1 240px; min-inline-size:0; min-block-size:44px;
  padding:var(--sp-2) var(--sp-3); border-radius:var(--r-md);
  border:1px solid var(--border); background:var(--surface-2); color:var(--text);
  /* 16px, deliberately: iOS Safari zooms the whole page when a focused input
     is under 16px, and the zoom does not come back. */
  font-size:16px; font-family:'Rubik',sans-serif;
}
.lib-search::placeholder{ color:var(--text-3); }
.lib-search:focus-visible{ outline:none; box-shadow:var(--sh-focus); border-color:var(--accent); }

.lib-sort, .lib-viewtog{
  min-block-size:44px; padding:var(--sp-2) var(--sp-3);
  border-radius:var(--r-md); border:1px solid var(--border);
  background:var(--surface-2); color:var(--text-2);
  font-size:var(--fs-200); font-family:'Rubik',sans-serif; cursor:pointer;
}
.lib-sort:focus-visible, .lib-viewtog:focus-visible{ outline:none; box-shadow:var(--sh-focus); }
.lib-synced{
  margin-inline-start:auto; font-size:var(--fs-100); color:var(--text-3);
  align-self:center;
}

/* ── Filter and channel chips ─────────────────────────────────────────────── */
.lib-chips{
  display:flex; gap:var(--sp-2); flex-wrap:wrap; margin-block-end:var(--sp-3);
}
.lib-chip{
  display:inline-flex; align-items:center; gap:var(--sp-2);
  min-block-size:36px; padding:var(--sp-1) var(--sp-3);
  border-radius:var(--r-full); cursor:pointer;
  border:1px solid var(--border-2); background:transparent; color:var(--text-3);
  font-size:var(--fs-200); font-weight:var(--fw-medium); font-family:'Rubik',sans-serif;
  transition:border-color var(--dur-fast) var(--ease-out),
             background var(--dur-fast) var(--ease-out),
             color var(--dur-fast) var(--ease-out);
}
.lib-chip.is-on{
  border-color:var(--accent); color:var(--accent-on-tint);
  background:color-mix(in srgb, var(--accent) 12%, transparent);
}
.lib-chip-n{
  font-size:var(--fs-100); font-weight:var(--fw-semi);
  padding-inline:var(--sp-2); border-radius:var(--r-full);
  /* --text-2: --text-3 on the --surface-3 well measured 4.47:1 light,
     4.26:1 dark. */
  background:var(--surface-3); color:var(--text-2);
}
.lib-chip.is-on .lib-chip-n{
  background:color-mix(in srgb, var(--accent) 20%, transparent); color:var(--accent-on-tint);
}
.lib-chip:focus-visible{ outline:none; box-shadow:var(--sh-focus); }
@media (hover:hover){
  .lib-chip:hover{ border-color:var(--accent); color:var(--text); }
}

/* ── Grid ─────────────────────────────────────────────────────────────────── */
.lib-grid{
  display:grid; gap:var(--sp-4);
  /* minmax(0,…) rather than minmax(280px,…): a fixed floor cannot shrink under
     a 375px viewport and pushes the whole page into horizontal scroll, which
     #content-wrap then clips — so the content is lost, not scrollable. */
  grid-template-columns:repeat(auto-fill,minmax(min(280px,100%),1fr));
}
.lib-grid--list{ grid-template-columns:1fr; }
.lib-grid--list .lib-card-excerpt{ -webkit-line-clamp:2; }

/* ── Card ─────────────────────────────────────────────────────────────────── */
.lib-card{
  position:relative; overflow:hidden; cursor:pointer;
  display:flex; flex-direction:column; gap:var(--sp-2);
  padding:var(--sp-4); padding-block-start:calc(var(--sp-4) + 3px);
  transition:transform var(--dur-fast) var(--ease-out),
             box-shadow var(--dur-fast) var(--ease-out),
             border-color var(--dur-fast) var(--ease-out);
}
.lib-card:focus-visible{ outline:none; box-shadow:var(--sh-focus); }
@media (hover:hover){
  .lib-card:hover{ transform:translateY(-2px); box-shadow:var(--sh-md); }
  .lib-card:hover .lib-card-actions{ opacity:1; }
}
@media (prefers-reduced-motion:reduce){
  .lib-card{ transition:none; }
  .lib-card:hover{ transform:none; }
}

/* The channel, read at a glance down a column of 24 cards. Colour is never the
   only carrier — .lib-ch names the channel in words on every card, and the
   brand mark carries it a third way. */
.lib-card-accent{
  position:absolute; inset-block-start:0; inset-inline:0; block-size:3px;
  background:var(--ch-color,var(--border-2));
}
.lib-card[data-ch="instagram"]{ --ch-color:#E4405F; }
.lib-card[data-ch="facebook"]{ --ch-color:#1877F2; }
.lib-card[data-ch="tiktok"]{ --ch-color:var(--text-2); }
.lib-card[data-ch="google_business"]{ --ch-color:#14b8a6; }
.lib-card[data-ch="youtube"]{ --ch-color:#FF0000; }
.lib-card[data-ch="whatsapp"]{ --ch-color:#25D366; }
.lib-card[data-ch="linkedin"]{ --ch-color:#0A66C2; }
.lib-card[data-ch="blog"]{ --ch-color:var(--status-running); }
.lib-card[data-ch="ebook"]{ --ch-color:var(--status-warn); }
.lib-card[data-ch="unassigned"]{ --ch-color:var(--border-2); }

.lib-card-head{ display:flex; align-items:center; gap:var(--sp-2); min-inline-size:0; }
.lib-card-status{ margin-inline-start:auto; flex-shrink:0; }

.lib-ch{
  display:inline-flex; align-items:center; gap:var(--sp-2); min-inline-size:0;
}
.lib-ch-name{
  font-size:var(--fs-100); font-weight:var(--fw-semi); color:var(--text-2);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}

.lib-card-title{
  margin:0; font-size:var(--fs-300); line-height:var(--lh-300);
  font-weight:var(--fw-semi); color:var(--text);
  font-family:'Rubik',sans-serif; direction:rtl;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  overflow:hidden;
}
.lib-card-excerpt{
  margin:0; font-size:var(--fs-200); line-height:var(--lh-200); color:var(--text-3);
  font-family:'Rubik',sans-serif; direction:rtl;
  display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical;
  overflow:hidden;
}

.lib-card-foot{
  display:flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap;
  margin-block-start:auto; padding-block-start:var(--sp-2);
  border-block-start:1px solid var(--card-line);
}
.lib-card-meta{ display:inline-flex; align-items:center; gap:var(--sp-2); flex-wrap:wrap; }
.lib-card-wc{ font-size:var(--fs-100); color:var(--text-3); }
.lib-card-actions{
  margin-inline-start:auto; display:inline-flex; align-items:center; gap:var(--sp-1);
  /* Revealed on hover on a pointer device, always visible on touch — where
     there is no hover to reveal them with. */
  opacity:1;
}
@media (hover:hover){
  .lib-card-actions{ opacity:0; transition:opacity var(--dur-fast) var(--ease-out); }
  .lib-card:focus-within .lib-card-actions{ opacity:1; }
}
.lib-row-act{
  min-block-size:32px; padding:var(--sp-1) var(--sp-2);
  border-radius:var(--r-sm); cursor:pointer;
  background:transparent; border:1px solid var(--border-2); color:var(--text-3);
  font-size:var(--fs-100); font-family:'Rubik',sans-serif;
  transition:color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.lib-row-act:focus-visible{ outline:none; box-shadow:var(--sh-focus); }
@media (hover:hover){
  .lib-row-act:hover{ color:var(--text); border-color:var(--accent); }
}
.lib-row-del:disabled, .lib-row-act:disabled{
  opacity:.4; cursor:not-allowed;
}

/* ── Selection bar ────────────────────────────────────────────────────────── */
.lib-selall{
  display:flex; align-items:center; gap:var(--sp-2); cursor:pointer;
  font-size:var(--fs-200); color:var(--text-2); min-block-size:44px;
}
.lib-sel-count{ font-size:var(--fs-100); color:var(--text-3); }
.lib-clear{ font-size:var(--fs-100); }
/* Quiet until it has work to do, then it reads as an action bar. It stays in
   the DOM either way, so the controls never move under the pointer
   mid-selection. */
.lib-toolbar.is-armed{
  border-color:var(--accent);
  background:color-mix(in srgb, var(--accent) 7%, var(--surface-2));
}

/* ── Large-batch confirmation ─────────────────────────────────────────────── */
.lib-del-typed-lbl{
  display:block; font-size:var(--fs-100); color:var(--text-2);
  margin-block-end:var(--sp-2);
}
.lib-del-code{
  display:block; inline-size:fit-content; margin-block-end:var(--sp-2);
  padding:var(--sp-1) var(--sp-3); border-radius:var(--r-sm);
  background:var(--surface-3); border:1px solid var(--border);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:var(--fs-200); font-weight:var(--fw-bold); color:var(--text);
  user-select:all;
}
.lib-del-typed{ inline-size:100%; margin-block-end:var(--sp-4); }

@media (max-width:640px){
  .lib-controls{ gap:var(--sp-2); }
  /* Row actions are 32px on a desktop, where a mouse can hit them, and the
     44px floor on touch — measured at 375px, where they were 32 and 26. */
  .lib-row-act, .lib-row-del{ min-block-size:44px; min-inline-size:44px; }
  .lib-synced{ margin-inline-start:0; inline-size:100%; }
  .lib-sort, .lib-viewtog{ flex:1 1 auto; }
  .lib-card-actions{ opacity:1; }
  /* The chip row scrolls rather than wrapping into four stacked lines that
     push the grid below the fold on a phone. */
  .lib-chips{
    flex-wrap:nowrap; overflow-x:auto; scrollbar-width:none;
    padding-block-end:var(--sp-1);
  }
  .lib-chips::-webkit-scrollbar{ display:none; }
  .lib-chip{ flex-shrink:0; min-block-size:44px; }
}

/* The artefact's own label — 'tip', 'question', 'social_proof'. Kept because
   it is real and sortable, demoted because it is not a title. */
.lib-card-tag{
  font-size:var(--fs-100); color:var(--text-2);   /* --text-3 on --surface-3: 4.47:1 */
  padding-inline:var(--sp-2); border-radius:var(--r-xs);
  background:var(--surface-3); white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; max-inline-size:9ch;
}

/* ── Stage pulse ───────────────────────────────────────────────────────────
   The Overview's status header, and the one loud element on the page. Sized
   mobile-first: every dimension below is the phone value, and the only thing
   that changes on a wider screen is that the rail gets taller.

   The segment rule is the important one. `.fnl-seg` next door carries
   `flex:0 0 auto; min-inline-size:3px`, which is how a bar with many segments
   overflows its own track on a narrow screen — N segments each with a px
   floor cannot be made to fit. These segments are `flex:1 1 0` with a ZERO
   floor, so twenty-three of them fit any width the phone has, including 320.
   Do not give this a min-inline-size.                                      */
.pulse{
  background:var(--surface); border:1px solid var(--border);
  border-radius:var(--r-lg); box-shadow:var(--sh-xs);
  padding:var(--sp-4); margin-block-end:var(--sp-4);
  display:flex; flex-direction:column; gap:var(--sp-3);
}
.pulse.is-fail{ border-color:color-mix(in srgb, var(--status-fail) 38%, var(--border)); }

.pulse-hd{ display:flex; align-items:center; gap:var(--sp-3); min-inline-size:0; }

/* A fraction is one LTR token. As two sibling spans in an RTL container the
   bidi algorithm reorders them and "9/22" paints as "9/ 22" — the same trap
   .kpi-frac exists to dodge, so this carries dir="ltr" in the markup too. */
.pulse-count{
  display:flex; align-items:baseline; flex:none;
  font-family:'Rubik', sans-serif; font-variant-numeric:tabular-nums;
  letter-spacing:var(--tracking-tight); line-height:1;
}
.pulse-done{ font-size:clamp(34px, 11vw, 44px); font-weight:var(--fw-bold); color:var(--text); }
.pulse-of  { font-size:clamp(15px, 4.5vw, 19px); font-weight:var(--fw-semi); color:var(--text-3); }

.pulse-meta { min-inline-size:0; flex:1 1 auto; }
.pulse-title{
  font-size:var(--fs-100); font-weight:var(--fw-semi); color:var(--text-3);
  text-transform:uppercase; letter-spacing:var(--tracking-caps);
}
.pulse-sub{
  font-size:var(--fs-200); color:var(--text-2); margin-block-start:2px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}

.pulse-beat{
  inline-size:9px; block-size:9px; border-radius:var(--r-full); flex:none;
  background:var(--status-idle);
}
.pulse.is-running .pulse-beat{ background:var(--status-running); }
.pulse.is-fail    .pulse-beat{ background:var(--status-fail); }
.pulse.is-done    .pulse-beat{ background:var(--status-done); }

.pulse-rail{ display:flex; gap:2px; min-inline-size:0; }
.pulse-seg{
  flex:1 1 0; min-inline-size:0;
  block-size:10px; border-radius:2px;
  background:var(--surface-3);
  transition:background var(--dur-base) var(--ease-out);
}
.pulse-seg.is-done   { background:var(--status-done); }
.pulse-seg.is-running{ background:var(--status-running); }
.pulse-seg.is-fail   { background:var(--status-fail); }
.pulse-seg.is-warn   { background:var(--status-warn); }
.pulse-seg.is-redone { background:var(--status-warn); }
.pulse-seg.is-pending{ background:var(--surface-3); }
.pulse-seg.is-skipped{ background:var(--surface-3); opacity:.45; }

@media (min-width:768px){
  .pulse-seg{ block-size:14px; border-radius:3px; }
  .pulse-rail{ gap:3px; }
}

/* Motion is the only thing on this page that says "live". It is also the
   first thing that has to go when the reader has asked for less of it, so
   every animation here is opt-in via no-preference rather than opt-out. */
@media (prefers-reduced-motion: no-preference){
  .pulse.is-running .pulse-beat{ animation:pulse-beat 1.6s var(--ease-in-out) infinite; }
  .pulse.is-running .pulse-seg.is-running{ animation:pulse-seg 1.6s var(--ease-in-out) infinite; }
  .pulse-done.is-bumped{ animation:pulse-bump 460ms var(--ease-out); }
  .pulse-seg.is-changed{ animation:pulse-flash 620ms var(--ease-out); }
}
@keyframes pulse-beat { 0%,100%{ opacity:1; transform:scale(1) } 50%{ opacity:.4; transform:scale(.8) } }
@keyframes pulse-seg  { 0%,100%{ opacity:1 } 50%{ opacity:.45 } }
@keyframes pulse-bump { 0%{ transform:scale(1) } 30%{ transform:scale(1.15) } 100%{ transform:scale(1) } }
@keyframes pulse-flash{ 0%{ transform:scaleY(1) } 40%{ transform:scaleY(1.9) } 100%{ transform:scaleY(1) } }

/* ── Phone top bar: identity first ─────────────────────────────────────────
   Measured at 390px before this rule: the search box took 125px, the client
   switcher 101px, and the switcher truncated — a 138px name rendered into
   91px, so "מרפאת שיקום" read as "מרנ". The row was spending its widest
   allocation on a control you cannot use one-handed while standing up, and
   clipping the one piece of information that says which business you are
   looking at. Whose dashboard is this outranks searching it.

   The search stays reachable — collapsing, not hiding. tests/test_nav_
   reachability.py treats a control you cannot get to as gone, and it is
   right: this is a 44px tap target that expands on focus, not a removal. */
@media (pointer:coarse), (max-width:768px){
  /* A ⌘ hint on a device with no ⌘ key. */
  #spotlight-kbd{ display:none !important; }

  #hdr-center{
    flex:0 0 auto !important;
    inline-size:44px; max-inline-size:44px !important;
    padding:0 !important; margin:0 !important;
    transition:max-inline-size var(--dur-base) var(--ease-out),
               inline-size    var(--dur-base) var(--ease-out);
  }
  #hdr-center:focus-within{
    inline-size:min(62vw, 260px); max-inline-size:min(62vw, 260px) !important;
  }
  /* Collapsed, the placeholder cannot be read, so the control has to say what
     it is some other way. Inlined as a data URI: a strict CSP and an offline
     first paint both rule out fetching a 300-byte icon. currentColor is not
     available inside url(), hence the literal stroke — it is --text-3's dark
     value, and the light theme override follows. */
  #spotlight-input{
    padding-inline:34px 10px !important;
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%239aa39f' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='7' cy='7' r='5'/%3E%3Cpath d='M11 11l4 4'/%3E%3C/svg%3E");
    background-repeat:no-repeat;
    background-position:center right 13px;
    background-size:16px 16px;
  }
  :root:not([data-theme="dark"]) #spotlight-input{
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%2364706e' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='7' cy='7' r='5'/%3E%3Cpath d='M11 11l4 4'/%3E%3C/svg%3E");
  }

  /* The room the search gave back. min-inline-size:0 is what actually lets
     the ellipsis happen inside a flex row instead of the name forcing the
     row wider — the rest of this file's overflow fixes are the same rule. */
  #mob-client-bar{
    flex:1 1 auto !important;
    min-inline-size:0 !important;
    max-inline-size:none !important;
  }
}

/* ── Empty states on a phone ───────────────────────────────────────────────
   .ea-empty-state is `padding:32px 16px` at every width, and the Overview
   renders one per widget that has no data yet. Measured on a 390px viewport
   against a client mid-pipeline: the Overview was 7,886px — twenty screens —
   and most of that was empty cards, each spending a 32px pad, a 32px emoji
   and a centred two-line paragraph to say "not yet".

   An empty widget is a placeholder, not a destination. It keeps its sentence
   so nothing becomes a silent blank, and gives up the hero proportions. The
   emoji goes: at 32px it was the largest glyph in a card containing no
   information, which is the wrong thing for the eye to land on while
   scrolling past nine of them. */
@media (max-width:768px){
  .ea-empty-state{ padding:var(--sp-4) var(--sp-3); }
  .ea-empty-icon { font-size:20px; margin-block-end:var(--sp-2); opacity:.55; }
  .ea-empty-title{ font-size:var(--fs-200); }
  .ea-empty-sub  { line-height:1.55; }
}

/* The Overview's h1 says "מבט על". So does the bottom tab bar's active item,
   40px below it, which is also how the reader got here. Dropping the
   duplicate reclaims the row for the picker, which is the only control in
   this header that does anything. */
@media (max-width:768px){
  .page-hdr{
    margin-block-end:var(--sp-3) !important;
    justify-content:flex-end;
  }
  #overview-standard > .page-hdr > .page-hdr-main{ display:none; }
}

/* ── Phone: the chat button must not sit on the tab bar ────────────────────
   #chat-fab is inset-block-end:20px, which in this RTL layout puts it in the
   bottom-INLINE-END (left) corner — the same corner #mobile-tabs puts its
   "± התאם תצוגה" customise button in. The FAB is z-index 60, the bar is 29,
   so the FAB won.

   Hit-tested on a 390px viewport, sampling a 3×3 grid over the customise
   button: 4 of 9 points were intercepted by #chat-fab, including both points
   over the button's own ± glyph. The visible part of the control was the
   unreachable part.

   Lifting the FAB clear of the bar fixes it without moving either control to
   a corner it does not belong in. The panel follows the button up, or it
   opens underneath the bar it just cleared. */
/* And the page must end above the lifted FAB, not just above the bar: the
   content reserve was nav + 12px, so at full scroll the last 46px of every tab
   sat behind the button. Measured at 390px: Intelligence's "Apply & Refresh"
   lost 3 of 9 hit points to #chat-fab at maximum scroll. nav + 12 + 46 + 12.
   A longhand in its own later rule, so it does not fight the shorthand in the
   breakpoint block above (same importance, later wins). */
@media (max-width:768px){
  #content-wrap{ padding-bottom:calc(var(--mobile-nav-h) + 70px) !important; }
  #chat-fab  { inset-block-end:calc(var(--mobile-nav-h) + 12px); }
  #chat-panel{ inset-block-end:calc(var(--mobile-nav-h) + 70px);
               max-block-size:min(520px, calc(100vh - var(--mobile-nav-h) - 150px));
               max-block-size:min(520px, calc(100dvh - var(--mobile-nav-h) - 150px)); }
}

/* ── Phone: the "כל האזורים" strip is a third way to navigate ──────────────
   .sl-strip is a nav strip of every zone. Its own comment explains the
   placement: "it sits at the bottom because the sidebar already carries these
   twelve destinations at all times." On a phone the sidebar is
   `display:none` — but the destinations are still carried, by the bottom tab
   bar and by the "עוד" sheet, which openNavSheet() fills with every
   configured tab. tests/test_nav_mobile_browser.py asserts that reachability
   directly, so this hides a duplicate rather than a route.

   It cost 358px at the very bottom of a 4,202px page — the least-read
   position on the least-read part of the screen. */
@media (max-width:768px){
  .sl-strip{ display:none !important; }
}

/* ── Phone: one floor for every control, and 16px text in every field ───────
   The touch-floor list above is an allowlist, and an allowlist only covers
   what somebody remembered. Sweeping all 27 tabs (tests/test_touch_floor_sweep)
   found ~75 controls under 44px that no selector named: calendar prev/next,
   the Intelligence rule chips, Copy Studio chips, Flyer and Leads fields,
   Billing and Site-builder buttons, unclassed inline-styled buttons.

   Text fields: iOS Safari zooms the whole page when one under 16px takes
   focus and never zooms back. 57 fields were 11-14px, most set inline by JS,
   which is why font-size is !important here and nowhere else in this block —
   an inline style outranks any selector without it.

   .tt-btn and #ea-pw-toggle are left out on purpose: their painted size is
   the design and a transparent ::after already carries the 44px hit area.
   .mc-dot is left out too: ten 44px dots overflow a phone, so the dots are
   24px (WCAG 2.2 minimum) and are hidden under 480px, where the carousel's
   44px arrows and swipe carry the navigation. */
@media (pointer:coarse), (max-width:768px){
  input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]):not([type=hidden]):not([type=color]),
  select, textarea{ font-size:16px !important; min-height:44px; box-sizing:border-box; }
  button:not(.tt-btn):not(#ea-pw-toggle):not(.mc-dot), .rule-chip, .copy-chip, .lc-key{
    min-height:44px; min-width:44px; }
  /* WebKit sizes a native <select> from its own metrics and ignores min-height:
     five of them measured 24px with the rule above. An explicit height is
     honoured. */
  select{ height:44px; }
  .rule-chip{ display:inline-flex; align-items:center; }
  /* Site Builder preview: "open in a new tab" painted 81x17. Same floor as the
     buttons; the text keeps its size, the box grows around it. */
  .wiz-open-link{ display:inline-flex; align-items:center; min-height:44px; padding:0 8px; }
  label:has(> input[type=checkbox]), label:has(> input[type=radio]){
    min-height:44px; display:flex; align-items:center; gap:var(--sp-2); }
  /* Unclassed disclosure rows (the Competitive-analysis source folds) painted
     20px tall at 390 and 768; the classed .ov-fold-sum already meets the
     floor. Padding, not display:flex — flex would drop the ::marker. */
  .ea-card > summary:not([class]){ padding-block:12px; }
  /* Research section headers: a clickable row 33px tall at 390 and 768. */
  .rsec-toggle{ min-height:44px; }
}

/* ── Scroll containment ────────────────────────────────────────────────────
   Nothing here set overscroll-behavior, so on iOS Safari a swipe that reaches
   the end of a sheet, the chat log, a modal or a dropdown carried on into the
   page behind it. `contain` keeps the gesture inside the box. It changes
   nothing when the box does not scroll, and nothing on desktop wheels beyond
   the same containment. */
#sb-nav, .chat-log, .sheet-bd, #modal-body, #onboard-inner, .client-dropdown,
.lib-del-dialog, .rf-raw > pre{ overscroll-behavior:contain; }

/* ── Touch: the rest of the hover lifts ────────────────────────────────────
   The @media (hover:none) block further up resets transform/filter for seven
   selectors, and it is incomplete in two ways that measurement found:
   specificity — `.flow-card:not(:disabled):hover` (0,3,0) beats the reset's
   `.flow-card:hover` (0,2,0), so every enabled flow card stayed lifted after a
   tap — and source order — `.fnl-seg:hover` comes after the block and wins.
   `#chat-fab:hover` was never in it at all: forced :hover in a touch context
   left it 2px up. This block sits last and repeats each selector exactly, so
   it ties on specificity and wins on order. tests/test_hover_neutralised.py
   fails when a new lifting hover rule is not listed in a hover:none block. */
@media (hover:none){
  #chat-fab:hover, .lib-card:hover, .media-thumb:hover,
  .flow-card:not(:disabled):hover,
  .att-row:hover .att-go, .flow-card:not(:disabled):hover .fc-ico{ transform:none; }
  .fnl-seg:hover{ filter:none; }
}


/* ── Client research sheet ─────────────────────────────────────────────── */
.f-check{display:flex;align-items:flex-start;gap:10px;min-height:44px;padding:8px 0;
  font-size:var(--fs-200);color:var(--text-2);cursor:pointer}
.f-check input{width:22px;height:22px;flex:none;margin:0;min-height:0}
.rs-head{display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-size:var(--fs-200)}
.rs-h{font-size:var(--fs-200);font-weight:700;color:var(--text-2);margin:16px 0 6px}
.rs-list,.rs-plan{list-style:none;margin:0;padding:0}
.rs-plan{list-style:disc;padding-inline-start:20px}
.rs-plan li{margin-bottom:6px;font-size:var(--fs-200)}
.rs-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-height:44px;
  padding:6px 0;border-bottom:1px solid var(--border);font-size:var(--fs-200)}
.rs-row > span:first-child{flex:1 1 40%}
.rs-why{display:block;flex:1 1 100%;color:var(--text-2);font-size:13px;line-height:1.4}
.rs-plan .rs-why{margin-top:2px}
.rs-pill{display:inline-block;padding:2px 10px;border-radius:999px;font-size:13px;font-weight:600;
  border:1px solid currentColor;color:var(--status-idle)}
.rs-done,.rs-draft{color:var(--status-done)}
.rs-running{color:var(--status-running)}
.rs-partial,.rs-skipped{color:var(--status-warn)}
.rs-failed{color:var(--status-fail)}


/* Publish plan card (integrations tab). Themed tokens only; rows wrap so a
   390px viewport never scrolls sideways. */
.pp-list { display:flex; flex-direction:column; gap:10px; margin:0; padding:0; list-style:none; }
.pp-row { display:flex; flex-wrap:wrap; align-items:center; gap:6px 10px;
  padding:10px 12px; background:var(--surface-2); border:1px solid var(--border);
  border-radius:var(--r-md); min-width:0; }
.pp-name { font-weight:600; font-size:13px; overflow-wrap:anywhere; }
.pp-chip { font-size:11px; font-weight:600; padding:2px 8px; border-radius:99px;
  white-space:nowrap; color:var(--pp-c); background:color-mix(in srgb, var(--pp-c) 13%, transparent); }
.pp-chip.is-ready { --pp-c:var(--status-done); }
.pp-chip.is-warn  { --pp-c:var(--status-warn); }
.pp-chip.is-idle  { --pp-c:var(--status-idle); }
.pp-note { flex-basis:100%; font-size:12px; color:var(--text-2); line-height:1.6; overflow-wrap:anywhere; }
.pp-foot { margin:12px 0 0; font-size:12px; color:var(--text-3); }


/* ── Plans tab ─────────────────────────────────────────────────────────── */
.plan-bar{display:flex;flex-wrap:wrap;align-items:center;gap:12px 20px;margin:0 0 10px;font-size:13px;color:var(--text-3)}
.plan-bar b{color:var(--text);font-variant-numeric:tabular-nums}
.plan-bar-btns{display:flex;gap:8px;margin-inline-start:auto}
.plan-bar-btns button,.plan-missing button{font:inherit;font-size:12px;min-height:32px;padding:6px 12px;border-radius:8px;border:1px solid var(--border);background:var(--surface-2);color:var(--text);cursor:pointer}
.plan-bar-btns button:hover,.plan-missing button:hover{border-color:var(--accent)}
.plan-seg{display:inline-flex;padding:3px;border-radius:10px;background:var(--surface-3);gap:2px}
.plan-seg button{font:inherit;font-size:13px;font-weight:500;min-height:34px;padding:6px 18px;border:0;border-radius:8px;background:transparent;color:var(--text-2);cursor:pointer;transition:background .18s cubic-bezier(.2,.8,.2,1),color .18s}
.plan-seg button:hover{color:var(--text)}
.plan-seg button.is-on{background:var(--surface);color:var(--accent);font-weight:700;box-shadow:0 1px 2px rgba(24,32,31,.1),0 2px 6px rgba(24,32,31,.06)}
.plan-seg button:focus-visible,.plan-bar-btns button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.plan-tally{display:flex;flex-wrap:wrap;gap:6px 16px}
.plan-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:0 0 16px;font-size:12px;color:var(--text-3)}
.plan-legend span{display:inline-flex;align-items:center;gap:6px}
.plan-grid{display:flex;flex-direction:column;gap:14px}
.plan-card{background:var(--surface-2);border:1px solid var(--border);border-radius:12px;overflow:hidden}
.plan-card[open]{border-color:var(--border-strong);box-shadow:0 1px 2px rgba(24,32,31,.04),0 6px 18px -8px rgba(24,32,31,.12)}
.plan-card>summary{display:grid;grid-template-columns:auto minmax(0,1.4fr) auto 96px auto;align-items:center;gap:14px;padding:14px 16px;cursor:pointer;list-style:none}
.plan-card>summary::-webkit-details-marker{display:none}
.plan-ico{display:grid;place-items:center;width:38px;height:38px;border-radius:10px;background:var(--accent-soft);color:var(--accent)}
.plan-card.is-done .plan-ico{background:color-mix(in srgb,var(--status-done) 12%,transparent);color:var(--status-done)}
.plan-head{display:flex;flex-direction:column;gap:2px;min-width:0}
.plan-head b{font-size:15px;color:var(--text)}
.plan-head small{font-size:12px;color:var(--text-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.plan-kpis{display:flex;gap:16px}
.plan-kpi{display:flex;flex-direction:column;align-items:center;min-width:56px}
.plan-kpi b{font-size:16px;color:var(--text);font-variant-numeric:tabular-nums}
.plan-kpi span{font-size:11px;color:var(--text-3);white-space:nowrap}
.plan-prog{position:relative;height:6px;border-radius:3px;background:var(--border);margin-bottom:14px}
.plan-prog i{position:absolute;inset:0 auto 0 0;border-radius:3px;background:var(--status-running)}
.plan-card.is-done .plan-prog i{background:var(--status-done)}
.plan-prog em{position:absolute;top:10px;inset-inline-start:0;font-style:normal;font-size:11px;color:var(--text-3)}
.plan-cta{display:flex;align-items:center;color:var(--accent)}
.plan-body{padding:16px 16px 18px;border-top:1px solid var(--border)}
/* the roadmap: one column per period, first period on the reading edge */
.road{display:grid;grid-template-columns:repeat(var(--road-n),minmax(0,1fr));gap:10px}
.road-col{display:flex;flex-direction:column;gap:8px;min-width:0;padding:12px;border-radius:10px;background:var(--bg);border:1px solid var(--border)}
.road-col.is-now{border-color:color-mix(in srgb,var(--accent) 45%,transparent);background:color-mix(in srgb,var(--accent) 4%,var(--bg))}
.road-hd{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 8px;padding-bottom:8px;border-bottom:1px solid var(--border)}
.road-hd b{font-size:14px;color:var(--text)}
.road-hd span{font-size:11px;color:var(--text-3);font-variant-numeric:tabular-nums}
.road-now{margin-inline-start:auto;font-style:normal;font-size:11px;font-weight:600;color:var(--accent-on-tint);padding:1px 8px;border-radius:999px;background:var(--accent-soft)}
.road-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.road-step{display:grid;grid-template-columns:14px minmax(0,1fr);gap:8px;align-items:start;font-size:13px;line-height:1.45;color:var(--text)}
.road-mark{display:flex;padding-top:2px}
.is-done .road-mark,.plan-legend .is-done{color:var(--status-done)}
.is-todo .road-mark,.plan-legend .is-todo{color:var(--status-warn)}
.is-item .road-mark,.plan-legend .is-item{color:var(--accent)}
.is-repeat .road-mark,.plan-legend .is-repeat{color:var(--status-idle)}
.road-step.is-done .road-t{color:var(--text-3)}
.road-step.is-repeat .road-t{color:var(--text-2)}
.road-t em{font-style:normal;font-size:11px;font-weight:600;color:var(--text-3)}
.road-stage{font-size:11px;padding:0 5px;border-radius:4px;border:1px solid var(--border);color:var(--text-3);vertical-align:1px}
.road-items{display:flex;flex-direction:column;gap:3px;margin-top:4px}
.road-items span{font-size:12px;color:var(--text-2);overflow-wrap:anywhere;padding-inline-start:8px;border-inline-start:1px solid var(--border)}
.road-items .road-more{border:0;padding:0;color:var(--text-3)}
.road-empty{margin:0;font-size:12px;color:var(--text-3)}
.plan-missing{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:14px 0 0;font-size:12px;color:var(--text-3)}
.plan-data{margin-top:14px;border-top:1px solid var(--border);padding-top:10px}
.plan-data>summary{cursor:pointer;font-size:12px;font-weight:600;color:var(--accent);min-height:44px;display:flex;align-items:center}
.plan-block{margin-top:16px}
.plan-block h4{margin:0 0 8px;font-size:12px;font-weight:700;color:var(--text-2);padding-bottom:4px;border-bottom:1px solid var(--border)}
.plan-list{margin:0;padding-inline-start:18px;font-size:13px;line-height:1.7;color:var(--text)}
.plan-empty{margin:0;font-size:12px;color:var(--text-3)}
.plan-chips{display:flex;flex-wrap:wrap;gap:6px}
.plan-chips span{font-size:12px;padding:3px 9px;border-radius:6px;border:1px solid var(--border);color:var(--text)}
.plan-cluster{margin-bottom:10px}
.plan-cluster b{font-size:12px;color:var(--accent)}
.plan-cluster em{font-style:normal;font-size:11px;color:var(--text-3);margin-inline-start:8px}
.plan-tbl-wrap{overflow-x:auto}
.plan-tbl{width:100%;border-collapse:collapse;font-size:12px}
.plan-tbl th{text-align:start;font-weight:600;color:var(--text-3);padding:6px 8px;border-bottom:1px solid var(--border);white-space:nowrap}
.plan-tbl td{padding:7px 8px;border-bottom:1px solid var(--border-2);color:var(--text);vertical-align:top}
.plan-tbl.is-narrow{width:auto;min-width:260px}
.plan-tbl:not(.is-narrow){min-width:560px}
.plan-tbl td:first-child{font-weight:500;min-width:110px}
.plan-card>summary:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.plan-card>summary:hover{background:color-mix(in srgb,var(--accent) 5%,transparent)}
@media (max-width:1100px){.road{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:760px){
  .plan-card>summary{grid-template-columns:auto minmax(0,1fr) auto;row-gap:10px}
  .plan-kpis{grid-column:1/-1;justify-content:space-around}
  .plan-prog{grid-column:1/-1;margin-bottom:16px}
  .plan-body{padding:12px 12px 16px}
  .plan-bar-btns{margin-inline-start:0}
  .plan-seg{width:100%}
  .plan-seg button{flex:1}
  .road{grid-template-columns:minmax(0,1fr)}
  .plan-tbl-wrap{margin-inline:-4px}
}
@media (prefers-reduced-motion:reduce){.plan-seg button{transition:none}}

/* Content scorecard — measurements as a table, not as prose about them.
   Logical properties throughout: he-IL is RTL, aoa_audio and
   not_your_sugar_daddy are en-US, so nothing here may hardcode a side. */
.ea-scorecard-counts { font-variant-numeric: tabular-nums; opacity: .75; }
.ea-scorecard-table { width: 100%; border-collapse: collapse; }
.ea-scorecard-table td { padding: var(--sp-2, 6px) var(--sp-3, 10px); }
.ea-axis-value { font-variant-numeric: tabular-nums; text-align: end; }
.ea-axis-rule  { opacity: .7; }
.ea-scorecard-table tr[data-ok="false"] .ea-axis-value { color: var(--danger, #c0392b); }
.ea-scorecard-table tr[data-ok="unavailable"] .ea-axis-value { opacity: .55; font-style: italic; }
.ea-finding { border-inline-start: 3px solid var(--warn, #e0a800); padding-inline-start: var(--sp-3, 10px); }
.ea-finding[data-severity="high"] { border-inline-start-color: var(--danger, #c0392b); }
.ea-finding-fix { font-weight: 600; }
.ea-scorecard-note { opacity: .7; font-size: .9em; }

/* Edit gate — the diff an operator approves. Distinct from the paid-run
   gate on purpose: this spends nothing and is recoverable, so it must not
   look like the one that starts a billable pipeline. */
.is-gate.is-edit .gate-diff {
  white-space: pre-wrap; overflow-x: auto; max-height: 20rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .85em; padding: var(--sp-2, 6px) var(--sp-3, 10px);
  border-radius: var(--r-sm, 6px);
}
.ea-btn--danger { background: var(--danger, #c0392b); color: #fff; }

/* Leads — ready-to-send queue (automatic lead generation, 2026-10-02) */
.lead-queue-card{border:1px solid var(--border);border-radius:10px;padding:12px 14px;margin-top:10px}
.lead-queue-head{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.lead-score{margin-inline-start:auto;font-weight:700;color:var(--accent)}
.lead-trial-badge{font-size:11px;padding:2px 8px;border-radius:999px;background:var(--surface-2);color:var(--text-3)}
.lead-reasons{margin:6px 0;padding-inline-start:18px;font-size:12px;color:var(--text-3)}
.lead-queue-opener{margin:6px 0 10px;line-height:1.6}
.lead-queue-actions{display:flex;gap:8px;flex-wrap:wrap}
.lead-queue-actions>*{min-height:44px;display:inline-flex;align-items:center}
.lead-queue-error{color:var(--danger, #c0392b);font-size:12px;margin:6px 0 0}

/* Sites gallery (renderSitesGallery in dashboard.js) — every active client's
   site, framed with the Site Builder's sandbox. Logical properties throughout:
   the dashboard is RTL. The stage size is computed in JS from the card width
   (--fw/--fh = the viewport the site renders at, --s = scale to fit), so a
   1280px desktop render shrinks to the card instead of scrolling it. */
.sites-hdr { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); }
.sites-hdr .sites-refresh { flex: none; margin-block-start: 4px; }
.sites-summary { font-variant-numeric: tabular-nums; }
.sites-grid {
  display: grid; gap: var(--sp-6);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 460px), 1fr));
  align-items: start;
}
.sites-card { min-width: 0; overflow: hidden; display: flex; flex-direction: column; }
.sites-card:hover { border-color: var(--border); box-shadow: var(--sh-xs); }
.sites-card-hd {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5);
  border-block-end: 1px solid var(--border);
}
.sites-card-who { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.sites-card-name {
  margin: 0; font-size: var(--fs-200); line-height: var(--lh-200);
  font-weight: var(--fw-bold); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sites-card-sub {
  font-size: var(--fs-100); line-height: var(--lh-100); color: var(--text-3);
  text-align: start; unicode-bidi: isolate;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sites-card-tools { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.sites-card-tools:empty { display: none; }

.sites-seg { display: inline-flex; padding: 3px; gap: 2px; border-radius: 10px; background: var(--surface-3); }
.sites-seg button {
  font: inherit; font-size: var(--fs-100); font-weight: var(--fw-medium);
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 30px; padding: 4px 12px; border: 0; border-radius: 8px;
  background: transparent; color: var(--text-2); cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
.sites-seg button:hover { color: var(--text); }
.sites-seg button.is-on {
  background: var(--surface); color: var(--accent); font-weight: var(--fw-bold);
  box-shadow: 0 1px 2px rgba(24,32,31,.1), 0 2px 6px rgba(24,32,31,.06);
}
.sites-seg button:focus-visible, .sites-open:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.sites-seg svg, .sites-open svg, .sites-refresh svg { flex: none; display: block; }
.sites-open {
  display: inline-flex; align-items: center; gap: 4px; min-height: 30px;
  font-size: var(--fs-100); font-weight: var(--fw-semi);
  color: var(--accent); text-decoration: none; border-radius: 6px;
}
.sites-open:hover { text-decoration: underline; text-underline-offset: 3px; }
/* The arrow points up-and-out in reading direction. */
[dir="rtl"] .sites-open svg { transform: scaleX(-1); }

.sites-card-body { display: flex; flex-direction: column; }
.sites-stage {
  position: relative; overflow: hidden;
  height: 320px;            /* replaced by _sitesFit() as soon as the card has a width */
  background: var(--surface-3);
}
.sites-stage-wait {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: var(--fs-100); color: var(--text-3);
}
.sites-stage.is-loaded .sites-stage-wait { visibility: hidden; }
.sites-frame {
  position: absolute; inset-block-start: var(--pad, 0px); left: 50%;
  width: var(--fw, 1280px); height: var(--fh, 800px);
  border: 0; display: block; background: transparent;
  transform: translateX(-50%) scale(var(--s, .3));
  transform-origin: 50% 0;
}
.sites-stage.is-loaded .sites-frame { background: #fff; }
.sites-stage[data-mode="mobile"] .sites-frame {
  border-radius: 28px;
  box-shadow: 0 0 0 1px var(--border-strong), 0 12px 32px -8px rgba(16, 24, 40, .28);
}
.sites-foot {
  margin: 0; padding: var(--sp-2) var(--sp-5);
  font-size: var(--fs-100); line-height: var(--lh-100); color: var(--text-3);
  border-block-start: 1px solid var(--border);
}
.sites-note { padding: var(--sp-8) var(--sp-5); text-align: center; font-size: var(--fs-100); color: var(--text-3); }

.sites-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-2); min-height: 220px; padding: var(--sp-8) var(--sp-6);
  text-align: center; color: var(--text-3);
}
.sites-empty svg { width: 28px; height: 28px; color: var(--text-3); margin-block-end: var(--sp-1); }
.sites-empty-title { margin: 0; font-size: var(--fs-200); font-weight: var(--fw-semi); color: var(--text-2); }
.sites-empty-sub { margin: 0; font-size: var(--fs-100); line-height: var(--lh-100); max-width: 34ch; }
.sites-empty-path {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--fs-100);
  color: var(--text-2); unicode-bidi: isolate; overflow-wrap: anywhere;
}
.sites-empty--error .sites-empty-title { color: var(--status-fail); }
.sites-empty--error .ea-btn { margin-block-start: var(--sp-2); }
.sites-empty--page { border: 1px dashed var(--border-strong); border-radius: var(--r-lg); }

@media (max-width: 760px) {
  .sites-grid { gap: var(--sp-4); }
  .sites-card-hd { padding: var(--sp-3) var(--sp-4); }
  .sites-card-tools { width: 100%; justify-content: space-between; }
}
@media (prefers-reduced-motion: reduce) { .sites-seg button { transition: none; } }
    /* ── Loading skeleton: a data tab while the client's portfolio loads ──── */
    .tab-loading-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(220px, 100%), 1fr));
      gap: 12px; padding: 16px 0; }
    .tab-loading-card { height: 96px; border-radius: 12px;
      background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface, #2c2c2e) 50%, var(--surface-2) 75%);
      background-size: 200% 100%; animation: ea-shimmer 1.4s infinite linear; }
    .tab-loading-card:nth-child(n+5) { height: 180px; }
    @media (prefers-reduced-motion: reduce) { .tab-loading-card { animation: none; } }

    /* ── Empty states: one stroke icon family (was emoji) ─────────────────── */
    .es-icon { display: inline-grid; place-items: center; width: 48px; height: 48px; border-radius: 50%;
      background: var(--surface-2); color: var(--text-3); border: 1px solid var(--border); }

    /* ── Media tab, section B: e-books ────────────────────────────────────── */
    .eb-sec { margin-top: 24px; }
    .eb-sec-hd { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 20px; }
    .eb-sec-letter { flex: none; display: grid; place-items: center; width: 32px; height: 32px; border-radius: 8px;
      background: var(--accent); color: var(--on-accent); font-weight: 800; font-size: 15px; }
    .eb-sec-title { margin: 0; font-size: 17px; font-weight: 800; color: var(--text); line-height: 1.3; }
    .eb-sec-sub { margin: 2px 0 0; font-size: 12.5px; color: var(--text-2); line-height: 1.5; }
    .eb-book { display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: 24px; align-items: center; }
    .eb-cover { display: block; width: 150px; aspect-ratio: 148 / 210; border-radius: 4px 10px 10px 4px; overflow: hidden;
      background: var(--surface-2); border: 1px solid var(--border);
      box-shadow: 0 1px 2px rgba(0,0,0,.08), 0 10px 24px -8px rgba(0,0,0,.28);
      transition: transform .2s ease, box-shadow .2s ease; }
    .eb-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
    .eb-cover:hover { transform: translateY(-2px); box-shadow: 0 2px 4px rgba(0,0,0,.08), 0 16px 32px -10px rgba(0,0,0,.34); }
    .eb-cover:focus-visible, .eb-thumb:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
    .eb-title { font-size: 20px; font-weight: 800; color: var(--text); line-height: 1.3; text-wrap: balance; }
    .eb-sub { font-size: 13px; color: var(--text-2); margin-top: 4px; line-height: 1.55; }
    .eb-facts { display: flex; gap: 22px; margin-top: 14px; }
    .eb-fact { display: flex; flex-direction: column; }
    .eb-fact b { font-size: 20px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; line-height: 1.1; }
    .eb-fact span { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }
    .eb-meta { font-size: 12px; color: var(--text-3); margin-top: 12px; }
    .eb-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }
    .eb-actions .ea-btn { min-height: 40px; display: inline-flex; align-items: center; text-decoration: none; }
    .eb-thumbs-label { margin-top: 24px; }
    .eb-thumbs { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr)); gap: 12px; }
    .eb-thumb { position: relative; display: block; border-radius: 10px; overflow: hidden; aspect-ratio: 3 / 2;
      background: var(--surface-2); border: 1px solid var(--border-2); text-decoration: none; }
    .eb-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .25s ease; }
    .eb-thumb:hover img { transform: scale(1.04); }
    .eb-thumb-cap { position: absolute; inset: auto 0 0 0; padding: 18px 8px 6px; display: flex; gap: 6px; align-items: baseline;
      background: linear-gradient(to top, rgba(0,0,0,.72), transparent); color: #fff; font-size: 11px; line-height: 1.3;
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .eb-thumb-cap b { font-weight: 800; font-variant-numeric: tabular-nums; }
    @media (max-width: 560px) {
      .eb-book { grid-template-columns: 1fr; justify-items: center; text-align: center; }
      .eb-facts, .eb-actions { justify-content: center; }
    }
    @media (prefers-reduced-motion: reduce) { .eb-cover, .eb-thumb img { transition: none; } .eb-cover:hover { transform: none; } }
    /* A tap leaves :hover applied on touch screens; the lift must not stick. */
    @media (hover:none) { .eb-cover:hover, .eb-thumb:hover img { transform: none; } }

/* Agency-scope roll-up shown on per-client tabs (renderPickClientPanel). */
.ag-pick{overflow-x:auto}
.ag-pick-table{width:100%;border-collapse:collapse;font-size:var(--fs-200);min-width:640px}
.ag-pick-table th{font-size:var(--fs-100);font-weight:var(--fw-semi);color:var(--text-3);text-align:start;padding:10px 14px;border-bottom:1px solid var(--border)}
.ag-pick-table td{padding:12px 14px;border-bottom:1px solid var(--border);vertical-align:middle}
.ag-pick-table tr:last-child td{border-bottom:0}
.ag-pick-table tbody tr:hover{background:var(--surface-2)}
.ag-pick-table .num{font-variant-numeric:tabular-nums;white-space:nowrap}
.ag-pick-sub{font-size:var(--fs-100);color:var(--text-3);margin-top:2px}

/* ── Agent faces (AGENT_PEOPLE / agentAvatarHtml in dashboard.js) ────────────
   One sprite of 24 headshots, 6 columns × 4 rows, 128px each, cropped from two
   generated contact sheets. Embedded as a data URI so it ships inside this
   file: the web root publishes only the manifest, and a new image would need
   its own manifest line and nginx location. --av-c / --av-r pick the tile. */
:root { --ea-agent-sprite: url("data:image/webp;base64,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"); }
.ea-av {
  --av: 28px;
  display: inline-block; flex: none; vertical-align: middle;
  inline-size: var(--av); block-size: var(--av); border-radius: 50%;
  background-color: var(--surface-2, #e6e2dc);
  background-image: var(--ea-agent-sprite);
  background-size: 600% 400%;
  background-position: calc(var(--av-c, 0) * 20%) calc(var(--av-r, 0) * 33.3333%);
  box-shadow: 0 0 0 1px var(--card-line, rgba(0,0,0,.08));
}
.ea-av--xs { --av: 20px; }
.ea-av--sm { --av: 28px; }
.ea-av--md { --av: 40px; }
.ea-av--lg { --av: 56px; }
.ea-av--none { background-image: none; }

/* flow cards: the agent replaces the step code */
.fc-agent { display: inline-flex; align-items: center; gap: 6px; min-inline-size: 0; }
.fc-agent__name { font-size: var(--fs-100); font-weight: 600; color: var(--text-2);
                  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.flow-card.is-running .ea-av { box-shadow: 0 0 0 2px var(--accent); }
.flow-card.is-fail .ea-av    { box-shadow: 0 0 0 2px var(--danger, #d64545); }

/* agents list: name over job */
.agent-who { display: flex; flex-direction: column; flex-shrink: 0; line-height: 1.2; min-inline-size: 0; }
.agent-who__name { font-size: 13px; font-weight: 600; color: var(--text); white-space: nowrap; }
.agent-who__job  { font-size: 11px; color: var(--text-3); white-space: nowrap; }
.dna-icon .ea-av, .dna-ref-chip .ea-av { box-shadow: none; }

/* ── Agency team — the whole roster on the overview (mountAgencyTeam) ───────
   Grouped by department, in the order the work flows. Logical properties
   only, so the strip mirrors under dir="rtl". */
.ea-team-strip { margin-block-start: 16px; }
.ea-team-title {
  margin: 0 0 10px; font-size: var(--fs-300); font-weight: var(--fw-bold, 700);
  color: var(--text);
}
.ea-team-group + .ea-team-group { margin-block-start: 14px; }
.ea-team-dept {
  margin: 0 0 8px; font-size: var(--fs-100); font-weight: 600;
  color: var(--text-3); letter-spacing: var(--tracking-caps, .04em);
}
.ea-team {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
/* Phone: each department is one swipeable row instead of a 24-card stack. */
@media (max-width: 640px) {
  .ea-team {
    grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 132px;
    gap: 8px; overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory; padding-block-end: 4px;
    scrollbar-width: none;
  }
  .ea-team::-webkit-scrollbar { display: none; }
  .ea-team > [role="listitem"] { scroll-snap-align: start; }
}
.ea-tm {
  all: unset; box-sizing: border-box; cursor: pointer;
  display: flex; align-items: center; gap: 12px;
  inline-size: 100%; min-block-size: 44px;
  padding: 10px 12px; text-align: start;
  background: var(--card); border: 1px solid var(--card-line); border-radius: var(--r-lg, 14px);
  box-shadow: var(--sh-xs, none);
  transition: border-color .18s var(--ease-out, ease), box-shadow .18s var(--ease-out, ease),
              transform .18s var(--ease-out, ease);
}
.ea-tm:focus-visible { outline: none; box-shadow: var(--sh-focus, 0 0 0 3px var(--accent)); }
.ea-tm-meta { display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; }
.ea-tm-name  { font-size: var(--fs-200); font-weight: var(--fw-bold, 700); color: var(--text);
               white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ea-tm-role  { font-size: var(--fs-100); color: var(--text-2); font-weight: 600; }
.ea-tm-blurb { font-size: var(--fs-100); color: var(--text-3); line-height: 1.35; }
@media (max-width: 640px) {
  .ea-tm { flex-direction: column; text-align: center; gap: 6px; padding: 12px 8px; block-size: 100%; }
  .ea-tm-name { white-space: normal; }
}
@media (hover: hover) {
  .ea-tm:hover { border-color: var(--border-strong, var(--card-line)); box-shadow: var(--sh-sm, none); transform: translateY(-1px); }
}
@media (prefers-reduced-motion: reduce) {
  .ea-tm, .ea-tm:hover { transition: none; transform: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PORTAL SHELL (2026-10-13) — the customer portal's layout, on the agency side.

   From 769px the sidebar is drawn as the portal's navy rail and the open
   group's tabs as a pill row under the header. The markup is unchanged
   (#sb-nav > .nav-group > .nav-group-label + .nav-group-items > .nav-item):
   this block only re-presents it, so keyboard order, tab reachability and the
   visibility preferences behave exactly as before. Below 769px #sidebar is
   hidden by the phone rules and #mobile-tabs navigates, untouched by this.

   --rail:1 on #sidebar is how dashboard.js knows the rail is on screen
   (_navRailMode) without copying this breakpoint.

   Values are the portal's own (customer_view.css): --portal-ink #0a2540,
   rail text #94a9bc, active = white on 10% white, radius 12, 90px wide.
   One deliberate difference: rail labels are 11px, not the portal's 10.5px —
   tests/test_dashboard_text_floor.py holds this file to an 11px floor.
   ═══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 769px) {
  :root {
    --sidebar-w: 90px;
    --header-h-base: 60px;
    --subnav-h: 50px;
    --content-max: 1240px;
    --rail-ink: #0a2540;
    --rail-fg: #94a9bc;
    --rail-fg-strong: #ffffff;
    --rail-hover: rgba(255, 255, 255, .06);
    --rail-active: rgba(255, 255, 255, .10);
  }
  :root[data-theme="dark"] { --rail-ink: #12142a; }

  #sidebar {
    --rail: 1;
    background: var(--rail-ink);
    border: 0;
    overflow: visible;           /* the pill row and the switcher are fixed children */
  }

  /* Mark only; the wordmark does not fit 90px and the header names the scope. */
  #sb-logo { padding: 18px 0 12px; border: 0; display: flex; justify-content: center; }
  #sb-logo > div > div { display: none; }

  /* ── Rail buttons: one per group ── */
  #sb-nav { padding: 4px 10px 8px; gap: 6px; overflow: visible; }
  #sb-nav .nav-group + .nav-group { margin-block-start: 0; }
  #sb-nav .nav-group-label {
    flex-direction: column; justify-content: center; gap: 5px;
    min-block-size: 60px; padding: 8px 2px;
    border-radius: 12px;
    color: var(--rail-fg);
    transition: background 120ms var(--ease-out), color 120ms var(--ease-out);
  }
  #sb-nav .nav-group-label::after,
  #sb-nav .nav-group-chev,
  #sb-nav .nav-group-text { display: none; }
  #sb-nav .nav-group-ico { display: flex; }
  #sb-nav .nav-group-ico svg { width: 20px; height: 20px; }
  #sb-nav .nav-group-short { font-size: 11px; font-weight: 700; line-height: 1.2; }
  #sb-nav .nav-group-label:focus-visible {
    outline: 2px solid var(--rail-fg-strong); outline-offset: -2px; border-radius: 12px;
  }
  #sb-nav .nav-group.is-active .nav-group-label {
    color: var(--rail-fg-strong); background: var(--rail-active);
  }

  /* ── Pill row: the open group's tabs, pinned under the header ── */
  #sb-nav .nav-group-items { display: none; }
  #sb-nav .nav-group.is-active .nav-group-items {
    display: flex; flex-direction: row; align-items: center; gap: 8px;
    position: fixed; z-index: 29;
    inset-block-start: var(--header-h);
    right: var(--sidebar-w); left: var(--wp-w, 0px);
    block-size: var(--subnav-h);
    padding: 0 24px;
    overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
    background: var(--bg);
    border-block-end: 1px solid var(--border);
  }
  #sb-nav .nav-group.is-active .nav-group-items::-webkit-scrollbar { display: none; }
  /* Collapsed still means hidden, even for the open group: the two rules
     above out-rank .nav-group.is-collapsed .nav-group-items on specificity. */
  #sb-nav .nav-group.is-collapsed .nav-group-items,
  #sb-nav .nav-group-items[hidden] { display: none; }
  #sb-nav .nav-item {
    flex: 0 0 auto; inline-size: auto; block-size: 34px; padding: 0 14px;
    border: 1px solid var(--border); border-radius: 999px;
    background: var(--surface); color: var(--text-2);
    font-size: 13px; font-weight: 600; white-space: nowrap;
    transition: background 120ms var(--ease-out), color 120ms var(--ease-out),
                border-color 120ms var(--ease-out), transform 120ms var(--ease-out);
  }
  #sb-nav .nav-item svg { display: none; }
  #sb-nav .nav-item.active {
    background: var(--accent-soft); border-color: transparent; color: var(--accent-hover);
  }

  /* ── Header: the client switcher moves in from the old sidebar ── */
  #sb-client-wrap {
    position: fixed; z-index: 31;
    inset-block-start: calc(var(--safe-top) + (var(--header-h-base) - 40px) / 2);
    right: calc(var(--sidebar-w) + 20px);
    inline-size: 224px; padding: 0;
  }
  #sb-client-wrap .client-btn { block-size: 40px; }
  #topbar { padding-inline-start: calc(20px + 224px + 14px); }
  /* The switcher already names the scope; the header keeps only what it adds. */
  #hdr-left > div > span:first-child { display: none; }

  #content-wrap {
    margin-top: calc(var(--header-h) + var(--subnav-h));
    min-height: calc(100vh - var(--header-h) - var(--subnav-h));
  }

  /* ── Rail foot: customise, new client, status, theme ── */
  #sidebar .tp-open {
    align-self: center; inline-size: 44px; block-size: 44px; margin: 0 0 6px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    border: 0; border-radius: 12px; background: transparent; color: var(--rail-fg);
    transition: background 120ms var(--ease-out), color 120ms var(--ease-out);
  }
  #sidebar .tp-open > span:not(.tp-open-ico),
  #sb-footer .sb-newclient > span:not([aria-hidden]) {
    position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap;      /* still read aloud */
  }
  #sb-footer {
    position: relative; border: 0; padding: 0 0 14px;
    display: flex; flex-direction: column; align-items: center; gap: 8px;
  }
  #sb-footer .sb-newclient {
    inline-size: 44px; block-size: 44px; margin: 0; border-radius: 12px;
    border-color: transparent; background: var(--rail-active); color: var(--rail-fg-strong);
    font-size: 20px; line-height: 1;
  }
  #sb-footer .sh-foot { margin: 0; }
  #sb-footer .theme-toggle {
    inline-size: 44px; block-size: 44px; border-radius: 50%;
    border-color: transparent; background: var(--rail-hover); color: var(--rail-fg);
  }
  /* System status: a dot on the rail, the full panel as a flyout beside it. */
  #sb-footer::before {
    content: ""; order: -1;
    inline-size: 10px; block-size: 10px; margin: 17px; border-radius: 50%;
    background: var(--status-done);
    box-shadow: 0 0 0 4px var(--rail-hover);
  }
  #sb-footer:has(.sh-row.is-idle)::before { background: var(--rail-fg); }
  #sb-footer:has(.sh-row.is-warn)::before { background: var(--status-warn); }
  #sb-footer:has(.sh-row.is-fail)::before { background: var(--status-fail); }
  #sb-footer .sys-health {
    position: absolute; z-index: 45;
    right: calc(100% + 10px); inset-block-end: 14px; inline-size: 232px;
    background: var(--surface); box-shadow: var(--sh-md);
    opacity: 0; pointer-events: none; transform: translateX(6px);
    transition: opacity 120ms var(--ease-out), transform 120ms var(--ease-out);
  }
  #sb-footer:hover .sys-health,
  #sb-footer:focus-within .sys-health { opacity: 1; pointer-events: auto; transform: none; }
}

/* Hover belongs to devices that have one (tests/test_hover_neutralised.py). */
@media (min-width: 769px) and (hover: hover) {
  #sb-nav .nav-group:not(.is-active) .nav-group-label:hover,
  #sidebar .tp-open:hover {
    background: var(--rail-hover); color: var(--rail-fg-strong);
  }
  #sb-nav .nav-group-label:hover .nav-group-text { color: inherit; }
  #sb-nav .nav-item:not(.active):hover {
    background: var(--surface); border-color: var(--accent); color: var(--text);
  }
  #sb-footer .sb-newclient:hover { background: var(--accent); color: var(--on-accent); }
  #sb-footer .theme-toggle:hover { background: var(--rail-active); color: var(--rail-fg-strong); }
}
@media (min-width: 769px) {
  #sb-nav .nav-item:active,
  #sb-nav .nav-group-label:active { transform: scale(.97); }
}
@media (min-width: 769px) and (prefers-reduced-motion: reduce) {
  #sb-nav .nav-group-label, #sb-nav .nav-item, #sidebar .tp-open,
  #sb-footer .sys-health { transition: none; }
  #sb-nav .nav-item:active, #sb-nav .nav-group-label:active { transform: none; }
  #sb-footer .sys-health { transform: none; }
}
/* Outside the rail the two rail-only spans do not exist visually. */
.nav-group-ico, .nav-group-short { display: none; }
@media (min-width: 769px) {
  #sb-nav .nav-group-short { display: block; }
}
/* A touch tablet (769–1024px, coarse pointer) hides #sidebar and navigates
   with #mobile-tabs, so the rail's header reservation must not apply there. */
@media (pointer:coarse) and (min-width:769px) and (max-width:1024px) {
  :root { --header-h-base: 56px; }
  #topbar { padding-inline-start: 24px; }
  #hdr-left > div > span:first-child { display: inline; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PORTAL SURFACES + MOTION (2026-10-13)

   One calm surface system, the customer portal's: a single accent, cards on
   --border hairlines with the 8px radius, and colour kept for things that
   mean something (status, a client's own brand stripe on its row).

   The KPI tiles used to carry a different top-border and icon colour per
   metric. Six colours for six numbers encoded nothing; the icon already says
   which metric it is. They share the accent now.

   Motion is transform/opacity only, 120ms, gated to devices that hover and
   switched off under prefers-reduced-motion. Compact, clickable cards lift;
   the large .ea-card containers do not — a whole panel rising under the
   cursor reads as the page moving.
   ═══════════════════════════════════════════════════════════════════════════ */
.agy-kpi-row .kpi:has([class*="kpi-ico--"]),
.ov-kpi-row .kpi:has([class*="kpi-ico--"]) {
  border-top: 1px solid var(--border);
}
.agy-kpi-row [class*="kpi-ico--"],
.ov-kpi-row [class*="kpi-ico--"] {
  background: var(--accent-soft);
  color: var(--accent);
}
.agy-row { border-radius: var(--r-lg); background: var(--surface); }

.kpi, .agy-row, .lib-card, .sites-card, .plan-card, .report-card,
.cl-card, .dna-card, .intake-card, .cs-tile, .flp-tile {
  transition: border-color 120ms var(--ease-out), box-shadow 120ms var(--ease-out),
              transform 120ms var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .kpi:not(.is-empty):hover,
  .agy-row:not(.is-unknown):hover,
  .lib-card:hover, .sites-card:hover, .plan-card:hover, .report-card:hover,
  .cl-card:hover, .dna-card:hover, .intake-card:hover, .cs-tile:hover, .flp-tile:hover {
    box-shadow: var(--sh-md);
    border-color: var(--border-strong);
  }
}
/* The lift is its own query: asking for reduced motion removes the movement
   and keeps the shadow, rather than relying on a later reset to out-rank
   :not(.is-unknown):hover — which it did not. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .kpi:not(.is-empty):hover,
  .agy-row:not(.is-unknown):hover,
  .lib-card:hover, .sites-card:hover, .plan-card:hover, .report-card:hover,
  .cl-card:hover, .dna-card:hover, .intake-card:hover, .cs-tile:hover, .flp-tile:hover {
    transform: translateY(-2px);
  }
}

/* An entrance animation with fill-mode `both` keeps its last keyframe
   (transform: translateY(0)) applied for good, and an animated value out-ranks
   any declaration — so the card could never lift afterwards. `backwards` holds
   the start state through the stagger delay and lets go once it has landed. */
.kpi, .agy-row, .lib-card, .sites-card, .plan-card, .report-card,
.cl-card, .dna-card, .intake-card, .cs-tile, .flp-tile { animation-fill-mode: backwards; }

/* Rows arrive after the tiles above them, one after another. */
.agy-rows > .agy-row { animation: ea-card-in var(--dur-slow) var(--ease-out) backwards; }
.agy-rows > .agy-row:nth-child(1) { animation-delay: 120ms; }
.agy-rows > .agy-row:nth-child(2) { animation-delay: 150ms; }
.agy-rows > .agy-row:nth-child(3) { animation-delay: 180ms; }
.agy-rows > .agy-row:nth-child(4) { animation-delay: 210ms; }
.agy-rows > .agy-row:nth-child(5) { animation-delay: 240ms; }
.agy-rows > .agy-row:nth-child(6) { animation-delay: 270ms; }
.agy-rows > .agy-row:nth-child(7) { animation-delay: 300ms; }
.agy-rows > .agy-row:nth-child(n+8) { animation-delay: 330ms; }

@media (prefers-reduced-motion: reduce) {
  .kpi, .agy-row, .lib-card, .sites-card, .plan-card, .report-card,
  .cl-card, .dna-card, .intake-card, .cs-tile, .flp-tile {
    transition: border-color 120ms var(--ease-out), box-shadow 120ms var(--ease-out);
  }
  .agy-rows > .agy-row { animation: none; }
}

/* Website Studio · hosting section inside the Sites tab (_studioHostingRender). */
.studio-hosting { padding: var(--sp-5); margin-block-end: var(--sp-6); }
.studio-h2 { font-size: var(--fs-lg, 18px); margin: 0 0 var(--sp-3); }
.studio-h { font-size: 14px; font-weight: 600; margin: var(--sp-5) 0 var(--sp-2); color: var(--text-2); }
.studio-note { font-size: 13px; color: var(--text-3); margin: 0 0 var(--sp-2); font-variant-numeric: tabular-nums; }
.studio-note--warn { color: var(--status-warn); }
.studio-vuln { color: var(--status-fail); font-weight: 600; }
.studio-alert {
  border: 1px solid var(--status-fail); background: var(--status-fail-bg); color: var(--text-1, inherit);
  border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4); margin-block-end: var(--sp-3); font-size: 14px;
}
.studio-alert strong { color: var(--status-fail); }
.studio-table-wrap { overflow-x: auto; max-width: 100%; }
.studio-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.studio-table th { text-align: start; font-weight: 600; color: var(--text-3); padding: 6px 8px; border-block-end: 1px solid var(--border); }
.studio-table td { padding: 8px; border-block-end: 1px solid var(--border); vertical-align: top; }
.studio-table td > span[dir=ltr] { overflow-wrap: anywhere; }
.studio-caps { margin-block-start: var(--sp-4); }
.studio-caps summary { cursor: pointer; font-size: 13px; color: var(--text-2); min-height: 44px; display: flex; align-items: center; }
@media (max-width: 640px) {
  .studio-hosting { padding: var(--sp-4); }
  .studio-table { font-size: 12px; }
  .studio-table th, .studio-table td { padding: 6px 4px; }
}

/* Design references card in the Site Builder (_refCard, Website Studio phase 3). */
.ref-form { display: flex; gap: var(--sp-2); margin-block-end: var(--sp-2); }
.ref-form input { flex: 1; min-width: 0; min-height: 44px; padding: 0 var(--sp-3); border: 1px solid var(--border-strong, var(--border));
  border-radius: var(--r-md); background: var(--surface); color: var(--text); font-size: 16px; }
.ref-form button { min-height: 44px; }
.ref-status { font-size: 12px; color: var(--text-3); min-height: 18px; margin-block-end: var(--sp-2); }
.ref-card { border: 1px solid var(--border); border-radius: var(--r-lg); padding: var(--sp-3) var(--sp-4); margin-block-start: var(--sp-3); }
.ref-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-3); margin-block-end: var(--sp-2); }
.ref-date { font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.ref-row { display: grid; grid-template-columns: 110px 1fr; gap: var(--sp-2); font-size: 12px; padding: 4px 0; border-block-start: 1px solid var(--border); }
.ref-k { color: var(--text-3); }
.ref-v { color: var(--text); overflow-wrap: anywhere; }
.ref-note { font-size: 12px; color: var(--text-3); margin: var(--sp-2) 0 0; }
/* Concept card (Site Builder) — reuses .ref-card / .ref-row. */
.concept-flag { font-size: 11px; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border); }
.concept-flag.is-ok { color: var(--status-done); }
.concept-flag.is-bad, .concept-font-meta.is-bad, .concept-msg.is-bad { color: var(--r); }
.concept-msg.is-warn { color: var(--status-warn); }
.concept-font { display: grid; gap: 2px; }
.concept-specimen { font-size: 22px; line-height: 1.25; color: var(--text); }
.concept-font-meta { font-size: 11px; color: var(--text-3); }
.concept-contrast { display: grid; gap: 4px; }
.concept-pair { display: flex; align-items: center; gap: 6px; font-size: 12px; flex-wrap: wrap; }
.concept-pair.is-bad { color: var(--r); }
.concept-pair.is-warn { color: var(--status-warn); }
.concept-chip { inline-size: 22px; block-size: 22px; border-radius: 6px; display: inline-grid; place-items: center; font-weight: 700; border: 1px solid var(--border); flex: none; }
.ref-swatches { display: flex; flex-wrap: wrap; gap: 6px 10px; }
.ref-color { display: inline-flex; align-items: center; gap: 4px; }
.ref-color code { font-size: 11px; color: var(--text-2); }
.ref-swatch { width: 14px; height: 14px; border-radius: 4px; border: 1px solid var(--border); display: inline-block; }
/* Design-system card (Site Builder): theme DESIGN.md + Israeli seed tiles, each tile in its own colours. */
.design-seeds { margin-block-start: var(--sp-3); }
.design-seeds > summary { cursor: pointer; font-size: 12px; font-weight: 600; color: var(--text); min-block-size: 44px; display: flex; align-items: center; }
.design-seed-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--sp-3); margin-block-start: var(--sp-3); }
.design-seed { display: grid; gap: 6px; padding: var(--sp-3); border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--surface); color: var(--text); }
.design-seed-name { font-size: 22px; line-height: 1.2; }
.design-seed-tag { font-size: 12px; line-height: 1.5; opacity: .85; }
.design-seed-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.design-seed-sw { display: flex; gap: 4px; }
.design-seed-btn { font-size: 12px; font-weight: 700; padding: 6px 14px; border: 1px solid rgba(0, 0, 0, .12); }
.design-seed-warn { font-size: 11px; opacity: .8; }
.design-seed-warn.is-warn { font-weight: 600; }
@media (max-width: 480px) { .ref-row { grid-template-columns: 1fr; gap: 2px; } }

/* Promotion preflight inside the staging card (_stgPromotion, Website Studio 2d). */
.promo { border-block-start: 1px solid var(--border); margin-block-start: var(--sp-3); padding-block-start: var(--sp-3); }
.promo-title { font-size: 12px; font-weight: 600; color: var(--text-2); margin: var(--sp-2) 0; }
.promo-verify { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-2); min-height: 44px; }
.promo-mark { display: inline-block; width: 1.2em; text-align: center; font-weight: 700; }
.promo-mark.is-ok { color: var(--status-done); }
.promo-mark.is-block { color: var(--status-fail); }
.promo-mark.is-warn { color: var(--status-warn); }
    /* Client messages tab (2026-10-19): list + thread, RTL, phone stacks. */
    .msg-layout { display: grid; grid-template-columns: minmax(240px, 340px) 1fr; gap: var(--sp-4); align-items: start; }
    .msg-list { display: flex; flex-direction: column; max-height: 72vh; overflow-y: auto; padding: var(--sp-2); }
    .msg-row { display: block; width: 100%; text-align: start; background: none; border: 0; border-bottom: 1px solid var(--border); padding: var(--sp-3); cursor: pointer; color: var(--text); font: inherit; }
    .msg-row:hover, .msg-row.is-open { background: var(--surface-1, rgba(0,0,0,.03)); }
    .msg-row.is-unread strong { font-weight: 700; }
    .msg-row-top { display: flex; justify-content: space-between; gap: var(--sp-2); align-items: center; font-size: 13px; }
    .msg-row-snippet { font-size: 12px; color: var(--text-2); margin-top: 4px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .msg-row-meta { font-size: 11px; color: var(--text-3); margin-top: 4px; }
    .msg-badge { min-width: 20px; padding: 1px 7px; border-radius: 10px; background: var(--status-fail); color: #fff; font-size: 11px; font-weight: 700; text-align: center; }
    .msg-empty { padding: var(--sp-5); text-align: center; color: var(--text-3); font-size: 13px; }
    .msg-thread-head { display: flex; justify-content: space-between; gap: var(--sp-2); flex-wrap: wrap; padding-bottom: var(--sp-3); border-bottom: 1px solid var(--border); font-size: 13px; color: var(--text-3); }
    .msg-thread-head strong { color: var(--text); font-size: 15px; }
    .msg-thread { display: flex; flex-direction: column; gap: var(--sp-3); max-height: 48vh; overflow-y: auto; padding: var(--sp-3) 0; }
    .msg-bubble { max-width: 78%; padding: var(--sp-3); border-radius: 12px; font-size: 13px; line-height: 1.55; }
    .msg-bubble.is-agency { align-self: flex-start; background: var(--accent-soft, rgba(70,120,90,.12)); }
    .msg-bubble.is-client { align-self: flex-end; background: var(--surface-1, rgba(0,0,0,.05)); }
    .msg-bubble-who { font-size: 11px; color: var(--text-3); margin-bottom: 4px; }
    .msg-bubble-body { white-space: pre-wrap; word-break: break-word; }
    .msg-reply { display: flex; flex-direction: column; gap: var(--sp-2); padding-top: var(--sp-3); border-top: 1px solid var(--border); }
    .msg-reply textarea, .msg-reply input[type=text], .msg-reply select { width: 100%; font: inherit; font-size: 16px; padding: var(--sp-2); border: 1px solid var(--border); border-radius: 8px; background: var(--surface-2); color: var(--text); box-sizing: border-box; }
    .msg-reply-row { display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap; }
    .msg-reply-row select { width: auto; }
    .msg-notify { font-size: 12px; color: var(--text-2); display: flex; align-items: center; gap: 4px; }
    .msg-out, .msg-hint { font-size: 12px; color: var(--text-3); }
    .msg-wa { display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap; }
    .msg-wa input[type=tel] { width: 150px; max-width: 100%; }
    @media (max-width: 768px) { .msg-layout { grid-template-columns: 1fr; } .msg-bubble { max-width: 92%; } }
    /* Monthly client report draft (Reports tab, 2026-10-19). */
    .rep-monthly { margin-bottom: var(--sp-4); }
    .rep-monthly-head { display: flex; gap: var(--sp-3); align-items: center; flex-wrap: wrap; margin-bottom: var(--sp-3); }
    .rep-monthly-head h3 { margin: 0; flex: 1; }
    .rep-monthly-note, .rep-monthly-src { font-size: 11px; color: var(--text-3); }
    .rep-monthly-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--sp-3); margin: var(--sp-3) 0; }
    .rep-monthly-tile { border: 1px solid var(--border); border-radius: 10px; padding: var(--sp-3); }
    .rep-monthly-tile.is-lead { border-color: var(--accent, var(--border)); }
    .rep-monthly-tile.is-missing .rep-monthly-value { color: var(--text-3); }
    .rep-monthly-label { font-size: 12px; color: var(--text-3); }
    .rep-monthly-value { font-size: 20px; font-weight: 700; margin: 4px 0; }
    .rep-monthly-sub { font-size: 12px; color: var(--text-2); }
    .rep-monthly-section h4 { font-size: 13px; margin: var(--sp-4) 0 var(--sp-2); }
    .rep-monthly-section ul { margin: 0; padding-inline-start: 18px; font-size: 13px; }
    .rep-monthly-section textarea { width: 100%; font: inherit; font-size: 16px; padding: var(--sp-2); border: 1px solid var(--border); border-radius: 8px; box-sizing: border-box; background: var(--surface-2); color: var(--text); margin-bottom: var(--sp-2); }
