/* ═══════════════════════════════════════════════════════════════════════
   CENTRALOOM STYLESHEET — extracted from index.html (Pass 2 redesign)
   Order: fonts → tokens/themes → base → layout shell → shared components →
   view-specific. Visual law: design/centraloom-design-system.md
   ═══════════════════════════════════════════════════════════════════════ */

    /* ── FONTS — bundled locally (Electron must render offline; no runtime CDN) ── */
    /* ══ REBRAND R1: INTER, SELF-HOSTED, THREE WEIGHTS ═══════════════════════════════════════
       400, 500 and 800, which is what the brand allows. The files are served from our own
       origin, so the strict content-security policy holds and nothing loads from Google Fonts.

       ⚠ THESE FACES WERE ALREADY DECLARED AND NOTHING USED THEM. The woff2 files have been in
       `public/assets/fonts/` since July and `--font-ui` was the system stack, so six fonts were
       served to nobody. R1 adds the 800 the brand needs and drops the 600 it does not.

       ⚠ R3 TOOK INTER BACK OUT OF THE UI. R1 pointed `--font-ui` at Inter; Lucas reviewed it at
       2000 px and rejected it, so the UI is the system stack again and Inter is the WORDMARK
       FONT only, through `--font-wordmark`. The 400 and 500 faces are left declared because they
       are the brand's package and the brand kit specifies all three: an @font-face nothing
       matches is never fetched, so declaring them costs a reader nothing. Verified in the live
       check, where only inter-latin-800-normal.woff2 is requested. */
    @font-face { font-family: 'Inter'; font-weight: 400; font-style: normal; font-display: swap; src: url('/assets/fonts/inter-latin-400-normal.woff2') format('woff2'); }
    @font-face { font-family: 'Inter'; font-weight: 500; font-style: normal; font-display: swap; src: url('/assets/fonts/inter-latin-500-normal.woff2') format('woff2'); }
    @font-face { font-family: 'Inter'; font-weight: 800; font-style: normal; font-display: swap; src: url('/assets/fonts/inter-latin-800-normal.woff2') format('woff2'); }
    /* ══ R6: IBM PLEX MONO IS THE APPLICATION'S FONT ═════════════════════════════════════════
       Three faces, each declared at the weight it actually is.

       ⚠ THE THIRD ONE CLAIMED TO BE 500 AND IS THE 600 FILE. Two faces of one family declared
       at the same weight is not a choice between them: the later wins, so every 500 in the
       application was rendering the 600 file and the real 500 was served to nobody.

       The brand's display weight is 800 and Plex Mono has no 800. With the three faces declared
       honestly the browser picks the nearest heavier one, so 800 renders the 600 face: a real
       face rather than a synthesised smear, which is what a wrong declaration would have given. */
    @font-face { font-family: 'IBM Plex Mono'; font-weight: 400; font-style: normal; font-display: swap; src: url('/assets/fonts/ibm-plex-mono-latin-400-normal.woff2') format('woff2'); }
    @font-face { font-family: 'IBM Plex Mono'; font-weight: 500; font-style: normal; font-display: swap; src: url('/assets/fonts/ibm-plex-mono-latin-500-normal.woff2') format('woff2'); }
    @font-face { font-family: 'IBM Plex Mono'; font-weight: 600; font-style: normal; font-display: swap; src: url('/assets/fonts/ibm-plex-mono-latin-600-normal.woff2') format('woff2'); }

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

    :root {
      /* ══ REBRAND R1: THE BRAND PALETTE ═══════════════════════════════════════════════════
         `docs/brand/README.md` is the source. These are the only raw brand colours in the app:
         everything else reaches them through the theme tokens below, so a future palette change
         is this block and not a search for hex.

         ONE ACCENT. Orange owns active and focus states, primary actions, progress and
         selection, and nothing else. It is never decoration and never body text. Green, red and
         amber are untouched and stay reserved for data meaning: pass, fail, warning. */
      --brand-carbon:   #0B0D0E;   /* primary dark surface, and text on light */
      --brand-black:    #000000;   /* the sidebar and the collapsed rail */
      --brand-white:    #FFFFFF;   /* text on dark, light surfaces */
      --brand-orange:   #F2801F;   /* the only accent */
      --brand-grey-600: #5A5E63;   /* secondary text on light */
      --brand-grey-550: #5F6068;   /* icon strokes on dark */
      --brand-grey-500: #8A8A92;   /* muted text on dark, inactive nav */
      --brand-grey-300: #DADCDF;   /* weave and hairlines on light */
      --brand-grey-200: #E3E5E8;   /* borders on light */
      --brand-grey-100: #F2F2F4;   /* quiet fills on light */

      /* ── Terminal design system: typography (spec §2) ── */
      /* ══ R6b: THE MONOSPACE IS SETTINGS ONLY ═════════════════════════════════════════════
         R1 made the interface Inter, R3 put it back to the system stack, R6 made the whole app
         IBM Plex Mono, and R6b corrects that: Lucas asked for the coding font in SETTINGS, and
         the whole application was a misread of the brief rather than the thing he asked for.

         So there are two UI fonts now, and which one you get depends on where you are:

           --font-ui        the system stack, everywhere. Exactly the stack R5 shipped at
                            bcb3fda, so every screen outside Settings renders as it did there.
           --font-settings  IBM Plex Mono, applied to #panel-settings and nothing else.

         ⚠ THE ROOT IS 16px AGAIN, AND THAT MATTERS MORE THAN IT LOOKS. R6 lowered it to 15px
         because the mono face runs about a tenth wider and the shell was crowding; with mono
         confined to one panel that reason is gone, and leaving the root at 15 would have
         shrunk every screen the brief says must be unchanged. Settings scales ITSELF instead,
         with the five steps redefined on the panel, which is the only place the mono width is
         being paid for.

         The wordmark stays Inter 800 and the editor's white page area keeps its own fonts, in
         both regimes: one is the mark rather than the interface, the other previews the
         client's published page. */
      --font-ui: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
      --font-settings: 'IBM Plex Mono', ui-monospace, SFMono-Regular, 'Cascadia Mono', Menlo, Consolas, monospace;
      --font-wordmark: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
      --font-mono: var(--font-ui);  /* stat numbers, IDs, costs, code */
      /* Legacy aliases — the whole app references --sans/--mono */
      --mono: var(--font-mono);
      --sans: var(--font-ui);

      /* ══ R2: THE TYPE SCALE. FIVE SIZES, AND THESE ARE ALL OF THEM ═══════════════════════
         The brand's rule is that hierarchy comes from WEIGHT AND LEVEL, not from more sizes, so
         a sixth size is the thing to resist rather than the thing to add. Weights are 400, 500
         and 800 only, which is what is self-hosted.

         The old scale had six names and the file had 27 distinct sizes in practice, most of them
         written inline and most used once. These five are what the shell and Produce use, and
         the smoke holds them to it. */
      /* ══ R4: THE SCALE GROWS A LITTLE ON A BIG SCREEN ═══════════════════════════════════
         The five steps are in rem now, against a root that is 16px up to 1600px wide and grows
         from there to 17.5px at 2000px. Below 1600 every size is the px it always was, to the
         pixel, so 1280 and 1440 render exactly as they did: 20, 16, 14, 12, 11.

         ⚠ THE RATIOS ARE THE POINT. Scaling the ROOT rather than each size means all five move
         together and the steps keep their proportions; bumping 11px to 12px by hand on a wide
         screen would have collapsed the gap between small and label and left the scale with
         four steps at the width it matters most. At 1920 the five are 21.5, 17.2, 15.1, 12.9
         and 11.8, which is a tenth larger and reads as the same screen.

         `html` carries the clamp. body keeps its own font-size, so nothing below 1600 shifts. */
      /* ⚠ R6b PUT THE ROOT BACK TO 16px, WHICH IS WHAT R5 SHIPPED.
         R6 lowered it to 15 because IBM Plex Mono sets every character on the same advance and
         so runs about a tenth wider, and at a 16px root the shell crowded: the top bar's
         subtitle wrapped at 1280 where it had been one line. That reason belonged to a mono
         application. With the mono confined to Settings, leaving the root at 15 would have
         shrunk every other screen for a cost only one panel pays.

         Settings carries the cost itself, further down: the five steps are redefined on
         #panel-settings against a local factor, which lands them on exactly the sizes R6
         measured as right for mono without touching anything outside that panel. */
      --fs-root: clamp(16px, calc(16px + (100vw - 1600px) * 0.00375), 17.5px);
      --fs-title: 1.25rem;      /* 20px at 1600 and below. The page title, weight 800 */
      --fs-heading: 1rem;       /* 16px. A section or card heading, weight 500 */
      --fs-body: 0.875rem;      /* 14px. Body text, buttons, nav, table cells */
      --fs-label: 0.75rem;      /* 12px. Field labels, column headers, chips */
      --fs-small: 0.6875rem;    /* 11px. Timestamps, hints, the quietest metadata */
      /* A figure is not a sixth size: it is the title size at weight 800. */
      --fs-stat: var(--fs-title);
      /* ⚠ R5: GLYPH SIZES, WHICH ARE NOT TYPE SIZES.
         An element whose whole content is a decorative symbol (an empty-state mark, a large
         status icon, a close cross) is a graphic. Flattening a 32px mark to the title size makes
         it a typo rather than an illustration, so two named sizes carry them. They are rem like
         the steps, so they grow with everything else above 1600px, and there are two of them on
         purpose: a third would be the start of a second scale. */
      --glyph-md: 1.25rem;      /* 20px. Close crosses, card icons */
      --glyph-lg: 2rem;         /* 32px. Empty-state and status marks */

      /* The old names, kept so the rest of the app keeps rendering, each pointed at the nearest
         step of the new scale. They are not for new code. */
      --text-xs: var(--fs-small);
      --text-sm: var(--fs-label);
      --text-base: var(--fs-body);
      --text-lg: var(--fs-heading);
      --text-xl: var(--fs-title);
      --text-stat: var(--fs-title);

      /* ══ R2: SPACING, ON A 4 PX BASE ════════════════════════════════════════════════════ */
      --space-1: 4px;
      --space-2: 8px;
      --space-3: 12px;
      --space-4: 16px;
      --space-5: 20px;
      --space-6: 24px;
      --space-8: 32px;
      --space-10: 40px;
      --space-12: 48px;
      --space-16: 64px;

      /* ══ R2: ONE CARD ═══════════════════════════════════════════════════════════════════
         Surface, a 1 px hairline, a 16 px radius, and NOTHING ELSE. No inset highlight, no
         gradient edge, no glow. Every panel, stat card and section on Produce is this. */
      --card-radius: 16px;
      --card-border: 1px solid rgba(255,255,255,0.08);
      --card-pad: var(--space-5);

      /* ══ R2, CORRECTED BY R3: PAGE LAYOUT ═══════════════════════════════════════════════
         A fixed gutter on each side of a CENTRED column, capped so the measure stays readable.

         R2 read the original defect backwards. The old arrangement was `margin: 0 auto` on a
         1600px column, and the complaint was the gap between the sidebar and the first card, so
         R2 pinned the column hard left. That fixes 1600px and breaks everything wider: at 2000px
         a 1440px column left 360px of nothing down the right. The gap was never caused by
         centring, it was caused by a cap too low for the screen. So: centred, and the cap raised
         to 1680, which fills 1920 to 2000 with a margin rather than a void and still leaves a
         readable measure at 1280, where the column is the available width anyway. */
      --page-gutter: var(--space-8);
      --page-max: 1680px;

      /* ── Terminal design system: spatial (spec §3) ── */
      --radius-panel: 12px;
      --radius-control: 8px;   /* buttons, inputs, selects */
      --radius-pill: 999px;    /* status badges */
      --pad-panel: 20px;
      --gap-grid: 16px;        /* between panels, across a row */
      /* R3: MORE AIR BETWEEN CARDS, DOWN THE PAGE ONLY. Widening --gap-grid would narrow every
         card in a multi-column row, which is a layout change on every screen; the complaint was
         vertical, so only the row gap moves. */
      --gap-grid-row: var(--space-6);
      --row-h: 40px;           /* table rows */
      --nav-w: 240px;
    }

    /* ── THEMES ── */
    /* Dark (default) */
    /* ── DARK (default) ── */
    body {
      --bg:#0d0d0d; --surface:#161616; --surface2:#1e1e1e;
      --border:#2a2a2a; --border-heavy:#383838;
      --text:#ffffff; --text-sub:#a0a0a0; --text-dim:#505050;
      --green:#4ade80; --red:#f87171; --amber:#fbbf24; --blue:var(--accent);
      --nav-bg:#111111; --nav-text:#e0e0e0; --nav-sub:#606060;
      --nav-active:#252525; --nav-accent:#ffffff; --nav-border:#000000;
      /* CONTRAST FIX: --card was never defined in ANY theme, so every component
         styled background:var(--card,#161616) rendered a DARK box in light themes
         too — dark text on a dark box (invisible URL preview, calendar chips,
         idea cards). Resolve it to the theme's own --surface2: this one line is
         inherited by every theme class below (each re-declares --surface2, and
         var() resolves at use time). --accent likewise never existed in CSS —
         links fell back to light blue on every theme; give it the per-theme blue. */
      --card: var(--surface2);
      /* R1: the accent was #FFFFFF, so "accent" and "text" were the same colour and nothing on
         screen could point at itself. It is the brand orange now, and every one of its use sites
         is already an accent use: the nav active state, the primary button, progress fill, table
         links, the active option border and the drop target. Routed through the token rather
         than edited at those sites, which is why this is one line and not thirty. */
      --accent: var(--brand-orange);
      --accent-ink: var(--brand-carbon);   /* text ON the accent */
      --aura: var(--brand-orange);
      --aura-warm: var(--brand-orange);
      /* ── TERMINAL-SPEC TOKEN BRIDGE (legacy → spec names) ──
         Components restyled to the Terminal spec use the spec token names.
         This bridge maps them onto each theme's own palette, so the six legacy
         themes keep working; body.theme-terminal below overrides with the
         spec's exact values. Muted tints are fixed rgba (subtle, theme-safe). */
      --bg-app: var(--bg);
      --bg-panel: var(--surface);
      --bg-panel-raised: var(--surface2);
      --bg-nav: var(--nav-bg);
      --border-subtle: var(--border);
      --border-strong: var(--border-heavy);
      --text-primary: var(--text);
      --text-secondary: var(--text-sub);
      --text-tertiary: var(--text-dim);
      --accent-hover: #F59236;                  /* the accent, one step lighter */
      /* R1: FOUR ALPHAS, NOT TEN. The old light-blue glow was written as a raw
         light-blue rgba at about twenty sites with ten different alphas, all bypassing the
         token layer, so flipping the accent would have left every one of them blue. They land on
         these four bands instead, which is most of this unit's palette shrink. */
      --accent-wash: rgba(242,128,31,0.07);         /* a fill you can barely see: drop targets */
      --accent-muted: rgba(242,128,31,0.14);        /* the accent as a quiet fill */
      --accent-glow: rgba(242,128,31,0.32);         /* focus rings and soft halos */
      --accent-glow-strong: rgba(242,128,31,0.60);  /* the live dot, the active marker */
      --positive: var(--green);
      --positive-muted: rgba(34, 197, 94, 0.12);
      --negative: var(--red);
      --negative-muted: rgba(239, 68, 68, 0.12);
      --warning: var(--amber);
      --warning-muted: rgba(245, 158, 11, 0.12);
      --safe-mode: var(--positive);
      --live-mode: var(--negative);
      --status-positive: var(--text);
      --status-negative: var(--text);
      --status-warning: var(--text-secondary);
      --status-positive-muted: rgba(255,255,255,0.10);
      --status-negative-muted: rgba(255,255,255,0.10);
      --status-warning-muted: rgba(255,255,255,0.10);
    }

    /* ── TERMINAL (spec §1) — the default theme ── */
    body.theme-terminal {
      /* Spec tokens — exact values */
      --bg-app: #0A0A0C;           /* app background, near-black */
      --bg-panel: #101114;         /* card/panel surface */
      --bg-panel-raised: #16181D;  /* hover rows, nested elements, inputs */
      --bg-nav: #060608;           /* left rail, darker than app bg */
      --border-subtle: #1E2026;    /* 1px card borders, table row dividers */
      --border-strong: #2A2D35;    /* input borders, active states */
      /* ══ R2: THREE TEXT LEVELS ON DARK, AND THE MUTED ONE IS READABLE ═══════════════════
         primary   #FFFFFF    what the screen is about
         secondary #9BA1AB    labels, table headers, metadata        about 7.0 to 1 on a card
         muted     #8A8A92    timestamps, hints                      about 5.4 to 1 on a card

         ⚠ MUTED WAS #5C6270 AND FAILED. On the card surface #101114 that is about 2.6 to 1,
         which is below the 4.5 to 1 floor, and the app leans on it heavily: the screenshot that
         prompted this unit is mostly 11 px text in that colour. It is the brand's grey-500 now,
         which the brand already names as "muted text on dark" and which passes on both the card
         and the app background. The smoke recomputes the ratio rather than trusting this note. */
      --text-primary: #FFFFFF;     /* headings, figures, the active nav item */
      --text-secondary: #9BA1AB;   /* labels, table headers, metadata */
      --text-tertiary: var(--brand-grey-500);  /* timestamps, hints, disabled */
      --positive: #22C55E;
      --positive-muted: rgba(34, 197, 94, 0.12);
      --negative: #EF4444;
      --negative-muted: rgba(239, 68, 68, 0.12);
      --warning: #F59E0B;
      --warning-muted: rgba(245, 158, 11, 0.12);
      --safe-mode: var(--positive);
      --live-mode: var(--negative);
      /* Reverse aliases (spec → legacy names) so every existing rule and the
         ~1,200 inline styles pick the terminal palette up wholesale. */
      --bg: var(--bg-app); --surface: var(--bg-panel); --surface2: var(--bg-panel-raised);
      --border: var(--border-subtle); --border-heavy: var(--border-strong);
      --text: var(--text-primary); --text-sub: var(--text-secondary); --text-dim: var(--text-tertiary);
      --green: var(--positive); --red: var(--negative); --amber: var(--warning); --blue: var(--accent);
      --card: var(--bg-panel-raised);
      /* ══ R1: THE SIDEBAR, FROM THE BRAND KIT'S "INSIDE THE APP" BOARD ════════════════════
         Black, not the old #060608. Inactive nav is the brand's grey-500; the active item is
         WHITE text on a white wash rather than orange text, which is what the kit shows: orange
         is the accent everywhere else, and a nav list where the current item is the only orange
         thing on a black panel reads as an alert rather than as a position. */
      --nav-bg: var(--brand-black); --nav-text: var(--brand-white); --nav-sub: var(--brand-grey-500);
      --nav-active: rgba(255,255,255,.08); --nav-accent: var(--brand-white); --nav-border: var(--brand-black);
    }




    html, body {
      height: 100%;
      overflow: hidden;
      overflow-x: hidden;
      background: var(--bg);
      color: var(--text);
      font-family: var(--sans);
      -webkit-font-smoothing: antialiased;
    }
    /* ⚠ R4: THE ROOT IS WHAT THE SCALE IS MEASURED IN, AND IT IS NOT THE BODY'S SIZE.
       Both used to be 14px in one rule. The rem steps above are sized against 16px, so html
       takes the clamp and body keeps the body size, written as the token rather than the 14px
       literal it was. Everything in the app inherits from body, not from html, so below 1600
       nothing moves at all. */
    html { font-size: var(--fs-root); }
    body { font-size: var(--fs-body); }

    /* ── STAGING BAR (unit 121) ──
       A thin band across the top, shown only when APP_ENV is staging. Amber and plain words
       rather than a colour alone: the one thing it has to do is stop somebody believing they are
       looking at the live site. [hidden] wins over the display here because an attribute selector
       outranks a class, so it works whatever order these rules end up in. */
    .staging-bar {
      position: fixed; top: 0; left: 0; right: 0; height: 22px; z-index: 99998;
      display: flex; align-items: center; justify-content: center; gap: 8px;
      font-family: var(--mono, monospace); font-size: var(--fs-small); letter-spacing: 0.04em;
      /* Theme tokens, never a literal: scripts/color-tokens-smoke.js refuses a status colour
         written out anywhere but the theme blocks. The hex is deliberately not repeated in this
         comment either, because that check reads continuation lines and would find it here, which
         is the failure scripts/lib/pins.js was written about. */
      background: var(--warning); color: var(--bg); border-bottom: 1px solid var(--border-heavy);
      user-select: none;
    }
    .staging-bar[hidden] { display: none; }

    /* ── APP SHELL ── */
    .app {
      display: grid;
      grid-template-columns: 200px 1fr;
      height: 100vh;
      overflow: hidden;
      overflow-x: hidden;
    }
    /* The shell is height-locked to the viewport, so the bar has to take its 22px FROM it rather
       than sit on top of the header or push the bottom off screen. */
    body.staging-env .app { height: calc(100vh - 22px); margin-top: 22px; }

    /* ══════════════════════════════════════
       SIDEBAR
    ══════════════════════════════════════ */
    .sidebar {
      border-right: 1px solid var(--nav-border, var(--border));
      display: flex;
      flex-direction: column;
      height: 100vh;
      overflow: hidden;
      background: var(--nav-bg, var(--bg));
    }

    /* R3: THE LOCKUP GETS ROOM. It had 20px above and 16px below, with the org switcher packed
       straight underneath, so the mark sat in a corner rather than at the top of a sidebar. The
       space above and below is doubled, and the rule below separates it from the org switcher.
       The hairline stays: it is what tells the lockup from the navigation. */
    .sidebar-logo {
      padding: var(--space-8) var(--space-5) var(--space-6);
      border-bottom: 1px solid var(--nav-border, var(--border));
      flex-shrink: 0;
    }

    .sidebar-meta {
      display: flex;
      align-items: center;
      justify-content: space-between;
    }

    .logo-tag {
      font-family: var(--font-ui);
      font-size: var(--fs-small);
      color: var(--nav-sub, var(--text-dim));
    }

    .sidebar-status {
      display: flex;
      align-items: center;
      gap: var(--space-1);
      font-family: var(--font-ui);
      font-size: var(--fs-small);
      color: var(--green);
    }

    .status-dot {
      width: 5px; height: 5px;
      border-radius: 50%;
      background: var(--green);
      flex-shrink: 0;
    }

    .sidebar-nav {
      flex: 1;
      /* min-height:0 lets this flex child actually shrink and scroll; without
         it, tall nav content pushes the bottom user block out of the viewport
         (the "ADMIN · NO AUTH" clipping). */
      min-height: 0;
      padding: 12px 14px 24px;
      overflow-y: auto;
    }

    .sidebar-nav::-webkit-scrollbar { width: 0; }

    .nav-group { margin-bottom: 2px; }

    .nav-group-label {
      font-family: var(--font-ui);
      font-size: var(--fs-small);
      font-weight: 500;
      color: var(--nav-sub, var(--text-dim));
      padding: 14px 20px 5px;
    }

    .nav-item {
      display: flex;
      align-items: center;
      gap: 9px;
      width: 100%;
      /* R1: 14px / 500 with an 8px radius, from the brand kit's sidebar board. It was
         13.5px / 400, which is the one size in the file nothing else used. */
      padding: 7px 10px;
      font-family: var(--font-ui);
      font-size: var(--fs-body);
      font-weight: 500;
      color: var(--nav-sub, var(--text-dim));
      border-radius: 8px;
      background: none;
      border: none;
      cursor: pointer;
      text-align: left;
      transition: all 0.12s;
      position: relative;
    }

    .nav-item:hover { color: var(--nav-accent, var(--text)); opacity:1; background: var(--nav-active, var(--surface)); }

    .nav-item.active {
      color: var(--nav-accent, var(--text));
      opacity: 1;
      background: var(--nav-active, var(--surface));
    }

    /* Nav icons, on parents only: one SVG sprite (/assets/icons/nav.svg, Tabler outlines). The stroke
       inherits the item's color: text-sub at rest, text on hover and active. 18px. Children are
       label-only when expanded. */
    .nav-icon { width: 18px; height: 18px; flex-shrink: 0; color: var(--text-sub); transition: color 0.12s; }
    .nav-item:hover .nav-icon, .nav-item.active .nav-icon, .nav-parent-wrap.parent-has-active > .nav-parent-row > .nav-parent-btn .nav-icon { color: var(--text); }
    .nav-chevron-btn { opacity: 0.18; }
    .nav-chevron-btn:hover { opacity: 0.7; }

    .nav-badge { margin-left: auto; font-family: var(--font-ui); font-size: var(--fs-small); font-weight: 500; letter-spacing: 0.02em; padding: 0 6px; border: none; background: var(--accent-muted); color: var(--accent); border-radius: var(--radius-pill); flex-shrink: 0; }

    .nav-badge.new    { color: var(--blue);  border-color: var(--blue); }

    /* Sub-nav */
    .nav-sub {
      display: none;
      background: var(--surface);
      border-top: 1px solid var(--border);
      border-bottom: 1px solid var(--border);
    }

    .nav-sub.open { display: block; }

    .nav-sub-item {
      display: flex;
      align-items: center;
      gap: 8px;
      width: 100%;
      padding: 7px 20px 7px 36px;
      font-family: var(--font-ui);
      font-size: var(--fs-body);
      color: var(--text-dim);
      background: none;
      border: none;
      cursor: pointer;
      text-align: left;
      transition: all 0.1s;
      position: relative;
    }

    .nav-sub-item:hover { color: var(--text-sub); }

    .nav-sub-item.active {
      color: var(--text);
    }

    .nav-sub-item.active::before {
      content: '';
      position: absolute;
      left: 0; top: 0; bottom: 0;
      width: 2px;
      background: var(--text);
    }

    /* ── Collapsible parent/child nav ── */
    .nav-parent-wrap { }
    .nav-parent-row { display:flex; align-items:stretch; }
    .nav-parent-btn { flex:1; min-width:0; }
    .nav-chevron-btn {
      width:26px; background:none; border:none;
      color:var(--nav-sub,var(--text-dim)); cursor:pointer;
      font-size:var(--fs-small); display:flex; align-items:center; justify-content:center;
      transition:transform 0.18s; flex-shrink:0; padding:0 4px 0 0; opacity:0.6;
    }
    .nav-chevron-btn:hover { opacity:1; color:var(--nav-text,var(--text)); }
    .nav-parent-wrap.expanded .nav-chevron-btn { transform:rotate(90deg); }
    .nav-children { display:none; margin:2px 0 8px 24px; border-left:1px solid rgba(255,255,255,0.10); }
    .nav-parent-wrap.expanded .nav-children { display:block; }
    .nav-parent-wrap.parent-has-active > .nav-parent-row > .nav-parent-btn { opacity:1; color:var(--nav-text,var(--text)); }
    .nav-child-item {
      display:flex; align-items:center; width:100%;
      padding:6px 14px;
      font-family:var(--font-ui); font-size:var(--fs-body);
      color:var(--nav-sub,var(--text-dim)); background:none; border:none;
      cursor:pointer; text-align:left; transition:all 0.1s; position:relative;
    }
    .nav-child-item:hover { color:var(--nav-text,var(--text-sub)); }
    .nav-child-item.active { color:var(--nav-accent,var(--text)); }
    .nav-parent-btn.parent-active { opacity:1; }

    /* ── Produce dashboard ── */
    .produce-action-card { display:flex; align-items:center; gap:14px; padding:14px 16px; background:var(--bg-panel-raised); border:1px solid var(--border-subtle); border-radius:var(--radius-control); cursor:pointer; transition:border-color 0.12s,background 0.12s; }
    .produce-action-card:hover { border-color:var(--border-heavy); background:var(--surface2); }
    .produce-action-icon { font-size: var(--fs-body); color:var(--accent); background:var(--accent-muted); width:28px; height:28px; display:flex; align-items:center; justify-content:center; border-radius:var(--radius-control); flex-shrink:0; }
    .produce-action-title {
      font-family:var(--mono); font-size: var(--fs-small); font-weight:500;
        color:var(--text); margin-bottom:2px;
    }
    .produce-action-sub { font-size: var(--fs-small); color:var(--text-dim); }
    .produce-activity-row {
      display:flex; align-items:center; gap:12px; padding:10px 14px;
      border:1px solid var(--border); border-radius:3px; margin-bottom:6px;
      background:var(--surface); cursor:pointer; transition:background 0.1s;
    }
    .produce-activity-row:hover { background:var(--surface2); }

    /* ── Optimizer modal ── */
    .optimizer-change-row {
      border:1px solid var(--border); border-radius:4px;
      padding:14px; margin-bottom:12px; transition:border-color 0.15s,opacity 0.15s;
    }
    .optimizer-change-row.rejected { opacity:0.4; border-style:dashed; }
    .optimizer-change-row.accepted { border-color:var(--border-heavy); }
    .optimizer-change-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; gap:8px; }
    .change-type-badge {
      font-family:var(--mono); font-size: var(--fs-small);  
      padding:2px 6px; border:1px solid var(--border-heavy); border-radius:2px; color:var(--text-sub); flex-shrink:0;
    }
    .optimizer-toggle-btn { flex-shrink:0; font-size:var(--fs-small); }
    .optimizer-diff-block { margin-bottom:8px; }
    .optimizer-diff-label {
      font-family:var(--mono); font-size: var(--fs-small); 
       color:var(--text-dim); margin-bottom:4px;
    }
    .optimizer-diff-text {
      font-size: var(--fs-label); line-height:1.55; padding:8px 10px;
      border-radius:3px; color:var(--text-sub);
    }
    .optimizer-diff-text.original { background:color-mix(in srgb, var(--negative) 8%, transparent); border-left:2px solid var(--red); }
    .optimizer-diff-text.proposed { background:color-mix(in srgb, var(--positive) 8%, transparent); border-left:2px solid var(--green); }
    @keyframes spin { to { transform:rotate(360deg); } }
    .spin { animation:spin 0.8s linear infinite; }

    /* ══════════════════════════════════════
       MAIN AREA
    ══════════════════════════════════════ */
    .main {
      display: flex;
      flex-direction: column;
      height: 100vh;
      overflow: hidden;
      overflow-x: hidden;
      min-width: 0;
    }

    .main-header {
      position: sticky;
      top: 0;
      z-index: 500;
      background: var(--bg-app);
      padding: 16px 32px 14px;
      border-bottom: 1px solid var(--border-subtle);
      display: flex;
      align-items: center;
      justify-content: space-between;
      flex-shrink: 0;
      min-height: 64px;
      gap: 14px;
    }

    .main-heading {
      display: flex;
      align-items: baseline;
      gap: 14px;
    }

    /* R2: the page title is the one 800 on the screen, at the title size. It was 18px / 700,
       which was neither a scale size nor a brand weight. */
    .main-title {
      font-size: var(--fs-title);
      font-weight: 800;
      letter-spacing: -0.03em;
    }

    .main-subtitle {
      font-family: var(--font-ui);
      font-size: var(--fs-label);
      color: var(--text-tertiary);
    }

    .main-actions {
      display: flex;
      gap: 12px;
      align-items: center;
    }

    /* Full-width scroll area next to the sidebar; the centered container lives on each panel. */
    .main-content {
      flex: 1;
      overflow-y: auto;
      overflow-x: hidden;
      padding: 0;
      min-width: 0;
    }

    .main-content::-webkit-scrollbar { width: 5px; }
    .main-content::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

    /* ── PANELS ──
       Every tab's content is wrapped in this consistent container: capped at a
       readable maximum, centered, with consistent 32px side padding. Individual
       panels can set a tighter max-width of their own. */
    .panel {
      display: none;
      width: 100%;
      /* ⚠ R3: CENTRED IN THE AREA RIGHT OF THE SIDEBAR, WITH EQUAL MARGINS.
         R2 pinned this hard left (`margin: 0`) on a 1440px cap, which looks right at 1440 and
         wrong at 2000: the content filled the left two thirds and the right third was empty.
         Centred again, and the cap is raised so a 1920 to 2000px screen is filled rather than
         merely centred in. Below the cap the column is the full available width, so the two
         margins are the gutter on each side; above it the leftover splits evenly by `auto`.
         Either way left equals right, which is what the smoke measures at three widths. */
      max-width: var(--page-max);
      margin: 0 auto;
      padding: 0 var(--page-gutter) var(--space-16);
      min-width: 0;
      overflow: hidden;
    }
    .panel.active { display: block; }
    /* Flex panels need display:flex when active, not display:block */
    #panel-intelligence.active { display: flex; flex-direction: column; }

    /* Write tab mode toggle (New Page / Rewrite Existing) */
    .write-toggle-wrap { display: inline-flex; border: 1px solid var(--border); border-radius: var(--radius-control); overflow: hidden; }
    .write-toggle {
      background: transparent; border: none; cursor: pointer; padding: 9px 18px;
      font-family: var(--font-ui); font-size: var(--fs-label); font-weight: 500; color: var(--text-dim);
      transition: background 0.12s, color 0.12s;
    }
    .write-toggle:hover { color: var(--text); }
    .write-toggle.active { background: var(--surface); color: var(--text); }

    /* Model Quality selector */
    .mq-opt { flex:1; min-width:150px; text-align:left; background:var(--bg-panel); border:1px solid var(--border-subtle); border-radius:var(--radius-control); padding:11px 13px; cursor:pointer; color:var(--text-primary); font-family:var(--font-ui); transition:border-color 0.12s; }
    .mq-opt:hover { border-color: var(--border-heavy, var(--text-dim)); }
    .mq-opt.active { border-color: var(--accent); background: var(--accent-muted); box-shadow: none; }

    /* Optimize cockpit columns */
    .opt-cockpit { display: grid; grid-template-columns: 1fr 1.1fr 1fr; gap: 16px; align-items: start; }
    @media (max-width: 1080px) { .opt-cockpit { grid-template-columns: 1fr; } }
    .opt-col { border: 1px solid var(--border); border-radius: 8px; padding: 16px; min-width: 0; }
    .opt-col-title { font-family: var(--mono); font-size: var(--fs-small); color: var(--text-dim); margin-bottom: 14px; }
    .opt-chip { display: block; width: 100%; text-align: left; border: 1px solid var(--border); background: var(--surface); color: var(--text); border-radius: var(--radius-control); padding: 9px 11px; margin-bottom: 8px; cursor: pointer; font-size: var(--fs-label); line-height: 1.4; font-family: inherit; transition: border-color 0.12s; }
    .opt-chip:hover { border-color: var(--border-heavy, var(--text-dim)); }
    .opt-stat-row { display: flex; justify-content: space-between; align-items: baseline; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: var(--fs-label); }
    .opt-stat-row:last-child { border-bottom: none; }
    .opt-stat-label { color: var(--text-dim); font-family: var(--mono); font-size: var(--fs-small); }
    .opt-stat-val { color: var(--text); font-weight: 500; }
    .opt-action-btn { display: block; width: 100%; text-align: left; }

    /* Publish queue chips (draggable) */
    /* (.pub-* rules consolidated in the PUBLISH block near the end of this file) */

    /* ══════════════════════════════════════
       PAGE STRUCTURE
    ══════════════════════════════════════ */
    /* R4: on the spacing scale. 36px was the one value in this screen that was not a
       multiple of four, and it set the rhythm for every section below it. */
    .page-section {
      border-bottom: 1px solid var(--border-subtle);
      padding: var(--space-8) 0;
    }

    /* ══ R5: TWO COLUMNS, NOT THREE ══════════════════════════════════════════════════════
       Settings showed the tab list, then a 160px column holding nothing but the section's name,
       then the content. The middle column was a label standing on its own, and because it was a
       grid track it reserved its width on every section whether the name was one word or three,
       pushing every field a further 184px right. At 1440 that left the forms starting past the
       middle of the screen.

       The label is the section's HEADING now, inside the content, so the row is one column and
       the tab list is the only thing beside it. Nothing in the markup moved: .section-label is
       still the first child of .section-row, it simply stops being a track of its own. */
    .section-row {
      display: block;
      min-width: 0;
    }
    .section-row > .section-label {
      display: block;
      margin-bottom: var(--space-4);
    }

    /* R5: it is the section's heading now rather than a column of its own, so it is set as one.
       The heading step and the primary level, because a heading inside the content has to lead
       the block it names; at the label size and the secondary level it read as another field
       label among the fields. */
    .section-label {
      font-family: var(--font-ui);
      font-size: var(--fs-heading);
      font-weight: 500;
      letter-spacing: -0.015em;
      color: var(--text-primary);
      padding-top: 0;
    }

    .section-content { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }

    /* ── FORMS ── */
    .form-row {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: var(--space-4);
    }

    .form-row.full { grid-template-columns: 1fr; }
    .field { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-4); }

    /* R4: on the scale. It was 11px at weight 700, which is not a brand weight, and the
       combination is what made every field label read as cramped shouting. */
    label {
      font-family: var(--font-ui);
      font-size: var(--fs-label);
      font-weight: 500;
      color: var(--text-secondary);
    }

    /* Terminal spec §3: inputs sit on --bg-panel-raised with a 1px strong
       border and control radius (replaces the old underline-only treatment).
       Checkboxes/radios excluded — they keep their restored native rendering. */
    input:not([type=checkbox]):not([type=radio]), select, textarea {
      font-family: var(--sans);
      font-size: var(--fs-body);
      font-weight: 400;
      color: var(--text);
      background: var(--bg-panel-raised);
      border: 1px solid var(--border-strong);
      border-radius: var(--radius-control);
      padding: 9px 12px;
      outline: none;
      transition: border-color 0.15s;
      width: 100%;
      appearance: none;
      -webkit-appearance: none;
    }

    /* CONTRAST FIX: --text-dim (#505050 dark / #aaa light) is below readable
       contrast for placeholder copy — use --text-sub, still visibly lighter than
       real input text but legible on every theme. */
    /* R5: 400, not 300. Neither the self-hosted faces nor the system stack carries a 300, so
       the browser synthesised one or fell back, differently per platform. */
    input::placeholder, textarea::placeholder { color: var(--text-sub, #a0a0a0); opacity: .85; font-weight: 400; }
    /* Unit 52: a capability question's example text must never be mistaken for a prefilled answer.
       The onboarding form is almost entirely prefilled from the site read, so the two sit side by
       side on the same screen and the operator's question is "did Centraloom find this, or is it
       showing me what to type". The general placeholder above is --text-sub at .85, which is close
       to a real value; these are --text-dim, fainter still, and italic so the difference survives a
       theme, a projector and a colour-blind reader. The "For example" line under each question
       stays: it is the one an operator can read without clicking into the box. */
    .cap-field::placeholder { color: var(--text-dim, #6b6b73); opacity: .7; font-style: italic; font-weight: 400; }
    /* Focus = the aura ("the light is here"). The old white-accent border was
       nearly invisible against the white-accent resting border. */
    input:focus, select:focus, textarea:focus { border-color: var(--aura); box-shadow: 0 0 0 2px var(--accent-glow); }

    /* ── SAFE / LIVE MODE ── */
    /* Fixed top-right, positioned CLEAR of the header's client-switcher box
       (right:56px used to overlap it — the "stray text over the titlebar"
       artifact). Opaque panel bg + high z so it reads above anything at any
       window size; the mode indicator must never be buried. */
    /* R2: on the system. It was 10px and 11.5px, neither of them a scale step, at weight 700,
       which is not a brand weight. The mode COLOUR is left alone: safe green and live red are
       data meaning, the one thing the brand keeps colour for besides the accent, and app.js
       sets it inline from the mode. */
    #site-mode-ctrl {
      position: static;
      display: flex; align-items: center; gap: var(--space-2);
      font-family: var(--font-ui); font-size: var(--fs-small); letter-spacing: .08em;
      background: var(--bg-panel); border: 1px solid var(--border-strong); border-radius: var(--radius-pill);
      padding: var(--space-1) var(--space-2) var(--space-1) var(--space-3);
    }
    /* R6: monospace made "SAFE MODE" wrap onto two lines inside its pill at 1280. The mode
       indicator is the one control that must never be ambiguous, so it stays on one line. */
    #site-mode-ctrl { white-space: nowrap; flex-shrink: 0; }
    #site-mode-ctrl .sm-label { font-weight: 500; white-space: nowrap; }
    #site-mode-ctrl .sm-btn {
      border: 1px solid var(--border); background: none; color: var(--text-sub);
      border-radius: var(--radius-pill); padding: var(--space-1) var(--space-3); cursor: pointer;
      font-family: var(--font-ui); font-size: var(--fs-small); font-weight: 500; letter-spacing: 0;
    }
    #site-mode-ctrl .sm-btn:hover { border-color: var(--border-strong); color: var(--text); }
    body.live-mode-on { border: 3px solid var(--live-mode); box-sizing: border-box; }
    #live-mode-banner {
      display: none; position: fixed; top: 0; left: 0; right: 0; z-index: 5999;
      background: #7f1d1d; color: #fff; text-align: center;
      font-family: var(--font-ui); font-size: var(--fs-small);
      padding: 5px 0; font-weight: 500; letter-spacing: .04em;
    }
    body.live-mode-on #live-mode-banner { display: block; }
    /* Controls that require Live Mode: greyed + inert while safe. */
    body.safe-mode .live-gated { opacity: .38 !important; pointer-events: none !important; cursor: not-allowed !important; }

    /* Campaign-entry doors: three mode cards, progressive disclosure below. */
    .gen-mode-card {
      flex: 1; min-width: 180px; text-align: left; cursor: pointer;
      background: var(--surface, #161616); border: 1px solid var(--border, #333);
      border-radius: var(--radius-control); padding: 14px 16px; color: var(--text, #e8e8e8);
      transition: border-color .15s ease;
    }
    .gen-mode-card:hover { border-color: var(--text-dim, #888); }
    /* Selection is neutral (matches .write-toggle.active): no accent ring. */
    .gen-mode-card.active { background: var(--surface); border-color: var(--border-strong); }
    .gen-mode-card .gm-title { font-family: var(--mono); font-size: var(--fs-small); margin-bottom: 6px; }
    .gen-mode-card .gm-desc { font-size: var(--fs-label); color: var(--text-sub, #a0a0a0); line-height: 1.4; }

    /* Supporting-blog keep/check boxes: the global "appearance:none" above strips
       native checkbox rendering, making these invisible. Restore a visible,
       checkable box for these classes only (markup/wiring unchanged). */
    .spoke-idea-pick, .spoke-pick {
      appearance: auto;
      -webkit-appearance: auto;
      width: 16px;
      height: 16px;
      border: none;
      border-bottom: none;
      accent-color: var(--positive);
      cursor: pointer;
      margin-top: 3px;
    }

    select {
      cursor: pointer;
      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%23aaa'/%3E%3C/svg%3E");
      background-repeat: no-repeat;
      background-position: right 4px center;
      padding-right: 20px;
    }

    textarea { resize: none; line-height: 1.7; }

    /* ⚠ R4: 9px WITH LETTER SPACING WAS NOT A HINT, IT WAS A DARE.
       Every explanatory line under every field in Settings used this, at the smallest size in
       the file and tracked out on top of that. It is the quiet step of the scale now, set
       normally, and it stays the muted level so it still reads as secondary. */
    .field-hint {
      font-family: var(--font-ui);
      font-size: var(--fs-small);
      color: var(--text-tertiary);
      letter-spacing: 0;
      line-height: 1.5;
    }
    /* "(optional)" / parenthetical qualifier inside a <label> — shared by Write and the Campaign wizard. */
    .label-opt { font-weight: 400; opacity: .5; }

    /* ── BUTTONS ── */
    /* ══ R5: THE THREE BUTTON LEVELS ═════════════════════════════════════════════════════
       Shape, type and cursor for every button in the application, named once. A class absent
       from this list renders as the browser's own grey box on a black page, which is how
       .btn-ghost and .ig-btn shipped. Layout-only classes (.ps-btn, .wiz-btn-sm, .camp-btn-xs)
       stay as size modifiers on top of a level. */
    .ui-btn, .btn, .btn-sm, .btn-ghost, .ig-btn, .ig-btn-primary, .camp-btn, .camp-view-btn,
    .filter-btn, .btn-retry, .import-mode-btn, .itree-page-btn, .tracked-btn, .day-btn,
    .score-toggle-btn, .optimizer-toggle-btn, .copy-btn, .intel-view-btn, .intel-gsc-filter-btn {
      font-family: var(--font-ui);
      font-size: var(--fs-label);
      font-weight: 500;
      line-height: 1.4;
      letter-spacing: 0;
      padding: var(--space-2) var(--space-3);
      border-radius: var(--radius-control);
      border: 1px solid transparent;
      background: transparent;
      cursor: pointer;
      white-space: nowrap;
      transition: background .12s, border-color .12s, color .12s;
    }
    /* ── primary: orange, one per area ── */
    .ui-btn.primary, .btn, .ig-btn-primary {
      background: var(--accent); border-color: var(--accent); color: var(--accent-ink, #fff);
    }
    .ui-btn.primary:hover, .btn:hover, .ig-btn-primary:hover {
      background: var(--accent-hover); border-color: var(--accent-hover);
    }
    /* ── secondary: a quiet outline, and the level nearly everything is ── */
    .ui-btn.ghost, .btn-sm, .btn-ghost, .ig-btn, .camp-btn, .camp-view-btn, .filter-btn,
    .import-mode-btn, .itree-page-btn, .tracked-btn, .day-btn, .score-toggle-btn,
    .optimizer-toggle-btn, .intel-view-btn, .intel-gsc-filter-btn {
      border-color: var(--border-strong); color: var(--text-secondary);
    }
    .ui-btn.ghost:hover, .btn-sm:hover, .btn-ghost:hover, .ig-btn:hover, .camp-btn:hover,
    .camp-view-btn:hover, .filter-btn:hover, .import-mode-btn:hover, .itree-page-btn:hover,
    .tracked-btn:hover, .day-btn:hover, .score-toggle-btn:hover, .optimizer-toggle-btn:hover,
    .intel-view-btn:hover, .intel-gsc-filter-btn:hover {
      color: var(--text-primary); background: var(--bg-panel-raised); border-color: var(--border-strong);
    }
    /* ── tertiary: text only, a box only under the pointer ── */
    .ui-btn.text, .copy-btn {
      border-color: transparent; color: var(--text-secondary); padding: var(--space-1) var(--space-2);
    }
    .ui-btn.text:hover, .copy-btn:hover { color: var(--text-primary); background: var(--bg-panel-raised); }
    /* ── modifiers, which are states of a level rather than levels ── */
    .ui-btn.ghost.danger, .camp-btn.danger, .tracked-btn.danger, .btn-sm.pub-danger, .btn-retry {
      border-color: var(--negative); color: var(--negative);
    }
    .ui-btn.ghost.danger:hover, .camp-btn.danger:hover, .tracked-btn.danger:hover,
    .btn-sm.pub-danger:hover, .btn-retry:hover {
      background: var(--negative); color: #fff; border-color: var(--negative);
    }
    /* ⚠ SELECTED IS AN ACCENT WASH, NOT SOLID WHITE. .intel-view-btn.active, .day-btn.selected
       and .camp-btn.launch each painted white on black, which reads louder than the primary
       action beside them. Same treatment .mq-opt.active already uses. */
    .camp-btn.launch, .intel-view-btn.active, .day-btn.selected, .filter-btn.active,
    .import-mode-btn.active, .camp-view-btn.active, .intel-gsc-filter-btn.active {
      background: var(--accent-muted); border-color: var(--accent); color: var(--text-primary);
    }
    .camp-btn.launch:hover, .intel-view-btn.active:hover, .day-btn.selected:hover,
    .filter-btn.active:hover, .import-mode-btn.active:hover, .camp-view-btn.active:hover {
      background: var(--accent-muted); border-color: var(--accent); color: var(--text-primary);
    }
    .ui-btn:disabled, .btn:disabled, .btn-sm:disabled, .btn-ghost:disabled, .ig-btn:disabled,
    .camp-btn:disabled {
      opacity: 1; color: var(--text-tertiary); border-color: var(--border-subtle);
      background: transparent; cursor: not-allowed;
    }
    .ui-btn:disabled:hover, .btn:disabled:hover, .btn-sm:disabled:hover, .btn-ghost:disabled:hover,
    .ig-btn:disabled:hover, .camp-btn:disabled:hover {
      background: transparent; color: var(--text-tertiary); border-color: var(--border-subtle);
    }
    /* R5: appearance comes from the primary level; this keeps only what is layout. */
    .btn { display: inline-block; margin-top: var(--space-2); }




    /* ── PROGRESS ── */
    .progress-section {
      display: none;
      border-bottom: 1px solid var(--border);
      padding: 32px 0;
    }

    .progress-section.visible { display: block; }

    .progress-inner {
      display: grid;
      grid-template-columns: 180px 1fr;
      gap: 40px;
      align-items: center;
    }

    .progress-status {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-dim);
    }

    .progress-track { display: flex; flex-direction: row; align-items: center; gap: 0; }

    .progress-step {
      flex: 1;
      text-align: center;
      position: relative;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 4px;
    }

    .progress-step:not(:last-child)::after {
      content: '';
      position: absolute;
      top: 4px; left: 50%;
      width: 100%; height: 1px;
      background: var(--border-heavy);
    }

    .progress-step.done:not(:last-child)::after { background: var(--text); }

    .step-node {
      width: 8px; height: 8px;
      border-radius: 50%;
      border: 1px solid var(--border-heavy);
      background: var(--bg);
      position: relative;
      z-index: 1;
      margin: 0 auto 4px;
      transition: all 0.2s;
    }

    /* Running = the aura ring (matches .ui-feed-dot.run). Background stays --bg,
       not transparent, so the hollow centre masks the connecting track line. */
    .progress-step.active .step-node { background: var(--bg); border: 1.5px solid var(--aura);
      box-shadow: 0 0 0 2px var(--accent-glow-strong); animation: uiPulse 1.4s ease-in-out infinite; }
    .progress-step.done .step-node   { background: var(--text);  border-color: var(--text); }

    .step-lbl {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-dim);
      display: block;
    }

    .progress-step.active .step-lbl { color: var(--text-sub); }
    .progress-step.done .step-lbl   { color: var(--text); }

    /* ── HISTORY ── */
    .history-header {
      display: grid;
      grid-template-columns: 60px 1fr 110px 115px 80px minmax(70px, auto);
      gap: 10px;
      padding: 16px 0 12px;
      border-bottom: 2px solid var(--text);
    }

    .history-header span {
      font-family: var(--font-ui);
      font-size: var(--fs-small);
      font-weight: 500;
      color: var(--text-dim);
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .job-row-wrap { border-bottom: 1px solid var(--border); }
    .job-row-wrap .job-row { border-bottom: none !important; }

    .job-row {
      display: grid;
      grid-template-columns: 60px 1fr 110px 115px 80px minmax(70px, auto);
      gap: 10px;
      padding: 18px 0;
      align-items: center;
      transition: background 0.1s;
    }

    .job-row:hover { background: var(--surface); margin: 0 -16px; padding: 18px 16px; }

    .job-type {
      font-family: var(--mono);
      font-size: var(--fs-small);
      font-weight:500;
      letter-spacing: 0.12em;
      text-transform: uppercase;
    }

    .job-type.generate { color: var(--blue); }
    .job-type.rewrite  { color: var(--amber); }
    .job-type.batch    { color: var(--green); }

    .job-keyword-main {
      font-size: var(--fs-label);
      font-weight: 500;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .job-client-cell {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-sub);
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }

    .job-time-cell {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-dim);
    }

    .job-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }

    .doc-link {
      font-family: var(--mono);
      font-size: var(--fs-small);
      font-weight:500;
      text-decoration: none;
      color: var(--text);
      border-bottom: 1px solid var(--text);
      padding-bottom: 1px;
      transition: opacity 0.1s;
    }

    .doc-link:hover { opacity: 0.5; }
    .doc-link.brief { color: var(--text-sub); border-color: var(--text-sub); }

    .copy-btn {
      font-family: var(--mono);
      font-size: var(--fs-small);
      background: none;
      border: none;
      color: var(--text-dim);
      cursor: pointer;
      padding: 0;
      transition: color 0.1s;
    }

    .copy-btn:hover { color: var(--text); }

    .status-running {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-secondary);   /* running is live, not pending: the pulse says so, not amber */
    }

    .status-error {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--negative);   /* an error state: the one legitimate red */
    }

    .score-toggle-btn {
      font-family: var(--mono);
      font-size: var(--fs-small);
      font-weight:500;
      letter-spacing: 0.08em;
      background: none;
      border: 1px solid var(--border-heavy);
      padding: 3px 8px;
      cursor: pointer;
      color: var(--text-sub);
      transition: all 0.1s;
    }

    .score-toggle-btn:hover { border-color: var(--text); color: var(--text); }

    .history-scorecard {
      padding: 20px 0 24px 40px;
      border-top: 1px solid var(--border);
      background: var(--surface);
    }

    .hs-header { display: flex; align-items: baseline; gap: 14px; margin-bottom: 16px; }

    .hs-score {
      font-size: var(--fs-title);
      font-weight:500;
      letter-spacing: -0.04em;
      line-height: 1;
    }

    /* Same pill as the Write result (.write-score-badge): the render sets background and color
       inline, white on accent-muted for Passed, text-secondary on accent-muted for Below gate. */
    /* R5: on a brand weight. 700 is not one of the three the brand allows, and it was on both
       halves of this pair, so the pair stays matched. */
    .hs-badge {
      font-family: var(--mono);
      font-size: var(--fs-small);
      font-weight: 500;
      padding: 4px 10px;
    }

    .hs-checks {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 0 40px;
      margin-bottom: 12px;
    }

    .qs-hist-item {
      display: flex;
      align-items: center;
      gap: 8px;
      font-family: var(--mono);
      font-size: var(--fs-small);
      padding: 5px 0;
      border-bottom: 1px solid var(--border);
    }

    .hs-notes {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-sub);
      letter-spacing: 0.04em;
      margin-top: 8px;
    }

    .qs-item {
      display: flex;
      align-items: center;
      gap: 8px;
      font-family: var(--mono);
      font-size: var(--fs-small);
      letter-spacing: 0.04em;
      padding: 5px 0;
      border-bottom: 1px solid var(--border);
    }

    .qs-dot {
      width: 5px; height: 5px;
      border-radius: 50%;
      flex-shrink: 0;
    }

    /* A failed check is a failure state and reads red; a passed one is text. */
    .qs-dot.pass { background: var(--text); }
    .qs-dot.fail { background: var(--negative); }
    .qs-label-pass { color: var(--text-sub); }
    .qs-label-fail { color: var(--negative); }

    /* ── FEED ── */
    .feed-stats {
      display: grid;
      grid-template-columns: repeat(4, 1fr);
      border-top: 2px solid var(--text);
      border-left: 2px solid var(--text);
    }

    .feed-stat {
      border-right: 2px solid var(--text);
      border-bottom: 2px solid var(--text);
      padding: 20px 24px;
    }

    .feed-stat-num {
      font-size: var(--fs-title);
      font-weight:500;
      letter-spacing: -0.04em;
      line-height: 1;
      margin-bottom: 4px;
    }

    .feed-stat-label {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-dim);
    }

    .feed-stream {
      background: var(--surface);
      border-left: 2px solid var(--text);
      border-right: 2px solid var(--text);
      border-bottom: 2px solid var(--text);
      min-height: 400px;
      max-height: 560px;
      overflow-y: auto;
      padding: 16px 20px;
      font-family: var(--mono);
    }

    .feed-stream .empty-state { color: #444; font-family: var(--mono); }

    .feed-line {
      display: flex;
      align-items: baseline;
      gap: 12px;
      padding: 3px 20px;
      animation: feedSlide 0.25s ease;
      line-height: 1.6;
    }

    .feed-line:hover { background: rgba(255,255,255,0.03); }

    @keyframes feedSlide {
      from { opacity: 0; transform: translateX(-6px); }
      to   { opacity: 1; transform: translateX(0); }
    }

    .feed-ts { font-size: var(--fs-small); color: #3a3f52; flex-shrink: 0; letter-spacing: 0.04em; }

    .feed-prefix {
      font-size: var(--fs-small);
      flex-shrink: 0;
      min-width: 72px;
    }

    .feed-prefix.complete      { color: #4fc98e; }
    .feed-prefix.quality_pass  { color: #4fc98e; }
    .feed-prefix.error         { color: #e06b6b; }
    .feed-prefix.quality_fail  { color: #f0b86e; }
    .feed-prefix.rewriting     { color: #f0b86e; }
    .feed-prefix.rewriting_quality { color: #f0b86e; }
    .feed-prefix.writing       { color: #7eb8f7; }
    .feed-prefix.writing_page  { color: #7eb8f7; }
    .feed-prefix.checking_quality { color: #a78bfa; }
    .feed-prefix.job_start     { color: #555b75; }
    .feed-prefix.brief         { color: #555b75; }
    .feed-prefix.brief_saved   { color: #555b75; }
    .feed-prefix.generating_brief { color: #555b75; }
    .feed-prefix.saving_brief  { color: #555b75; }
    .feed-prefix.saving_page   { color: #555b75; }
    .feed-prefix.live          { color: var(--text-primary); }

    .feed-text { font-size: var(--fs-small); color: #8b90a8; flex: 1; }
    .feed-text .kw { color: #c8cad8; font-weight:500; }
    .feed-text .score-pass { color: #4fc98e; font-weight:500; }
    .feed-text .score-fail { color: #e06b6b; font-weight:500; }

    .feed-text .feed-open {
      color: #4fc98e;
      text-decoration: none;
      margin-left: 8px;
      border-bottom: 1px solid #2a5a40;
      font-size: var(--fs-small);
    }

    .feed-text .feed-open:hover { border-color: #4fc98e; }

    .feed-cursor {
      display: inline-block;
      width: 7px; height: 12px;
      background: #3a3f52;
      margin-left: 4px;
      animation: blink 1s infinite;
      vertical-align: middle;
    }

    @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }

    /* ── STUB PANELS ── */
    .stub-hero {
      padding: 56px 0 44px;
      border-bottom: 1px solid var(--border);
      max-width: 580px;
    }

    .stub-icon { font-size: var(--fs-title); margin-bottom: 16px; color: var(--text-dim); }

    .stub-title {
      font-size: var(--glyph-lg);
      font-weight:500;
      letter-spacing: -0.03em;
      margin-bottom: 14px;
    }

    .stub-desc {
      font-size: var(--fs-body);
      line-height: 1.7;
      color: var(--text-sub);
      margin-bottom: 22px;
      font-weight:400;
    }

    .stub-pills { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 24px; }

    .stub-pill {
      font-family: var(--mono);
      font-size: var(--fs-small);
      border: 1px solid var(--border-heavy);
      padding: 4px 10px;
      color: var(--text-sub);
    }

    .stub-coming {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-dim);
    }

    .stub-preview-grid {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      border-top: 2px solid var(--text);
      border-left: 2px solid var(--text);
    }

    .stub-preview-card {
      border-right: 2px solid var(--text);
      border-bottom: 2px solid var(--text);
      padding: 24px;
    }

    .stub-preview-label {
      font-family: var(--mono);
      font-size: var(--fs-small);
      font-weight:500;
      color: var(--text-dim);
      margin-bottom: 10px;
    }

    .stub-preview-desc {
      font-size: var(--fs-label);
      line-height: 1.6;
      color: var(--text-sub);
      font-weight:400;
    }

    /* Survivors of the deleted RESEARCH block — renderResearchNoGsc still renders these. */
    .research-no-gsc { text-align:center; padding:60px 0; color:var(--text-dim); }
    .research-no-gsc .no-gsc-icon { font-size: var(--glyph-lg); margin-bottom:12px; }
    .research-no-gsc p { font-size: var(--fs-label); margin:6px 0; }
    .comp-domain-row { display:flex; align-items:center; gap:16px; padding:12px 0; border-bottom:1px solid var(--border); }
    .comp-domain-row:last-child { border-bottom:none; }
    .comp-domain { font-size: var(--fs-label); font-weight:500; color:var(--text); min-width:200px; }
    .comp-kw-list { flex:1; display:flex; flex-wrap:wrap; gap:6px; }
    .comp-kw-chip { font-family:var(--mono); font-size: var(--fs-small); padding:2px 8px; background:var(--surface); border:1px solid var(--border); border-radius:2px; color:var(--text-sub); }

    /* ── CAMPAIGNS ── */
    .camp-view-btn:first-child { border-radius:3px 0 0 3px; }
    .camp-view-btn:last-child { border-radius:0 3px 3px 0; border-left:none; }
    .camp-view-btn:not(:first-child):not(:last-child) { border-left:none; }
    .camp-view-pane { display:none; }
    .camp-view-pane.active { display:block; }
    /* Pipeline cards */
    .camp-card { border:1px solid var(--border); border-left:3px solid var(--border); border-radius:4px; padding:12px 16px; margin-bottom:10px; transition:border-color 0.15s; position:relative; overflow:hidden; word-break:break-word; }
    .camp-card.status-draft { border-left-color:var(--border); }
    .camp-card.status-active { border-left-color:rgba(255,255,255,0.25); }
    .camp-card.status-complete { border-left-color:rgba(255,255,255,0.25); }
    .camp-card.status-paused { border-left-color:var(--text-dim); }
    .camp-card:hover { border-color:var(--text-sub); }
    .camp-card-header { display:flex; align-items:flex-start; justify-content:space-between; gap:16px; margin-bottom:10px; }
    .camp-card-title { font-size: var(--fs-label); font-weight:500; color:var(--text); }
    .camp-card-meta { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); margin-top:3px; }
    .camp-status-badge { font-family:var(--mono); font-size: var(--fs-small); padding:3px 8px; border-radius:2px; flex-shrink:0; }
    .camp-status-badge.draft { background:var(--surface); color:var(--text-dim); }
    .camp-status-badge.active { background:var(--surface); color:var(--text-secondary); }
    .camp-status-badge.complete { background:transparent; color:var(--text-tertiary); }
    .camp-status-badge.paused { background:var(--surface); color:var(--text-dim); }
    .camp-progress-row { display:flex; align-items:center; gap:12px; margin-bottom:10px; }
    .camp-progress-bar { flex:1; height:3px; background:var(--border); border-radius:2px; overflow:hidden; }
    .camp-progress-fill { height:100%; border-radius:2px; background:var(--text); transition:width 0.5s; }
    .camp-progress-label { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-sub); white-space:nowrap; }
    .camp-stats-row { display:flex; gap:20px; flex-wrap:wrap; margin-bottom:10px; }
    .camp-stat { display:flex; flex-direction:column; gap:1px; }
    .camp-stat-val { font-family:var(--mono); font-size: var(--fs-small); font-weight:500; color:var(--text); }
    .camp-stat-label { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); }
    .camp-actions { display:flex; gap:6px; flex-wrap:wrap; opacity:0; transition:opacity 0.15s; }
    .camp-card:hover .camp-actions { opacity:1; }
    /* Velocity indicator */
    .camp-velocity { font-family:var(--mono); font-size: var(--fs-small); padding:3px 8px; border-radius:2px; }
    .camp-velocity.on-track { background:rgba(255,255,255,0.07); color:var(--text-secondary); }
    .camp-velocity.behind { background:var(--warning-muted); color:var(--warning); }
    .camp-velocity.stalled { background:color-mix(in srgb, var(--negative) 10%, transparent); color:var(--negative); }
    /* Board view */
    #camp-board { display:flex; width:100%; overflow-x:hidden; gap:6px; }
    .board-col { flex:1; min-width:0; display:flex; flex-direction:column; gap:0; }
    .board-col-header { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); padding:8px 10px; border-bottom:1px solid var(--border); display:flex; align-items:center; justify-content:space-between; background:var(--surface); border-radius:3px 3px 0 0; }
    .board-col-count { background:var(--border); color:var(--text-dim); font-size: var(--fs-small); padding:1px 5px; border-radius:10px; }
    .board-col-body { flex:1; min-height:200px; padding:6px; background:var(--surface); border-radius:0 0 3px 3px; border:1px solid var(--border); border-top:none; display:flex; flex-direction:column; gap:5px; overflow-y:auto; max-height:calc(100vh - 180px); }
    .board-card { background:var(--bg); border:1px solid var(--border); border-radius:3px; padding:8px 10px; cursor:pointer; transition:border-color 0.12s; word-break:break-word; font-size: var(--fs-label); }
    .board-card:hover { border-color:var(--text-sub); }
    .board-card-kw { font-size: var(--fs-small); color:var(--text); margin-bottom:4px; line-height:1.3; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .board-card-meta { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); display:flex; gap:4px; align-items:center; overflow:hidden; }
    .board-card-score { font-family:var(--mono); font-size: var(--fs-small); font-weight:500; margin-left:auto; color:var(--text); }
    /* Board chrome de-inlined from the markup/template (identity colors — the
       per-column BOARD_COLS border-top and per-card CLIENT_COLORS border/dot —
       stay inline by the identity carve-out). */
    .board-wrap { min-width:0; overflow-x:hidden; }
    .board-filter-row { display:flex; gap:2px; margin-bottom:12px; align-items:center; }
    .board-filter { font-family:var(--mono); font-size: var(--fs-small); padding:4px 8px; background:var(--surface); border:1px solid var(--border); color:var(--text); border-radius:2px; }
    .board-empty { padding:12px 8px; font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); text-align:center; }
    .board-card-dot { width:6px; height:6px; border-radius:50%; flex-shrink:0; }
    .board-card.stale { border-left:2px solid var(--warning); }   /* stale = pending decision → real amber (--status-warning is aliased gray) */
    .board-card-stage { font-family:var(--mono); font-size: var(--fs-small); letter-spacing:0.06em; color:var(--text-dim); margin-top:3px; display:flex; align-items:center; gap:4px; }
    .board-card-stage .live-dot { width:5px; height:5px; border-radius:50%; background:transparent; border:1.5px solid var(--aura); box-shadow: 0 0 0 2px var(--accent-glow-strong); animation:uiPulse 1.4s ease-in-out infinite; flex-shrink:0; }
    .board-card.running { border-color:rgba(255,255,255,0.25); }
    /* Calendar drag */
    .cal-cell.drag-over { outline:2px dashed var(--accent-glow-strong); outline-offset:-2px; }
    .cal-page-chip.dragging { opacity:0.4; }
    .cal-page-chip[draggable="true"] { cursor:grab; }
    .cal-page-chip[draggable="true"]:active { cursor:grabbing; }
    /* Calendar */
    .cal-grid { display:grid; grid-template-columns:repeat(7,1fr); gap:2px; }
    .cal-day-header { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); text-align:center; padding:6px 0; }
    .cal-cell { min-height:80px; background:var(--surface); border:1px solid var(--border); border-radius:3px; padding:6px; transition:background 0.1s; position:relative; overflow:hidden; }
    /* Now = the aura. Bloom derived from the shipped halo constants (no prototype
       today-treatment exists to copy): inset wash + soft outer glow. */
    .cal-cell.today { border-color:var(--accent); }
    .cal-cell.other-month { opacity:0.35; }
    .cal-cell:not(.other-month) { cursor:pointer; }
    .cal-cell:hover:not(.other-month) { background:var(--surface2); }
    .cal-cell.import-hover { outline:2px dashed var(--accent); }

    /* Import Panel */
    .import-mode-bar { display:flex; gap:2px; background:var(--surface2); border-radius:4px; padding:2px; }
    .import-mode-btn { flex:1; }
    .import-dropzone { border:1px dashed var(--border-heavy); border-radius:6px; padding:12px; transition:border-color 0.15s, background 0.15s; position:relative; }
    .import-dropzone.dragover { border-color:var(--aura); background:var(--accent-wash); }   /* drop target = current → aura, like .pub-cal-day.drop-hover */
    /* Import drawer de-inline: rides the campaign drawer shell (deltas: 660px wide,
       z-index 4200, .65 backdrop) and the shared wizard/publish classes. */
    .imp-drawer-overlay { z-index:4200; background:rgba(0,0,0,0.65); }
    .imp-drawer { width:660px; max-width:96vw; }
    /* ── Page presets builder (Settings → Publishing, Publish Studio U5) ── */
    .ps-wrap { border-top:1px solid var(--border-subtle); padding-top:var(--space-4); margin-top:var(--space-4); }
    .ps-btn { font-size:var(--fs-small); padding:3px 10px; }
    .ps-list { margin:10px 0 14px; }
    .ps-empty { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); padding:8px 0; }
    .ps-row { display:flex; align-items:center; gap:12px; padding:8px 10px; border:1px solid var(--border); border-radius:4px; margin-bottom:6px; cursor:pointer; }
    .ps-row:hover { background:var(--surface); }
    .ps-row.active { border-color:var(--accent); }
    .ps-row-name { font-size: var(--fs-label); color:var(--text); flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .ps-row-meta { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); white-space:nowrap; }
    .ps-row-actions { display:flex; gap:6px; flex-shrink:0; }
    .ps-row-actions .camp-btn { font-size: var(--fs-small); padding:2px 7px; }
    /* R4: a section inside the card, not a box inside it. Hairline above, no outline. */
    .ps-builder { border:none; border-top:1px solid var(--border-subtle); border-radius:0; padding:var(--space-4) 0 0; }
    .ps-builder-title { font-size: var(--fs-label); font-weight:500; color:var(--text); }
    .ps-dirty { font-family:var(--mono); font-size: var(--fs-small); color:var(--warning); font-weight:400; margin-left:6px; }
    .ps-add { display:inline-flex; align-items:center; gap:6px; font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); }
    .ps-add select { width:auto; font-size: var(--fs-small); padding:3px 6px; }
    .ps-cards { display:flex; flex-direction:column; gap:8px; margin-top:10px; }
    .ps-card { display:flex; align-items:stretch; gap:12px; padding:8px 10px; border:1px solid var(--border-subtle); border-radius:4px; background:var(--bg-panel-raised); cursor:grab; }
    .ps-card.drop-hover { border-color:var(--aura); background:var(--accent-wash); }
    .ps-card-sketch { flex:0 0 150px; background:var(--bg-panel); border-radius:3px; padding:5px; display:flex; flex-direction:column; justify-content:center; }
    .ps-nosketch { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); text-align:center; padding:8px 0; }
    .ps-card-body { flex:1; min-width:0; display:flex; flex-direction:column; gap:6px; justify-content:center; }
    .ps-card-title { font-size: var(--fs-label); color:var(--text); }
    .ps-card-key { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); margin-left:6px; }
    .ps-repeat { font-family:var(--mono); font-size: var(--fs-small); letter-spacing:.05em; padding:1px 6px; border-radius:999px; background:rgba(255,255,255,0.10); color:var(--text-secondary); margin-left:4px; }
    .ps-card-src { display:inline-flex; align-items:center; gap:6px; font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); }
    .ps-card-src select { width:auto; font-size: var(--fs-small); padding:2px 6px; }
    .ps-card-src input[type=number] { width:58px; font-size: var(--fs-small); padding:2px 6px; }
    .ps-card-actions { display:flex; flex-direction:column; gap:4px; justify-content:center; flex-shrink:0; }
    .ps-card-actions .camp-btn { font-size: var(--fs-small); padding:1px 7px; }
    .ps-error { margin-top:var(--space-2); font-family:var(--font-ui); font-size:var(--fs-small); color:var(--red); }
    .imp-publish-to { font-size: var(--fs-label); color:var(--text-sub); }
    .imp-publish-to span { color:var(--text); font-weight:500; }
    .imp-body { padding:20px 24px; flex:1; display:flex; flex-direction:column; gap:20px; }
    .imp-drop-foot { display:flex; align-items:center; justify-content:space-between; margin-top:8px; }
    .imp-file-label { cursor:pointer; }
    .imp-file-btn { font-size: var(--fs-small); padding:4px 10px; }
    .imp-file-input { display:none; }
    .imp-stack { display:flex; flex-direction:column; gap:10px; }
    .import-mode-bar.imp-narrow { max-width:280px; }
    .imp-datetime-field { margin-top:10px; }
    .imp-input.imp-datetime { max-width:260px; }
    .import-section-label.imp-warn { margin:0; color:var(--warning); }   /* quality warnings = pending decision, amber stays */
    .imp-quality-list { display:flex; flex-direction:column; gap:6px; margin-bottom:14px; }
    .imp-quality-note { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-sub); margin-bottom:12px; }
    .import-content-textarea { width:100%; min-height:160px; max-height:260px; resize:vertical; background:transparent; border:none; color:var(--text); font-family:var(--sans); font-size: var(--fs-label); line-height:1.6; outline:none; padding:0; }
    .import-content-textarea::placeholder { color:var(--text-dim); }
    .import-preview-box { background:var(--surface); border:1px solid var(--border); border-radius:4px; padding:14px 16px; max-height:220px; overflow-y:auto; font-size: var(--fs-label); line-height:1.6; }
    .import-preview-box h2 { font-size: var(--fs-body); font-weight:500; color:var(--text); margin:12px 0 4px; }
    .import-preview-box h3 { font-size: var(--fs-label); font-weight:500; color:var(--text-sub); margin:10px 0 4px; }
    .import-preview-box p { color:var(--text-sub); margin:0 0 8px; font-size: var(--fs-label); }
    .import-preview-box h2:first-child, .import-preview-box h3:first-child { margin-top:0; }
    .import-warning-item { display:flex; align-items:center; gap:8px; padding:6px 10px; background:color-mix(in srgb, var(--warning) 8%, transparent); border:1px solid color-mix(in srgb, var(--warning) 25%, transparent); border-radius:3px; font-size: var(--fs-label); color:var(--warning); font-family:var(--mono); letter-spacing:0.04em; }
    .import-section-label { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); margin-bottom:10px; margin-top:4px; }
    .import-panel-footer { padding:16px 24px; border-top:1px solid var(--border); background:var(--bg); display:flex; gap:10px; justify-content:flex-end; position:sticky; bottom:0; }
    .imp-select { width:100%; background:var(--surface); border:1px solid var(--border); border-radius:3px; color:var(--text); font-family:var(--sans); font-size: var(--fs-label); padding:7px 10px; }
    .imp-select:focus { outline:1px solid var(--aura); box-shadow: 0 0 0 2px var(--accent-glow); }
    .imp-input { width:100%; background:var(--surface); border:1px solid var(--border); border-radius:3px; color:var(--text); font-family:var(--sans); font-size: var(--fs-label); padding:7px 10px; }
    .imp-input:focus { outline:1px solid var(--aura); box-shadow: 0 0 0 2px var(--accent-glow); }
    .imp-input::placeholder { color:var(--text-dim); }
    .cal-date { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); margin-bottom:4px; }
    .cal-date.today-num { color:var(--aura); font-weight:500; text-shadow:0 0 8px var(--accent-glow-strong); }
    /* R1: the text was a literal #000 on nine different light hues. The chip is one light brand
       surface now, so the text is the brand's carbon through a token rather than raw black. */
    .cal-page-chip { font-size: var(--fs-small); padding:2px 5px; border-radius:2px; margin-bottom:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; cursor:pointer; color:var(--brand-carbon); }
    /* Calendar chrome de-inlined (identity colors — chip background/border from
       PAGE_TYPE_COLORS/CLIENT_COLORS and the legend dot — stay inline, as does
       the per-chip status opacity the renderer computes). */
    .cal-toolbar { display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; }
    .cal-nav { display:flex; align-items:center; gap:12px; }
    .cal-month-label { font-family:var(--mono); font-size: var(--fs-label); font-weight:500; color:var(--text); min-width:140px; text-align:center; }
    .cal-legend { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }
    .cal-legend-item { display:flex; align-items:center; gap:5px; font-family:var(--mono); font-size: var(--fs-small); color:var(--text-sub); }
    .cal-legend-dot { width:8px; height:8px; border-radius:50%; flex-shrink:0; }
    .cal-push { margin-left:8px; }
    .cal-push-sm { margin-left:4px; }
    .cal-summary { margin-top:12px; font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); }
    .cal-page-chip:hover { opacity:0.8; }
    .cal-overflow { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); }
    /* Wizard steps */
    .wiz-dot { width:7px; height:7px; border-radius:50%; background:var(--border); transition:background 0.2s; }
    .wiz-dot.active { background:var(--text); }
    .wiz-dot.done { background:var(--text-tertiary); }
    /* Wizard option cards */
    .wiz-option { border:1px solid var(--border); border-radius:6px; padding:16px 18px; cursor:pointer; transition:all 0.15s; margin-bottom:10px; display:flex; align-items:flex-start; gap:14px; }
    .wiz-option:hover { border-color:var(--text-sub); }
    .wiz-option.selected { border-color:var(--text); background:var(--surface); }
    .wiz-option-icon { font-size: var(--fs-body); flex-shrink:0; margin-top:2px; font-family:var(--mono); color:var(--text-sub); width:20px; text-align:center; }
    .wiz-option-title { font-size: var(--fs-label); font-weight:500; color:var(--text); margin-bottom:3px; }
    .wiz-option-desc { font-size: var(--fs-label); color:var(--text-sub); line-height:1.5; }
    /* Campaign type cards — Step 1 */
    .wiz-type-grid { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
    .wiz-type-card { border:1px solid var(--border); border-radius:8px; padding:16px; cursor:pointer; transition:all 0.15s; position:relative; }
    .wiz-type-card:hover { border-color:var(--text-sub); background:var(--surface); }
    .wiz-type-card.selected { border-color:var(--accent); background:var(--surface); }
    .wiz-type-card-icon { font-size: var(--glyph-md); margin-bottom:8px; }
    .wiz-type-card-title { font-size: var(--fs-label); font-weight:500; color:var(--text); margin-bottom:4px; }
    .wiz-type-card-sub { font-family:var(--mono); font-size: var(--fs-small); margin-bottom:6px; }
    .wiz-type-card-desc { font-size: var(--fs-small); color:var(--text-sub); line-height:1.5; }
    .wiz-type-card-examples { margin-top:8px; display:flex; flex-wrap:wrap; gap:4px; }
    .wiz-type-card-ex { font-family:var(--mono); font-size: var(--fs-small); padding:2px 6px; border-radius:2px; background:rgba(255,255,255,0.06); color:var(--text-dim); }
    .wiz-type-card.full-width { grid-column:span 2; }
    /* Control level cards */
    .wiz-control-card { border:1px solid var(--border); border-radius:6px; padding:14px 16px; cursor:pointer; transition:all 0.15s; margin-bottom:8px; }
    .wiz-control-card:hover { border-color:var(--text-sub); }
    .wiz-control-card.selected { border-color:var(--text); background:var(--surface); }
    .wiz-control-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:6px; }
    .wiz-control-title { font-size: var(--fs-label); font-weight:500; color:var(--text); }
    .wiz-control-badge { font-family:var(--mono); font-size: var(--fs-small); padding:2px 7px; border-radius:2px; }
    .wiz-control-desc { font-size: var(--fs-label); color:var(--text-sub); line-height:1.5; }
    .wiz-checkpoints { display:flex; gap:6px; flex-wrap:wrap; margin-top:8px; }
    .wiz-checkpoint { font-family:var(--mono); font-size: var(--fs-small); letter-spacing:0.06em; padding:2px 8px; border-radius:2px; background:var(--border); color:var(--text-dim); }
    /* Campaign type badges on pipeline cards */
    .camp-type-badge { font-family:var(--mono); font-size: var(--fs-small); padding:2px 7px; border-radius:2px; flex-shrink:0; }
    .camp-type-badge.service_page { background:var(--bg-panel-raised); color:var(--text-secondary); }
    .camp-type-badge.blog_cluster { background:color-mix(in srgb, var(--positive) 12%, transparent); color:var(--positive); }
    .camp-type-badge.insurance { background:rgba(167,139,250,0.12); color:#a78bfa; }
    .camp-type-badge.location { background:color-mix(in srgb, var(--warning) 12%, transparent); color:var(--warning); }
    .camp-type-badge.cleanup { background:color-mix(in srgb, var(--negative) 12%, transparent); color:var(--negative); }
    /* Publishing accordion */
    .wiz-accordion { border:1px solid var(--border); border-radius:6px; overflow:hidden; margin-bottom:12px; }
    .wiz-accordion-header { padding:12px 16px; cursor:pointer; display:flex; align-items:center; justify-content:space-between; font-size: var(--fs-label); font-weight:500; color:var(--text-sub); }
    .wiz-accordion-header:hover { background:var(--surface); }
    .wiz-accordion-body { padding:16px; border-top:1px solid var(--border); display:none; }
    .wiz-accordion.open .wiz-accordion-body { display:block; }
    .wiz-accordion-arrow { font-size: var(--fs-small); transition:transform 0.15s; }
    .wiz-accordion.open .wiz-accordion-arrow { transform:rotate(180deg); }
    /* Focus step checklist */
    .wiz-checklist { list-style:none; padding:0; margin:0; }
    .wiz-checklist-item { display:flex; align-items:center; gap:10px; padding:8px 10px; border:1px solid var(--border); border-radius:4px; margin-bottom:6px; cursor:pointer; }
    .wiz-checklist-item:hover { background:var(--surface); }
    .wiz-checklist-item input[type=checkbox] { width:14px; height:14px; flex-shrink:0; cursor:pointer; }
    .wiz-checklist-item label { font-size: var(--fs-label); color:var(--text); cursor:pointer; flex:1; }
    .wiz-checklist-item.wiz-align-top { align-items:flex-start; }              /* multi-line rows (news topics) */
    .wiz-checklist-item.wiz-align-top > input[type=checkbox] { margin-top:3px; }
    .wiz-checklist-item .wiz-ci-meta { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); }
    /* Blog cluster toggle */
    .wiz-cluster-toggle { display:flex; align-items:center; gap:10px; padding:12px 14px; border:1px solid var(--border); border-radius:6px; cursor:pointer; margin-top:12px; }
    .wiz-cluster-toggle input { width:16px; height:16px; cursor:pointer; }
    .wiz-cluster-toggle-label { font-size: var(--fs-label); color:var(--text); }
    .wiz-cluster-toggle-sub { font-size: var(--fs-small); color:var(--text-dim); }
    /* Related campaign link on pipeline card */
    .camp-cluster-link { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-secondary); margin-top:4px; }
    /* Day picker */
    .day-picker { display:flex; gap:6px; flex-wrap:wrap; margin-top:8px; }
    .day-btn { width:36px; height:36px; border-radius:50%; padding:0; display:flex; align-items:center; justify-content:center; font-size:var(--fs-small); }
    /* Wizard form skeleton (focus + publishing steps). The steps ride the shared
       .field/.form-row/.field-hint primitives; these are the deltas that differed
       enough to keep, plus the wizard-only pieces (empty box, label row,
       select-all label, placeholder). */
    .field.wiz-tight { margin-bottom:12px; }                          /* primitive is 14px */
    .form-row.wiz-row { gap:12px; margin-bottom:12px; }              /* primitive gap is 16px */
    .form-row.wiz-row-lg { margin-bottom:16px; }
    .wiz-inline-row { display:flex; gap:8px; }
    .wiz-inline-row > input { flex:1; }
    .wiz-hint { font-size: var(--fs-small); color:var(--text-dim); margin-top:4px; }   /* prose hint; .field-hint is 9px mono */
    .wiz-label-row { display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; }
    .wiz-check-label { font-size: var(--fs-small); color:var(--text-dim); display:flex; align-items:center; gap:6px; cursor:pointer; }
    .wiz-group { margin-bottom:10px; }
    .wiz-empty { color:var(--text-dim); font-size: var(--fs-label); padding:10px 0; }
    .wiz-placeholder { color:var(--text-dim); padding:40px 0; text-align:center; }
    /* Review step + topic-plan cards + volume panel. Colors are byte-identical to
       the inline values they replace (tier blue/green, amber dedup warning, red
       danger line); only the container moved to a class. */
    .wiz-inline-row > .wiz-control-card { flex:1; }
    .wiz-control-tag { font-family:var(--mono); font-size: var(--fs-small); color:var(--text); }   /* .wiz-control-desc is 12px sans */
    .wiz-warn { background:color-mix(in srgb, var(--warning) 10%, transparent); border:1px solid color-mix(in srgb, var(--warning) 30%, transparent); border-radius:4px; padding:10px 12px; margin-bottom:12px; font-size: var(--fs-label); color:var(--text); }
    .wiz-note { background:var(--surface); border:1px solid var(--border); border-radius:4px; padding:10px 12px; margin-bottom:12px; font-size: var(--fs-label); color:var(--text-sub); }
    .wiz-note a { color:var(--text-sub); text-decoration:underline; }   /* quiet link: decoration, not status */
    .wiz-danger { color:var(--negative); font-size: var(--fs-label); }
    .wiz-summary { display:grid; grid-template-columns:1fr 1fr; gap:10px; margin-bottom:16px; }
    .wiz-summary-row { background:var(--surface); border-radius:4px; padding:10px 12px; }
    .wiz-summary-key { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); margin-bottom:3px; }
    .wiz-summary-val { font-size: var(--fs-label); font-weight:500; color:var(--text); }
    .wiz-preview { border:1px solid var(--border); border-radius:4px; padding:10px 12px; max-height:140px; overflow-y:auto; }
    .wiz-preview-item { font-size: var(--fs-small); color:var(--text-sub); padding:2px 0; }
    .wiz-mono-label { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); }
    .wiz-section-head { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); margin:12px 0 7px; }
    .wiz-section-sub { opacity:.6; text-transform:none; letter-spacing:0; }
    .wiz-tier { font-family:var(--mono); font-size: var(--fs-small); letter-spacing:.08em; padding:2px 5px; border:1px solid currentColor; }
    .wiz-tier-1 { color:var(--text-secondary); }
    .wiz-tier-2 { color:#38667E; }   /* board-ramp teal (Published stop); green is dead app-wide */
    .wiz-tier-count { font-weight:500; }
    .wiz-mini-btn { font-size: var(--fs-small); padding:2px 6px; font-family:var(--mono); letter-spacing:.06em; }
    .wiz-btn-sm { font-size: var(--fs-small); padding:3px 8px; }                                   /* .btn-sm is 12.5px / 6px 12px */
    .wiz-btn-group { display:flex; gap:6px; }
    .wiz-prio { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); }
    /* R5: a row in a list of plans, not a box per plan. Selection is the accent wash the rest
       of the app uses for a chosen control, rather than an opacity change nobody can name. */
    .wiz-plan-card { border:none; border-top:1px solid var(--border-subtle); border-radius:0; padding:var(--space-3) var(--space-2); margin-bottom:0; background:none; color:var(--text-secondary); }
    .wiz-plan-card:first-child { border-top:none; }
    .wiz-plan-card.selected { background:var(--accent-muted); color:var(--text-primary); }
    .wiz-plan-head { display:flex; gap:8px; align-items:center; }
    .wiz-plan-head > input[type=checkbox] { flex:none; }
    input[type=text].wiz-plan-title { flex:1; font-weight:500; font-size: var(--fs-label); }   /* attribute selector: outranks the global input:not()... rule */
    .wiz-plan-remove { opacity:.5; padding:2px 7px; flex:none; }
    .wiz-plan-meta { display:flex; gap:6px; align-items:center; margin-top:6px; flex-wrap:wrap; }
    .wiz-plan-type { font-size: var(--fs-small); color:var(--text-dim); }
    input[type=text].wiz-plan-kw { width:100%; margin-top:6px; font-size: var(--fs-label); }
    .wiz-plan-sub { font-size: var(--fs-small); color:var(--text-dim); margin-top:4px; }
    .wiz-plan-sub strong { color:var(--text-sub); }
    .wiz-plan-sub.wiz-plan-exists, .wiz-plan-exists a { color:var(--text); }
    .wiz-volume { border:1px solid var(--border); border-radius:6px; padding:11px 12px; margin-bottom:12px; background:var(--bg); }
    .wiz-volume-stats { display:flex; gap:16px; flex-wrap:wrap; margin-bottom:11px; font-size: var(--fs-label); }
    .wiz-volume-sel { color:var(--text-sub); }
    .wiz-volume-sel strong { color:var(--text); }
    .wiz-volume-sel span { color:var(--text-dim); }
    .wiz-volume-excl { color:var(--text); }
    .wiz-volume-controls { display:flex; gap:10px; flex-wrap:wrap; align-items:flex-end; }
    .wiz-volume-field { display:flex; flex-direction:column; gap:3px; }
    .wiz-volume-field.wiz-grow { flex:1; min-width:160px; }
    .wiz-volume-field > label { font-size: var(--fs-small); color:var(--text-dim); }
    .wiz-volume-field > input[type=number], .wiz-volume-field > select { font-size: var(--fs-label); }
    .wiz-volume-field > input[type=number] { width:76px; }   /* must outrank the global input:not()... width:100% */
    .wiz-volume-note { font-size: var(--fs-small); color:var(--text-dim); margin-top:9px; }
    .wiz-volume-note.wiz-volume-alert { color:var(--text); margin-top:8px; border-top:1px solid var(--border); padding-top:8px; }
    /* Camp empty */
    .camp-empty { padding:60px 0; text-align:center; color:var(--text-dim); }
    .camp-empty-icon { font-size: var(--glyph-lg); margin-bottom:16px; }
    .camp-empty-title { font-family:var(--mono); font-size: var(--fs-small); margin-bottom:8px; }
    .camp-empty-desc { font-size: var(--fs-label); color:var(--text-sub); }

    /* ── CAMPAIGN DETAIL VIEW ── */
    #camp-detail-overlay { display:none; position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.75); z-index:3000; align-items:flex-start; justify-content:flex-end; }
    #camp-detail-overlay.open { display:flex; }
    #camp-detail-panel { width:520px; height:100%; background:var(--bg); border-left:1px solid var(--border); overflow-y:auto; display:flex; flex-direction:column; }
    .camp-detail-header { padding:20px 24px; border-bottom:1px solid var(--border); position:sticky; top:0; background:var(--bg); z-index:1; display:flex; align-items:center; justify-content:space-between; }
    .camp-kw-row { display:flex; align-items:center; gap:10px; padding:10px 0; border-bottom:1px solid rgba(255,255,255,0.04); }
    .camp-kw-row:last-child { border-bottom:none; }
    .camp-kw-status { font-family:var(--mono); font-size: var(--fs-small); padding:2px 7px; border-radius:2px; flex-shrink:0; }
    .camp-kw-status.planned { background:var(--surface); color:var(--text-dim); }
    .camp-kw-status.written { background:color-mix(in srgb, var(--positive) 10%, transparent); color:var(--positive); }
    .camp-kw-status.error { background:color-mix(in srgb, var(--negative) 10%, transparent); color:var(--negative); }
    .camp-kw-status.running { background:color-mix(in srgb, var(--warning) 10%, transparent); color:var(--warning); }
    .camp-kw-text { flex:1; font-size: var(--fs-label); color:var(--text); min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .camp-kw-score { font-family:var(--mono); font-size: var(--fs-small); font-weight:500; flex-shrink:0; min-width:32px; text-align:right; }
    /* Health score */
    .camp-health { width:40px; height:40px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-family:var(--mono); font-size: var(--fs-label); font-weight:500; flex-shrink:0; }
    /* Campaign detail drawer (a right-side drawer, not the centered modal
       primitive) + Tracking rows, de-inlined. The overlay's display and the
       tracked bulk bar's display are still written by JS; badge color comes
       from the per-status map in trackedStatusBadge. */
    .camp-drawer-overlay { position:fixed; top:0; left:0; right:0; bottom:0; background:rgba(0,0,0,0.6); z-index:3000; align-items:flex-start; justify-content:flex-end; }
    .camp-drawer { width:520px; height:100%; background:var(--bg); border-left:1px solid var(--border); overflow-y:auto; display:flex; flex-direction:column; }
    .camp-drawer-body { padding:20px 24px; flex:1; }
    .camp-btn.camp-btn-xs { font-size: var(--fs-small); padding:2px 7px; }
    .camp-detail-stats { display:flex; gap:16px; margin-bottom:16px; flex-wrap:wrap; }
    .camp-stat-val.danger { color:var(--red); }
    .camp-detail-progress { margin-bottom:20px; }
    .camp-detail-progress .ui-progress { width:100%; }
    .camp-detail-heading { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); margin-bottom:10px; }
    .camp-kw-delta { flex-shrink:0; }
    .camp-kw-score.dim { color:var(--text-dim); }
    .camp-kw-doc { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); text-decoration:none; letter-spacing:0.06em; flex-shrink:0; }
    .camp-kw-done { font-family:var(--mono); font-size: var(--fs-small); color:var(--text); }
    .tracked-bulk-bar { align-items:center; gap:10px; flex-wrap:wrap; background:var(--bg-panel-raised); border:1px solid var(--border-strong); border-radius:var(--radius-control); padding:8px 12px; margin-bottom:10px; }   /* neutral, like .pub-bulk-bar: selection is not a warning */
    .tracked-bulk-label { font-family:var(--mono); font-size: var(--fs-small); color:var(--text); }
    .tracked-bulk-items { gap:8px; }
    /* R3: the same row pattern on the tracked-records list, flattened the same way. This one is
       an accordion, so the hairline also marks where one record's head and body end and the
       next record begins, which the box used to do. */
    .tracked-rec { border:none; border-top:1px solid var(--border-subtle); border-radius:0; margin-bottom:0; background:none; }
    .tracked-rec:first-child { border-top:none; }
    .tracked-rec-head { display:flex; align-items:center; gap:12px; padding:var(--space-3) 0; cursor:pointer; }
    .tracked-caret { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); width:10px; }
    .tracked-name { font-size: var(--fs-label); color:var(--text); font-weight:500; flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .tracked-type { font-family:var(--mono); font-size: var(--fs-small); color:var(--accent,#7dd3fc); border:1px solid var(--border); border-radius:2px; padding:1px 6px; }
    .tracked-meta { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); white-space:nowrap; }
    .tracked-items { padding:4px 0 8px 14px; }
    .tracked-none { font-size: var(--fs-small); color:var(--text-dim); padding:6px 0; }
    .tracked-item { display:flex; align-items:center; gap:10px; padding:6px 0; border-top:1px solid var(--border); }
    .tracked-marker { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); width:40px; flex-shrink:0; }
    .tracked-title { font-size: var(--fs-label); color:var(--text); flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
    .tracked-badge { font-family:var(--mono); font-size: var(--fs-small); border:1px solid currentColor; border-radius:2px; padding:1px 6px; white-space:nowrap; }
    .tracked-link { font-family:var(--mono); font-size: var(--fs-small); color:var(--accent,#7dd3fc); text-decoration:none; white-space:nowrap; }
    .tracked-btn { padding:var(--space-1) var(--space-2); font-size:var(--fs-small); }
    /* Sidebar collapse: the rail itself is specified in ONE block near the brand lockup (search
       "Collapsed rail"). Only the grid column lives here, next to the app shell it belongs to. */
    .app:has(.sidebar-collapsed) { grid-template-columns: 44px 1fr; }
    /* Keyboard shortcut hints */
    .kbd { display:inline-block; font-family:var(--mono); font-size: var(--fs-small); padding:1px 4px; border:1px solid var(--border); border-radius:2px; color:var(--text-dim); }
    /* Undo toast */
    .toast-undo { display:inline-flex; align-items:center; gap:8px; }
    /* Theme toggle */
    /* Light mode */

    /* Keyword expansion loading */
    .kw-expand-loading { font-family:var(--mono); font-size: var(--fs-small); color:var(--warning); letter-spacing:0.08em; }

    /* ── INTELLIGENCE ── */    /* ── INTELLIGENCE ── */
    .intel-stat-block { display:flex; flex-direction:column; gap:4px; }
    .intel-stat-num { font-size: var(--fs-title); font-weight:500; letter-spacing:-0.04em; line-height:1; color:var(--text); }
    .intel-stat-label { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); }
    /* Tree explorer */
    #intel-tree-explorer { width:100%; }
    .itree-folder-row {
      display:flex; align-items:center; gap:0;
      padding:0;
      border-bottom:1px solid var(--border);
      cursor:pointer;
      transition:background 0.1s;
      user-select:none;
    }
    .itree-folder-row:hover { background:var(--surface); }
    .itree-folder-row.open { background:var(--surface); }
    .itree-toggle {
      width:36px; height:40px; flex-shrink:0;
      display:flex; align-items:center; justify-content:center;
      font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim);
      transition:transform 0.15s;
    }
    .itree-folder-row.open .itree-toggle { color:var(--text); }
    .itree-folder-name {
      flex:1; font-family:var(--mono); font-size: var(--fs-label); font-weight:500;
      color:var(--text); padding:10px 0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
    }
    .itree-folder-meta {
      font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim);
      padding:0 16px; white-space:nowrap; flex-shrink:0;
    }
    .itree-folder-score {
      font-family:var(--mono); font-size: var(--fs-label); font-weight:500;
      padding:0 16px 0 0; flex-shrink:0; min-width:40px; text-align:right;
    }
    .itree-status-bar {
      width:60px; height:3px; background:var(--border); border-radius:2px; flex-shrink:0; margin-right:16px; overflow:hidden;
    }
    .itree-status-fill { height:100%; border-radius:2px; }
    /* Children container */
    .itree-children {
      display:none;
      border-bottom:1px solid var(--border);
      background:var(--bg);
    }
    .itree-children.open { display:block; }
    /* Sub-folder rows */
    .itree-subfolder-row {
      display:flex; align-items:center;
      padding:0 0 0 36px;
      border-bottom:1px solid rgba(255,255,255,0.04);
      cursor:pointer;
      transition:background 0.1s;
    }
    .itree-subfolder-row:last-child { border-bottom:none; }
    .itree-subfolder-row:hover { background:var(--surface); }
    .itree-subfolder-row.open { background:var(--surface); }
    .itree-sub-toggle { width:28px; height:36px; display:flex; align-items:center; justify-content:center; font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); flex-shrink:0; }
    .itree-sub-name { flex:1; font-family:var(--mono); font-size: var(--fs-small); color:var(--text-sub); padding:8px 0; }
    .itree-subfolder-row:hover .itree-sub-name { color:var(--text); }
    .itree-sub-meta { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); padding:0 16px; white-space:nowrap; }
    .itree-sub-score { font-family:var(--mono); font-size: var(--fs-label); font-weight:500; padding:0 16px 0 0; min-width:36px; text-align:right; }
    /* Sub-children */
    .itree-sub-children { display:none; }
    .itree-sub-children.open { display:block; }
    /* Page rows */
    .itree-page-row {
      display:flex; align-items:center; gap:8px;
      padding:9px 12px 9px 48px;
      border-bottom:1px solid rgba(255,255,255,0.03);
      cursor:pointer;
      transition:background 0.1s;
      position:relative;
      min-width:0;
    }
    .itree-page-row:hover { background:var(--surface); }
    .itree-page-row:hover .itree-page-actions { opacity:1; }
    .itree-page-status { width:6px; height:6px; border-radius:50%; flex-shrink:0; }
    .itree-page-title { flex:1; font-size: var(--fs-label); color:var(--text); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0; }
    .itree-page-words { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); flex-shrink:0; min-width:40px; text-align:right; }
    .itree-page-score { font-family:var(--mono); font-size: var(--fs-label); font-weight:500; flex-shrink:0; min-width:30px; text-align:right; }
    .itree-page-actions { opacity:0; display:flex; gap:6px; flex-shrink:0; transition:opacity 0.15s; }
    .itree-page-btn { padding:var(--space-1) var(--space-2); font-size:var(--fs-small); }
    .itree-page-btn.rw { border-color:var(--warning); color:var(--warning); }
    .itree-page-btn.rw:hover { background:var(--warning); color:var(--bg); }
    /* Deeper indent for 3rd level pages */
    .itree-page-row.depth-3 { padding-left:72px; }
    .itree-page-row.depth-4 { padding-left:96px; }
    @keyframes treeIn { from { opacity:0; } to { opacity:1; } }
    #intel-tree-explorer { animation:treeIn 0.2s ease; }

    /* ── SETTINGS ── */    /* ── SETTINGS ── */
    .settings-integration-list {
      display: flex;
      flex-direction: column;
      border-top: 1px solid var(--border);
    }

    .settings-integration {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: var(--space-4) 0;
      border-bottom: 1px solid var(--border-subtle);
    }
    .settings-integration:last-child { border-bottom: none; }

    .settings-int-name { font-size: var(--fs-body); font-weight: 500; margin-bottom: 3px; }

    .settings-int-desc {
      font-family: var(--font-ui);
      font-size: var(--fs-small);
      letter-spacing: 0;
      color: var(--text-tertiary);
    }

    .settings-int-status { font-family: var(--font-ui); font-size: var(--fs-small); font-weight: 500; padding: 3px 10px; border-radius: var(--radius-pill); flex-shrink: 0; }

    .settings-int-status.connected { color: var(--status-positive); background: var(--status-positive-muted); }
    .settings-int-status.pending   { color: var(--text-dim); border: 1px solid var(--border-heavy); }

    /* ── PERFORMANCE PANELS ── */
    .perf-empty {
      padding: 80px 0;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 12px;
      border-bottom: 1px solid var(--border);
    }

    .perf-empty-title {
      font-size: var(--fs-heading);
      font-weight:500;
      letter-spacing: -0.02em;
    }

    .perf-empty-desc {
      font-size: var(--fs-label);
      color: var(--text-sub);
      font-weight:400;
      max-width: 420px;
      line-height: 1.6;
    }

    .perf-req {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-dim);
      margin-top: 4px;
    }

    /* ── CLIENTS ── */
    .clients-list {
      border-top: 2px solid var(--text);
    }

    .client-row {
      display: grid;
      grid-template-columns: 1fr 90px 90px minmax(230px, auto);
      gap: 20px;
      padding: 16px 0;
      border-bottom: 1px solid var(--border);
      align-items: center;
    }

    .client-row-header {
      display: grid;
      grid-template-columns: 1fr 90px 90px minmax(230px, auto);
      gap: 20px;
      padding: 12px 0;
      border-bottom: 2px solid var(--text);
    }
    .client-row-header span:nth-child(2), .client-row-header span:nth-child(3) { text-align: right; }

    .client-row-header span {
      font-family: var(--mono);
      font-size: var(--fs-small);
      font-weight:500;
      color: var(--text-dim);
    }

    .client-name { font-size: var(--fs-body); font-weight:500; }
    .client-url  {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-dim);
      margin-top: 3px;
    }

    .client-stat {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-sub);
    }

    .client-status {
      font-family: var(--mono);
      font-size: var(--fs-small);
      font-weight:500;
      padding: 3px 8px;
      border: 1px solid;
    }

    .client-status.active { color: var(--green); border-color: var(--green); }
    .client-status.paused { color: var(--text-dim); border-color: var(--border-heavy); }

    /* ── EMPTY / TOAST / ANIMATIONS ── */
    .empty-state {
      padding: 80px 0;
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-dim);
      text-align: center;
    }

    .toast {
      position: fixed;
      bottom: 32px;
      left: 50%;
      transform: translateX(-50%) translateY(6px);
      background: var(--bg-panel-raised);
      color: var(--text-primary);
      border: 1px solid var(--border-strong);
      border-radius: var(--radius-control);
      padding: 10px 18px;
      font-family: var(--font-ui);
      font-size: var(--text-sm);
      opacity: 0;
      pointer-events: none;
      transition: all 0.2s;
      z-index: 9700;
    }

    .toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
    .toast.error   { background: var(--red); }
    .toast.success { background: var(--green); }

    /* ── STEP ELAPSED TIME ── */
    .step-elapsed {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--amber);
      text-align: center;
      min-height: 10px;
      display: block;
    }
    .progress-step:not(.active) .step-elapsed { display: none; }

    /* ── HISTORY FILTERS ── */
    .history-filters {
      display: flex;
      gap: 12px;
      align-items: center;
      padding: 20px 0 16px;
      border-bottom: 1px solid var(--border);
      flex-wrap: wrap;
    }
    .filter-select {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-sub);
      border: 1px solid var(--border-heavy);
      padding: 5px 20px 5px 8px;
      background: transparent;
      border-bottom: 1px solid var(--border-heavy);
      cursor: pointer;
    }

    /* ── ERROR CARD ── */
    .error-card {
      border: 1px solid var(--negative);
      border-radius: var(--radius-control);
      padding: var(--space-4) var(--space-5);
      margin-top: var(--space-4);
      background: var(--negative-muted);
      color: var(--text-primary);
    }
    .error-card-title {
      font-family: var(--mono);
      font-size: var(--fs-small);
      font-weight:500;
      color: var(--red);
      margin-bottom: 8px;
    }
    .error-card-msg {
      font-size: var(--fs-label);
      color: var(--text);
      line-height: 1.5;
      margin-bottom: 12px;
      font-weight:400;
    }

    /* ── SCORE COLORS IN HISTORY ── */
    .score-pill {
      font-family: var(--mono);
      font-size: var(--fs-small);
      font-weight: 500;
      letter-spacing: 0.08em;
      padding: 3px 8px;
      color: var(--text-primary);
      background: var(--accent-muted);   /* a score is a number; the gate marker is the aura, on the gauge */
      border: 1px solid rgba(255,255,255,0.10);
      cursor: pointer;
      transition: all 0.1s;
    }
    .score-pill:hover { opacity: 0.7; }

  /* ── WORD COUNT ESTIMATOR ── */
    .word-count-hint {
      font-family: var(--mono);
      font-size: var(--fs-small);
      color: var(--text-dim);
      letter-spacing: 0.08em;
      margin-top: 6px;
      transition: color 0.2s;
    }
    .word-count-hint.ready { color: var(--text-primary); } /* neutral flash — same timing, color ruling: no green */

    /* ── CLIENT SWITCHER IN HEADER ── */
    /* ══ R2: THE ORG SWITCHER, FOR A BLACK SIDEBAR ══════════════════════════════════════
       It read as a pale chip stuck on the black: a lit border, an 8px all-caps label and a 10px
       name at weight 700 with wide tracking, none of which is in the type scale. It is a quiet
       control now, the same white wash the active nav item uses, with the label at the label
       size and the name at the body size. Hover lifts the wash rather than lighting the edge. */
    .client-switcher { display: flex; align-items: center; gap: var(--space-2); border: 1px solid transparent; border-radius: var(--radius-control); padding: var(--space-2) var(--space-3); cursor: pointer; background: rgba(255,255,255,.04); transition: background 0.12s; position: relative; width: 100%; text-align: left; }
    .client-switcher:hover { background: rgba(255,255,255,.08); }
    .client-switcher-label {
      font-family: var(--font-ui);
      font-size: var(--fs-small);
      font-weight: 500;
      color: var(--nav-sub, var(--text-tertiary));
    }
    /* ⚠ R6: IT TRUNCATES NOW, BECAUSE MONOSPACE MADE IT WRAP TO THREE LINES.
       A long client name used to fit on one line in a proportional font. In Plex Mono the same
       name is about a tenth wider, and with nothing stopping it the picker grew downwards and
       pushed the whole top bar taller. One line, ellipsis, and the full name is in the control's
       title, the same arrangement the site host beneath it already used. */
    .client-switcher-name {
      font-family: var(--font-ui);
      font-size: var(--fs-body);
      font-weight: 500;
      letter-spacing: -0.01em;
      color: var(--nav-text, var(--text));
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
      max-width: 220px;
    }
    /* The sidebar's org switcher uses the same class in a 180px rail, so it caps tighter. */
    .sidebar .client-switcher-name { max-width: 128px; }
    /* R4: the site host, moved here from the Active Client card. Hidden when there is none, so
       a client without a site leaves no empty line under its name. */
    .client-switcher-site {
      font-family: var(--font-ui);
      font-size: var(--fs-small);
      color: var(--nav-sub, var(--text-tertiary));
      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
      max-width: 180px;
    }
    .client-switcher-site:empty { display: none; }
    .client-switcher-arrow { color: var(--nav-sub, var(--text-tertiary)); font-size: var(--fs-small); margin-left: auto; }
    .client-dropdown {
      position: absolute;
      top: calc(100% + 4px);
      right: 0;
      background: var(--bg);
      border: 1px solid var(--border-heavy);
      box-shadow: 0 4px 16px rgba(0,0,0,0.08);
      z-index: 50;
      min-width: 180px;
      display: none;
    }
    .client-dropdown.open { display: block; }
    .client-dropdown-item {
      display: block;
      width: 100%;
      padding: 10px 16px;
      font-family: var(--font-ui);
      font-size: var(--fs-label);
      text-align: left;
      background: none;
      border: none;
      cursor: pointer;
      color: var(--text-sub);
      transition: background 0.1s;
    }
    .client-dropdown-item:hover { background: var(--surface); color: var(--text); }
    .client-dropdown-item.active { color: var(--text); font-weight: 500; }
    /* Org switcher (sidebar, under the brand lockup): the client-switcher pattern, opening
       from the left edge since it sits in the rail. Hidden with the rest of the lockup when
       the sidebar is collapsed. */
    .org-switcher-wrap { position: relative; }
    /* The sidebar clips overflow, so the dropdown leaves the flow: fixed, positioned by
       toggleOrgDropdown from the button's rect (top/left are set inline at open), above
       the main header (z 500). */
    #org-dropdown { position: fixed; width: 260px; right: auto; z-index: 600; }
    .org-dd-role { font-family: var(--font-ui); font-size: var(--fs-small); color: var(--text-tertiary); margin-left: 8px; }
    /* Join by code: a separated last item in the org dropdown, with an inline code field. */
    .org-dd-sep { border-top: 1px solid var(--border-subtle); margin: 4px 0; }
    /* The required-choice state: several memberships and nothing chosen yet. The prompt reuses the
       existing switcher rather than adding a second surface; these three rules are all it needs. */
    .org-dd-note { font-family: var(--font-ui); font-size: var(--fs-small); line-height: 1.5; color: var(--text-secondary);
                   padding: 8px 10px; border-bottom: 1px solid var(--border-subtle); margin-bottom: 4px; }
    #org-switcher-btn.org-required { border-color: var(--text-secondary); }
    /* Nothing org-scoped may render behind the prompt: a screen built from another org's data is
       the failure this state exists to prevent. The switcher itself stays visible and usable. */
    body.org-unchosen .panel:not(#panel-settings) { display: none !important; }
    body.org-unchosen #org-dropdown { display: block; }
    .org-join { padding: 6px 12px 10px; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
    .org-join input { width: 120px; font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: 0.08em; text-transform: uppercase; padding: 5px 8px; }
    .org-join input::placeholder { text-transform: none; letter-spacing: normal; }
    #org-create-name { width: 170px; text-transform: none; letter-spacing: normal; }
    .org-join-err { flex-basis: 100%; font-family: var(--font-mono); font-size: var(--fs-small); color: var(--red); min-height: 12px; }
    /* Settings → Organization */
    .org-set-name { font-size: var(--fs-body); font-weight: 500; color: var(--text-primary); padding: var(--space-1) 0; }
    .org-code-row { display: flex; gap: var(--space-2); align-items: center; }
    .org-code { width: 150px; font-family: var(--font-mono); font-size: var(--fs-body); letter-spacing: 0.12em; }
    /* Settings → Organization → Members: the bordered row-card idiom; a disabled control
       carries its reason in the title. */
    .org-members { display: flex; flex-direction: column; gap: 0; }
    .org-mem-head, .org-mem-row { display: grid; grid-template-columns: 32px minmax(0,1.4fr) minmax(70px,110px) minmax(80px,130px) minmax(90px,180px); gap: var(--space-2); align-items: center; }
    .org-mem-head.with-email, .org-mem-row.with-email { grid-template-columns: 32px minmax(0,1.2fr) minmax(0,1.4fr) minmax(70px,110px) minmax(80px,130px) minmax(90px,180px); }
    /* Below the width where six columns can hold a name, an email, a role, a date and a pair of
       buttons, the date and the email go: neither is why anybody opens this table. */
    @media (max-width: 1180px) {
      .org-mem-head.with-email, .org-mem-row.with-email { grid-template-columns: 32px minmax(0,1.4fr) minmax(70px,110px) minmax(90px,180px); }
      .org-mem-head.with-email > :nth-child(3), .org-mem-row.with-email > :nth-child(3),
      .org-mem-head.with-email > :nth-child(5), .org-mem-row.with-email > :nth-child(5) { display: none; }
      .org-mem-head > :nth-child(4), .org-mem-row > :nth-child(4) { display: none; }
      .org-mem-head, .org-mem-row { grid-template-columns: 32px minmax(0,1.4fr) minmax(70px,110px) minmax(90px,180px); }
    }
    .org-mem-head { font-family: var(--font-ui); font-size: var(--fs-small); color: var(--text-secondary); padding: 0 0 var(--space-2); }
    /* R4: flat, like every other row in the app since R3. It drew its own background, border
       and 11px radius inside the Settings card, which is a box inside a box. */
    .org-mem-row { background: none; border: none; border-top: 1px solid var(--border-subtle); border-radius: 0; padding: var(--space-3) 0; min-height: var(--row-h); }
    .org-mem-row:first-child { border-top: none; }
    .org-mem-avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--accent-muted) center/cover no-repeat; color: var(--text-primary); display: inline-flex; align-items: center; justify-content: center; font-size: var(--fs-label); font-weight: 500; }
    .org-mem-name { font-size: var(--fs-body); color: var(--text-primary); }
    .org-mem-you { font-family: var(--font-ui); font-size: var(--fs-small); color: var(--text-tertiary); margin-left: 6px; }
    .org-mem-email, .org-mem-joined { font-family: var(--font-ui); font-size: var(--fs-small); color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .org-mem-role { width: auto; font-size: var(--fs-small); padding: 3px 6px; }
    .org-mem-actions { text-align: right; }
    /* Disabled reads as disabled: tertiary text, subtle border, no red, not-allowed. The reason rides on the title. */
    .org-mem-row select:disabled, .org-mem-row button:disabled, .org-mem-row .btn-sm.pub-danger:disabled { opacity: 1; color: var(--text-tertiary); border-color: var(--border-subtle); background: transparent; cursor: not-allowed; }
    .org-mem-row .btn-sm.pub-danger:disabled:hover, .org-mem-row button:disabled:hover { background: transparent; color: var(--text-tertiary); }
    .org-danger { margin-top: var(--space-6); padding-top: var(--space-4); }
    /* An organization with no clients: each org-scoped panel shows only its banner. */
    .noclients { display: none; margin: 40px auto; max-width: 520px; }
    body.no-clients .noclients { display: block; }
    body.no-clients #panel-produce > :not(.noclients), body.no-clients #panel-history > :not(.noclients), body.no-clients #panel-quality > :not(.noclients),
    /* !important: the Intelligence topbar (and any other panel child) may carry an inline display, which
       otherwise beats this rule and leaves the toolbar rendered under the banner. */
    body.no-clients #panel-feed > :not(.noclients), body.no-clients #panel-write > :not(.noclients), body.no-clients #panel-intelligence > :not(.noclients) { display: none !important; }
    #org-del-confirm { max-width: 260px; }

    /* ⚠ R4: THE SIDEBAR'S ACTIVE CLIENT CARD IS GONE, AND SO ARE ITS RULES.
       .sidebar-client-block, -label, -name, -name.is-none, -site and -site-label used to live
       here. The card named the client the top bar's picker already names and had no action, so
       it was the shell's second readout of one value. Leaving dead rules behind is how a class
       comes back by accident, so they are removed rather than commented out. The site line it
       carried is .client-switcher-site above. */

    /* ── SCROLLBAR POLISH ── */
    ::-webkit-scrollbar { width:5px; height:5px; }
    ::-webkit-scrollbar-track { background:transparent; }
    ::-webkit-scrollbar-thumb { background:var(--border); border-radius:3px; }
    ::-webkit-scrollbar-thumb:hover { background:var(--text-dim); }
    /* R4: the one remaining 13px on a form control, on the scale with the rest. */
    input, select, textarea { font-size: var(--fs-body); }

    /* ── HISTORY TABLE ── */
    .history-table { width:100%; border-collapse:collapse; font-size: var(--fs-label); }
    .history-table th { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); padding:8px 12px; border-bottom:1px solid var(--border); text-align:left; cursor:pointer; user-select:none; white-space:nowrap; }
    .history-table th:hover { color:var(--text); }
    .history-table td { height:var(--row-h); padding:6px 12px; border-bottom:1px solid var(--border-subtle); vertical-align:middle; }
    .history-table tbody tr:hover td { background:var(--bg-panel-raised); }
    .history-table tr:last-child td { border-bottom:none; }
    .history-table tr:hover td { background:var(--surface); }
    .history-table .hist-kw { font-size: var(--fs-label); color:var(--text); max-width:260px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; cursor:pointer; }
    .history-table .hist-kw:hover { color:var(--warning); }
    .history-table .hist-score { font-family:var(--mono); font-size: var(--fs-small); font-weight:500; }
    .history-table .hist-error { font-size: var(--fs-small); color:var(--negative); }

    /* ── FEED TIMELINE ── */
    .feed-timeline { padding:8px 0; }
    .feed-event-row { display:flex; gap:10px; align-items:flex-start; padding:6px 0; border-left:2px solid var(--border); margin-left:8px; padding-left:12px; margin-bottom:2px; }
    .feed-event-row.complete { border-left-color:var(--positive); }
    .feed-event-row.error { border-left-color:var(--negative); }
    .feed-event-row.published { border-left-color:var(--border-strong); }
    .feed-event-row.running { border-left-color:var(--warning); }
    .feed-ev-title { font-size: var(--fs-label); color:var(--text); }
    .feed-ev-meta { font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); margin-top:2px; }

    /* ══ TERMINAL TYPE ROLES (spec §2) ═══════════════════════════════════════
       UI text = --font-ui, which R3 put back to the system stack. Mono stays for: numerals/stat
       figures, costs, IDs, URLs,
       badges/pills, timestamps/meta rows, and the small letterspaced uppercase
       section labels (the one deliberate terminal flourish). This block flips
       the broad UI surfaces the old mono-everywhere styling covered; it sits
       LAST so it wins the cascade at equal specificity. */
    .nav-item, .nav-sub-item, .nav-child-item,
    .btn, .btn-sm, .camp-btn, .btn-retry, .toast,
    .camp-view-btn, .filter-btn, .filter-select,
    .import-mode-btn, .optimizer-toggle-btn, .score-toggle-btn, .copy-btn, .day-btn,
    .itree-page-btn, .produce-action-title, .main-subtitle, .camp-empty-title,
    .client-dropdown-item, .client-switcher-name, .wiz-type-card-sub, .wiz-type-card-ex,
    .field-hint, .doc-link, .itree-folder-name, .itree-sub-name, .empty-state,
    .feed-stream, .gen-mode-card .gm-desc {
      font-family: var(--font-ui);
    }
    /* Panel/page titles: the UI font, at the weight the type scale gives them. */
    h1, h2, h3, .section-title { font-family: var(--font-ui); }


/* ── (moved from a late inline style block) ── */

    #kb-dropzone.dragover { border-color: var(--accent); background: var(--surface); color: var(--text); }
    .kb-file-row { display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 10px;border:1px solid var(--border);border-radius:4px;margin-bottom:6px; }
    .kb-file-row .kb-fname { font-family:var(--mono);font-size: var(--fs-label);color:var(--text);word-break:break-all; }
    .kb-file-row .kb-fmeta { font-size: var(--fs-small);color:var(--text-dim); }
  
/* ═══════════════════════════════════════════════════════════════════════════
   SHARED UI COMPONENTS (Pass 2 — rendered by public/ui.js; spec §3-4)
   ═══════════════════════════════════════════════════════════════════════════ */
.ui-grid { display:grid; grid-template-columns:repeat(12,1fr); column-gap:var(--gap-grid); row-gap:var(--gap-grid-row); align-items:start; }
.ui-col-2{grid-column:span 2}.ui-col-3{grid-column:span 3}.ui-col-4{grid-column:span 4}
.ui-col-5{grid-column:span 5}.ui-col-6{grid-column:span 6}.ui-col-7{grid-column:span 7}
.ui-col-8{grid-column:span 8}.ui-col-9{grid-column:span 9}.ui-col-12{grid-column:span 12}
@media (max-width:1100px){ .ui-col-4,.ui-col-8,.ui-col-6,.ui-col-3,.ui-col-9{grid-column:span 12} }
/* The Produce dashboard's actionable pair: Waiting on you beside Work on next.
   FLEX, not two grid columns, and the reason is visibility. Both cards are conditional, so
   whenever only one is on screen a grid track would still be reserved for the other and the
   survivor would sit next to dead space. A display:none flex child is out of flow, so the
   survivor grows to the full width on its own. 5 and 7 are kept as flex GROWTH ratios, so the
   proportions are unchanged from the grid version while both are visible.
   min-width:0 because flex items default to min-width:auto and a wide table inside a panel
   would otherwise refuse to shrink and push the row past the grid. */
.produce-pair { display:flex; gap:var(--gap-grid); align-items:flex-start; }
.produce-pair > .ui-panel { min-width:0; }
.produce-pair > #produce-waiting-card { flex:5 1 0; }
.produce-pair > #produce-next-card    { flex:7 1 0; }
/* NO narrow-width stacking rule here, deliberately. The 1100px collapse above lists 4, 8, 6, 3
   and 9 and pointedly omits 5 and 7, so NO 5/7 pair on this dashboard stacks - Active jobs
   beside Quality snapshot is the other one, and it stays side by side all the way down. This
   pair now behaves identically. Measured at a 1040px viewport: 296px beside 414px, no dead
   space and no horizontal scroll. Whether 5/7 pairs SHOULD collapse is a separate call that
   belongs on the rule above, where it would apply to both pairs at once rather than to this
   one by hand. A first attempt here was also silently dead: .produce-pair > .ui-panel loses
   to the #id rules below on specificity, and the flex shorthand resets flex-basis anyway. */

/* R2: ONE CARD. The inset top highlight is gone: it was a lit edge on every panel, which is the
   "glow" half of what made these read as old. Surface, hairline, radius, nothing else. */
.ui-panel { background:var(--bg-panel); border:var(--card-border); border-radius:var(--card-radius); min-width:0; }
.ui-panel-head { display:flex; align-items:center; justify-content:space-between; gap:var(--space-3); padding:var(--space-4) var(--space-5) var(--space-3); }
.ui-panel-body { padding:0 0 8px; }
.ui-panel-body.inset { padding:0 18px 18px; }
.ui-panel-title { font-family:var(--font-ui); font-size:var(--fs-heading); font-weight:500; letter-spacing:-0.015em; color:var(--text-primary); }
.ui-panel-actions { display:flex; align-items:center; gap:8px; }

.ui-stat-card { background:var(--bg-panel); border:var(--card-border); border-radius:var(--card-radius); padding:var(--space-4) var(--space-5) var(--space-3); min-height:96px; display:flex; flex-direction:column; min-width:0; }
.ui-stat-label { font-family:var(--font-ui); font-size:var(--fs-label); font-weight:500; color:var(--text-secondary); margin-bottom:var(--space-2); }
.ui-stat-row { display:flex; align-items:baseline; gap:8px; }
.ui-stat-num { font-family:var(--font-ui); font-size:var(--fs-stat); font-weight:800; letter-spacing:-0.02em; color:var(--text-primary); line-height:1; }
.ui-stat-num.negative { color:var(--text-secondary); }   /* position 31+: data, neutral by ruling */
.ui-stat-delta { font-family:var(--font-mono); font-size:var(--text-xs); font-weight:500; }
.ui-stat-delta.up { color:var(--status-positive); } .ui-stat-delta.down { color:var(--text-secondary); }   /* a decline is data, neutral by ruling */
.ui-spark { width:100%; height:34px; margin-top:auto; display:block; }

.ui-pill { display:inline-block; font-family:var(--font-ui); font-size:var(--text-xs); font-weight:500; padding:3px 10px; border-radius:var(--radius-pill); white-space:nowrap; line-height:1.4; }
.ui-pill.positive { background:var(--status-positive-muted); color:var(--status-positive); }
.ui-pill.negative { background:rgba(255,255,255,0.10);      color:var(--text-secondary); }   /* data pills (failed checks, readability): neutral by ruling */
/* Real red via --red (the week strip's .pw-chip.pw-missed token) — .negative is
   aliased to --status-negative = var(--text) and would render white. */
.ui-pill.danger   { background:color-mix(in srgb, var(--negative) 10%, transparent);         color:var(--negative); }
/* No live producer (degraded/warning are unmapped statuses); pointed at real amber so it stops lying if one appears. */
.ui-pill.warning  { background:var(--accent-muted);           color:var(--text-secondary); }   /* a count or a caution about data: tonal */
/* GSC position pill (Intelligence Data tables): one neutral pill in every band. Position
   is a data value, not a status. Replaces the undefined .pos-win / .pos-gap variants. */
.pos-badge { display:inline-block; font-family:var(--font-mono); font-size: var(--fs-small); padding:2px 8px; border-radius:var(--radius-pill); background:rgba(255,255,255,0.10); color:var(--text-secondary); white-space:nowrap; }
/* Tree columns that read crawl-score fields (score, words, thin/needs_work/good status);
   renderIntelTree sets this class when no page carries a score (real crawls). */
#intel-tree-explorer.no-crawl-scores .itree-page-status,
#intel-tree-explorer.no-crawl-scores .itree-page-words,
#intel-tree-explorer.no-crawl-scores .itree-page-score,
#intel-tree-explorer.no-crawl-scores .itree-status-bar,
#intel-tree-explorer.no-crawl-scores .itree-folder-score,
#intel-tree-explorer.no-crawl-scores .itree-sub-score { display:none; }
.ui-pill.guard-warning { background:var(--accent-muted);   color:var(--text-secondary); }
.ui-pill.accent   { background:var(--accent-muted);   color:var(--accent); }
.ui-pill.secondary{ background:var(--bg-panel-raised); color:var(--text-secondary); }
.ui-pill.pulse    { animation:uiPulse 1.4s ease-in-out infinite; }
@keyframes uiPulse { 0%,100%{opacity:1} 50%{opacity:.55} }

/* Tables can't shrink below their min-content width, and .main-content is
   overflow-x:hidden — so a wide table BLEEDS off-screen with no scrollbar.
   The wrapper scrolls the table inside the panel instead of widening the page. */
.ui-table-scroll { overflow-x:auto; min-width:0; }
/* Ellipsis for a long cell value (keyword) — full text on the title attr. */
.ui-cell-trunc { display:inline-block; max-width:340px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; vertical-align:bottom; }
.ui-table { width:100%; border-collapse:separate; border-spacing:0 6px; }
.ui-table th { font-family:var(--font-mono); font-size:var(--text-xs); font-weight:500; color:var(--text-secondary); text-align:left; padding:0 18px 8px; }
.ui-table td { height:var(--row-h); padding:6px 18px; background:var(--bg-panel-raised); border-top:1px solid rgba(255,255,255,0.055); border-bottom:1px solid rgba(255,255,255,0.055); font-family:var(--font-ui); font-size:var(--text-sm); color:var(--text-primary); vertical-align:middle; line-height:1.4; }
.ui-table td:first-child { border-left:1px solid rgba(255,255,255,0.055); border-radius:11px 0 0 11px; }
.ui-table td:last-child { border-right:1px solid rgba(255,255,255,0.055); border-radius:0 11px 11px 0; }
.ui-table tbody tr:hover td { background:rgba(255,255,255,0.07); border-color:rgba(255,255,255,0.10); }
.ui-table tbody tr[onclick] { cursor:pointer; }
.ui-table th.right, .ui-table td.right { text-align:right; }
.ui-table td.mono { font-family:var(--font-mono); }
    .ui-table th:first-child, .ui-table td:first-child { width:auto; }
    .ui-table th:not(:first-child), .ui-table td:not(:first-child) { width:1%; white-space:nowrap; }
.ui-table a { color:var(--accent); text-decoration:none; }
.ui-table a:hover { text-decoration:underline; }

/* ══ R3: A ROW INSIDE A CARD IS FLAT ═════════════════════════════════════════════════════════
   This is THE row pattern: UI.feedItem renders it, and Waiting on you, Since you were last here,
   Work on next and Recent activity are all made of it. It used to carry its own background, its
   own 1px border and its own 11px radius inside a card that already has a background, a border
   and a 16px radius, so every list read as boxes inside a box.

   Flat now: no background, no border, no radius of its own. Rows are told apart by ONE hairline
   between them, and `:first-child` drops the leading one so the list does not open with a rule
   against the card's own padding. The hover state stays, because a clickable row has to say so,
   but as a wash rather than a second border appearing on hover. */
.ui-feed-item { display:flex; align-items:flex-start; gap:10px; margin:0; padding:var(--space-3) 0;
  background:none; border:none; border-top:1px solid var(--border-subtle); border-radius:0; }
.ui-feed-item:first-child { border-top:none; }
.ui-feed-item[data-action] { cursor:pointer; }
.ui-feed-item[data-action]:hover { background:rgba(255,255,255,0.04); }
.ui-feed-icon { width:28px; height:28px; flex-shrink:0; display:flex; align-items:center; justify-content:center; background:var(--accent-muted); color:var(--accent); border-radius:var(--radius-control); font-size: var(--fs-label); }
/* Feed state dot (UI.feedItem) — replaces the icon tile on activity rows (the
   static quick-action shortcuts still use .ui-feed-icon). Prototype values:
   7px dot; running = hollow aura ring pulsing with uiPulse (the working
   pulse — the old `animation:pulse` name never had keyframes). */
.ui-feed-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; margin-top: 6px; }
.ui-feed-dot.done { background: #FFFFFF; }
.ui-feed-dot.run { background: transparent; border: 1.5px solid var(--aura);
  box-shadow: 0 0 0 2px var(--accent-glow-strong); animation: uiPulse 1.4s ease-in-out infinite; }
.ui-feed-dot.fail { background: var(--text-tertiary); }
.ui-feed-body { flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; }
.ui-feed-text { font-family:var(--font-ui); font-size:var(--text-sm); color:var(--text-primary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
/* Meta hierarchy: the metric (.ui-feed-meta-strong) reads first in secondary,
   the rest of the meta line tertiary. */
.ui-feed-meta { font-family:var(--font-mono); font-size:var(--text-xs); color:var(--text-tertiary); }
.ui-feed-meta-strong { color: var(--text-secondary); }
.ui-feed-time { font-family:var(--font-mono); font-size:var(--text-xs); color:var(--text-tertiary); flex-shrink:0; margin-top:2px; }

/* ── Light treatment (aura) ─────────────────────────────────────────────────
   Top-edge light on panels/cards, leading-edge bar on the active nav item and
   hovered rows. position:relative added here is safe: no .ui-panel/.ui-stat-card
   has an absolutely-positioned descendant to re-anchor (checked). */
.ui-panel, .ui-stat-card { position:relative; }
/* R2: REMOVED. This drew a gradient hairline across the top edge of EVERY panel and stat card,
   which is the coloured glow on card edges this unit exists to take out. The one card style is
   surface, hairline, radius; an edge that lights up on its own is not part of it. */
.ui-panel::before, .ui-stat-card::before { content:none; }
/* R1: the active marker is the thread, one orange line, and it takes its colour from the token
   rather than from the old light-blue literal that the glow was hard-coded to. */
.nav-item.active::before {
  content:''; position:absolute; left:0; top:15%; bottom:15%; width:2px; border-radius:2px;
  background: var(--accent);
  pointer-events:none;
}
.ui-feed-item { position:relative; }
/* ⚠ R3: THIS SELECTOR MATCHED NOTHING. It was written as `[onclick]`, and units 116 and 117
   removed the last inline handler from this application, so no feed row has carried an onclick
   attribute since. The rows are clickable through `data-action`, which is what the hover
   affordance has to key off. Same treatment the live `.ui-table` row hover already uses. */
.ui-feed-item[data-action]:hover::before {
  content:''; position:absolute; left:0; top:18%; bottom:18%; width:2px; border-radius:2px;
  background: var(--accent);
  pointer-events:none;
}
.ui-table td:first-child { position:relative; }
.ui-table tbody tr:hover td:first-child::before {
  content:''; position:absolute; left:0; top:18%; bottom:18%; width:2px; border-radius:2px;
  background: var(--accent);
  pointer-events:none;
}

.ui-empty { text-align:center; padding:32px 16px; }
.ui-empty-icon { font-size: var(--glyph-lg); color:var(--text-tertiary); margin-bottom:8px; }
.ui-empty-title { font-family:var(--font-ui); font-size:var(--text-base); font-weight:500; color:var(--text-secondary); margin-bottom:4px; }
.ui-empty-hint { font-family:var(--font-ui); font-size:var(--text-sm); color:var(--text-tertiary); margin-bottom:12px; }
/* A failed read. Left-aligned with an accent rule down its edge - the deliberate opposite of
   .ui-empty above, which is a centred block with a big calm glyph. The two must be tellable
   apart without reading them: one means "nothing here", the other means "I could not find out".
   Amber rather than red: the request failed, nothing is broken and nothing was lost. */
.ui-load-error { display:flex; align-items:flex-start; gap:8px; text-align:left; padding:12px 14px; margin:4px 0;
  border-left:2px solid var(--amber); background:var(--bg-panel-raised); border-radius:0 var(--radius-control) var(--radius-control) 0; }
.ui-load-error-mark { color:var(--amber); font-size: var(--fs-label); line-height:18px; flex-shrink:0; }
.ui-load-error-text { font-family:var(--font-ui); font-size:var(--text-sm); color:var(--text-secondary); line-height:18px; }
.ui-load-error-recover { color:var(--text-tertiary); }

.ui-progress { display:inline-flex; align-items:center; gap:8px; min-width:120px; }
.ui-progress-track { flex:1; height:4px; background:var(--bg-panel-raised); border-radius:var(--radius-pill); overflow:hidden; }
.ui-progress-fill { display:block; height:100%; background:var(--accent); border-radius:var(--radius-pill); }
.ui-progress-label { font-family:var(--font-mono); font-size:var(--text-sm); color:var(--text-secondary); }

.ui-btn { font-family:var(--font-ui); font-size:var(--text-sm); font-weight:500; border-radius:var(--radius-control); cursor:pointer; padding:6px 12px; transition:all .12s; }
.ui-btn.primary { background:var(--accent); border:1px solid var(--accent); color:var(--accent-ink,#fff); }
.ui-btn.primary:hover { background:var(--accent-hover); border-color:var(--accent-hover); }
.ui-btn.ghost { background:transparent; border:1px solid var(--border-strong); color:var(--text-secondary); }
.ui-btn.ghost:hover { color:var(--text-primary); background:var(--bg-panel-raised); }
.ui-btn.ghost.danger { color:var(--negative); border-color:var(--negative); }
.ui-btn:disabled { color:var(--text-tertiary); border-color:var(--border-subtle); background:transparent; cursor:not-allowed; }
.ui-btn:disabled:hover { background:transparent; color:var(--text-tertiary); }

/* Quality gauge (UI.scoreGauge) — replaced the score ring. Monochrome by
   design: tonal dim→bright fill, white gate marker at UI.qualityGate with a
   soft cold halo (aura blue, matches --aura). */
/* R2: the gauge filled a fixed 200px inside a card that is far wider, so the quality snapshot
   read as a small block floating in its own card. It takes the card's width now, up to a cap,
   and stays left-aligned with every other card's contents. 26px was its own size and is gone. */
.ui-gauge { width: 100%; max-width: 360px; text-align: left; }
.ui-gauge-head { display: flex; align-items: baseline; gap: var(--space-2); }
.ui-gauge-num { font-family: var(--font-ui); font-size: var(--fs-stat); font-weight: 800; color: var(--text-primary); line-height: 1; }
.ui-gauge-scale { font-family: var(--font-ui); font-size: var(--fs-label); color: var(--text-secondary); }
.ui-gauge-track { position: relative; height: 6px; border-radius: 3px; background: var(--bg-panel-raised); margin: 10px 0 6px; }
.ui-gauge-track.has-gate { margin: 14px 0 24px; }
.ui-gauge-fill { position: absolute; left: 0; top: 0; bottom: 0; border-radius: 3px;
  background: var(--accent); }
.ui-gauge-gate { position: absolute; top: -4px; bottom: -4px; width: 2px; margin-left: -1px; border-radius: 1px;
  background: var(--text-primary); }
.ui-gauge-gate-label { position: absolute; top: 11px; transform: translateX(-50%);
  font-family: var(--font-ui); font-size: var(--fs-small); letter-spacing: 0.04em; color: var(--text-secondary); white-space: nowrap; }
.ui-gauge-label { font-family: var(--font-ui); font-size: var(--fs-label); color: var(--text-secondary); }

/* Search clicks chart (Produce) — monochrome area chart: white line, tonal
   gradient fill, low-opacity gridlines, aura-bloomed endpoint marking the
   series' latest day, month labels beneath. Number large, label beneath it. */
.pc-plot { position: relative; }
.pc-plot svg { display: block; width: 100%; height: 72px; }
.pc-grid { stroke: rgba(255, 255, 255, 0.06); stroke-width: 1; vector-effect: non-scaling-stroke; }
.pc-line { fill: none; stroke: rgba(255, 255, 255, 0.9); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
/* Endpoint = today: white dot with the aura bloom (same halo as the gate marker
   and run dots). An HTML overlay, not an svg circle — preserveAspectRatio="none"
   would stretch a circle into an ellipse. */
.pc-end-dot { position: absolute; width: 6px; height: 6px; border-radius: 50%; transform: translate(-50%, -50%);
  background: var(--text-primary); }
/* Approvals (Pass 2): the Produce bordered row-card idiom. .ap- classes only —
   the old cards borrowed client-row/client-name, which are shared with the
   Clients and Users screens and stay untouched. */
.ap-intro { font-size: var(--fs-label); color:var(--text-sub); }
/* R5: Approvals rows are the app's row pattern, flat since R3 everywhere but here. */
.ap-card { display:flex; gap:12px; margin:0; padding:var(--space-3) 0; border-radius:0; background:none; border:none; border-top:1px solid var(--border-subtle); }
.ap-card:first-child { border-top:none; }
.ap-card:hover { background:rgba(255,255,255,0.04); }
.ap-card-title { font-size: var(--fs-body); font-weight:500; color:var(--text-primary); }
.ap-card-meta { font-family:var(--font-ui); font-size:var(--fs-small); color:var(--text-secondary); margin-top:3px; }
.ap-card-actions { display:flex; gap:6px; align-items:center; flex-shrink:0; }
/* Quiet done mark — status green retired; link behavior unchanged. */
.ap-done { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); text-decoration:none; white-space:nowrap; }
.ap-done:hover { color:var(--text-secondary); }

/* Work on Next (Produce) — queue rows in the feed-row idiom: dot, kind label,
   two-line body, clicks at stake, actions right. Held rows dimmed in-list.
   (The .ig-* row classes are #panel-intelligence-scoped, hence this set.) */
.pn-row { align-items: center; }
.pn-row .ui-feed-dot { margin-top: 0; }
/* The example line can carry a ~420-char stored holdReason — clamp to two lines
   (full text rides in the span's title attribute). Scoped: the base
   .ui-feed-meta rule stays untouched for the activity feed. */
.pn-row .ui-feed-meta { display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.pn-kind { font-family: var(--font-mono); font-size: var(--fs-small); letter-spacing: 0.05em; color: var(--text-secondary); min-width: 52px; flex-shrink: 0; }
.pn-stake { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-tertiary); flex-shrink: 0; }
.pn-actions { display: flex; gap: 6px; flex-shrink: 0; }
.pn-actions .ui-btn { font-size: var(--fs-small); padding: 3px 10px; }
.pn-held { opacity: 0.6; }
/* Seated as a real control (show-more / show-less). Every NEW property here is
   compensated in the #panel-intelligence .ig-quiet scoped rule (index.html) so
   the six Intelligence pager footers stay pixel-identical. */
.pn-quiet { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-tertiary); display: inline-flex; align-items: center; padding: 6px 12px; border-radius: var(--radius-control); margin-top: 10px; cursor: pointer; transition: background 0.12s, color 0.12s; }
.pn-quiet:hover { color: var(--text-secondary); background: rgba(255,255,255,0.06); }
/* Plain quiet text (pn-quiet's PRE-control look) for static info lines — no
   cursor, no hover wash, no control seating. */
.pn-note { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-tertiary); padding: 8px 2px 6px; }
/* Neutral dim dot for held rows — .fail means failed; held is not a failure. */
.ui-feed-dot.dim { background: var(--text-tertiary); }
/* Quality Snapshot fills its grid row so its card bottom lines up with its row
   sibling Active Jobs (.ui-grid's align-items:start would shrink-wrap it).
   Scoped to this one card — no other row stretches. Same mechanism for the
   Work on Next / Waiting on You pair: the sections ARE the panels (block flow,
   not flex), so their bodies keep sizing to content — pager footers stay in
   flow under the last row and the empty space sits below them. */
#produce-quality-card { align-self: stretch; }
#produce-next-card, #produce-waiting-card { align-self: stretch; }

.pc-months { position: relative; height: 16px; margin-top: 4px; }
.pc-month { position: absolute; transform: translateX(-50%); font-family: var(--font-mono); font-size: var(--fs-small); letter-spacing: 0.05em; color: var(--text-tertiary); }
.pc-month:first-child { transform: none; }


.ui-skeleton-row { height:14px; border-radius:4px; margin:10px 0; background:linear-gradient(90deg, var(--bg-panel-raised) 25%, var(--border-subtle) 50%, var(--bg-panel-raised) 75%); background-size:200% 100%; animation:uiShimmer 1.2s linear infinite; }
@keyframes uiShimmer { from{background-position:200% 0} to{background-position:-200% 0} }


/* ═══ SHELL (Pass 2): compact logo lockup, user block, content grid ═══ */
/* Brand lockup: one theme-aware transparent PNG (mark + wordmark baked in),
   centered, with tagline + online indicator stacked beneath it. */
.sidebar-logo { position:relative; display:flex; flex-direction:column; align-items:center; text-align:center; }
.sidebar-logo .logo-img { display:block; width:80px; max-width:80px; height:auto; margin:0; flex-shrink:0; object-fit:contain; }
/* Brand C-mark: the transparent near-white PNG, rendered plain. */
/* ══ R1: THE COMPACT LOCKUP IN THE SIDEBAR ═══════════════════════════════════════════════════
   Bird and name side by side with their BOTTOMS ALIGNED, which is what makes it a lockup rather
   than two things near each other: the branch under the bird and the baseline of the name sit on
   the same line. The name is real text in Inter 800, never SVG text, so it is selectable, it is
   read aloud, and it uses the font the rest of the app uses. */
.brand-mark { position:relative; display:flex; align-items:flex-end; gap:var(--space-2); width:auto; flex-shrink:0; }
.brand-bird { width:38px; height:auto; display:block; flex-shrink:0; overflow:visible; }
.brand-bird .bird-body   { fill: var(--nav-text, #FFFFFF); }
/* ⚠ THE CUTOUTS TAKE THE SURFACE, NOT A COLOUR. The eye and the wing are holes in the bird, so
   their fill has to equal whatever is behind it. Driven from --nav-bg, the same token that paints
   the sidebar, so changing the sidebar can never leave two mismatched boxes on the mark. */
.brand-bird .bird-cut    { fill: var(--nav-bg, #000000); }
.brand-bird .bird-branch { fill: var(--accent); }
/* R3: the one place in the app that renders Inter, and smaller than R1 set it. 27px beside a
   44px bird filled the lockup corner to corner and read as cramped; 22px beside a 38px bird
   leaves air on both sides without changing the lockup's proportions. The bottoms stay aligned,
   which is still what makes it a lockup: padding-bottom nudges the baseline onto the branch. */
.brand-word {
  font-family: var(--font-wordmark); font-weight: 800; font-size: 22px;
  letter-spacing: -0.04em; line-height: 0.82; color: var(--nav-text, #FFFFFF);
  padding-bottom: 5px; white-space: nowrap;
}
/* R3: clear separation between the mark and the org switcher. At 9px the switcher read as part
   of the lockup, which is what made the whole corner look packed. */
.logo-lockup { display:flex; flex-direction:column; align-items:center; gap:var(--space-5); }
.logo-name { font-family:var(--font-ui); font-size: var(--fs-body); font-weight:500; letter-spacing:-0.02em; line-height:1.15; color:var(--nav-text,#F2F3F5); }
.logo-tag { font-family:var(--font-ui); font-size:var(--fs-small); color:var(--text-tertiary); margin-top:6px; }
.sidebar-logo .logo-tag { margin-top:0; white-space:nowrap; }
.sidebar-logo .sidebar-status { margin-top:9px; justify-content:flex-start; }
.sidebar-collapse-btn { position:absolute; top:0; right:8px; background:transparent; border:none; color:var(--text-tertiary); cursor:pointer; font-size:var(--fs-label); padding:2px 4px; flex-shrink:0; }
.sidebar-collapse-btn:hover { color:var(--text-secondary); }

/* ── Collapsed rail ──────────────────────────────────────────────────────────
   The rail reclaims width; it is not a navigation surface until nav icons exist. Shown: the
   expand button at the top and a 28px mark centered below it. Everything else is hidden
   outright, never clipped: the org switcher, the client block, the whole nav (labels, children,
   chevrons, badges), the user badge text, the legacy logo pieces. The grid column that follows
   the rail lives with the app shell (.app:has(.sidebar-collapsed)); the Mac header offset lives
   with the frameless-window rules. */
.sidebar-collapsed { width:44px !important; overflow:hidden; }
.sidebar-collapsed .sidebar-logo { padding: 30px 0 12px; }
body.mac-inset .sidebar-collapsed .sidebar-logo { padding-top: 78px; }   /* traffic lights + the button row */
.sidebar-collapsed .sidebar-collapse-btn { right:auto; left:50%; transform:translateX(-50%); }
/* R1: the rail lockup is the bird alone, centred. The word is hidden rather than shrunk, because
   "centraloom" at rail width would be unreadable and the bird is the mark. */
.sidebar-collapsed .brand-mark { display:flex; justify-content:center; width:100%; }
.sidebar-collapsed .brand-bird { width:30px; }
.sidebar-collapsed .brand-word { display:none; }
.sidebar-collapsed .org-switcher-wrap,
.sidebar-collapsed .sidebar-user-info,
.sidebar-collapsed .logo-tag, .sidebar-collapsed .logo-text, .sidebar-collapsed .logo-img { display:none; }
.sidebar-collapsed .sidebar-user { justify-content:center; padding:12px 0 16px; }
.sidebar-collapsed .notif-bell { display:none; }   /* the rail has no room for it; the bell returns when the sidebar expands */
/* The nav shows again in the rail, as icons only: labels, chevrons, and children hidden; each parent
   centered in the 44px rail at 18px with 8px vertical padding; the active one keeps the raised
   background and the aura bar on the left edge (.nav-item.active and its ::before, unchanged).
   Each rail icon's title is the button's title attribute. */
.sidebar-collapsed .sidebar-nav { display:block; padding:8px 0 16px; }
.sidebar-collapsed .nav-label, .sidebar-collapsed .nav-chevron-btn, .sidebar-collapsed .nav-children { display:none; }
/* .nav-parent-wrap.expanded .nav-children { display:block } carries three classes and outranks the
   two-class rule above, so an expanded parent's children (their guide line and 2px/8px margins)
   still rendered in the rail and pushed Settings down. This selector carries .expanded too. */
.sidebar-collapsed .nav-parent-wrap.expanded .nav-children { display:none; }
.sidebar-collapsed .nav-parent-row { display:block; }
.sidebar-collapsed .nav-item { justify-content:center; padding:8px 0; border-radius:0; }
.sidebar-collapsed .nav-icon { width:18px; height:18px; }
.sidebar-collapsed .nav-badge { position:absolute; top:3px; right:5px; margin:0; padding:0 4px; font-size:var(--fs-small); }
/* ── end collapsed rail ── */

.sidebar-user { display:flex; align-items:center; gap:9px; padding:12px 14px 16px; border-top:1px solid var(--border-subtle); flex-shrink:0; margin-top:auto; }
/* ONE button wraps the avatar, name and role, so the badge is a single tab stop and the whole
   area is clickable. The reset strips the user-agent button chrome; the flex row reproduces the
   layout the two sibling elements had, and it sits above the rules below so the avatar keeps
   its own background and centring. */
.sidebar-user-account { display:flex; align-items:center; gap:9px; flex:1; min-width:0;
  appearance:none; -webkit-appearance:none; border:0; margin:0; padding:0; background:none;
  font:inherit; color:inherit; text-align:left; }
.sidebar-user-account:focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:6px; }
.sidebar-user-avatar { width:28px; height:28px; border-radius:50%; background:var(--accent-muted); color:var(--accent); display:flex; align-items:center; justify-content:center; font-size:var(--fs-body); flex-shrink:0; }
.sidebar-user-info { flex:1; min-width:0; }
.sidebar-user-name { display:block; font-family:var(--font-ui); font-size:var(--fs-label); font-weight:500; color:var(--text-primary); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sidebar-user-role { display:block; font-family:var(--font-ui); font-size:var(--fs-small); color:var(--text-tertiary); }
.sidebar-user-logout { font-size:var(--fs-small); padding:3px 8px; }
/* ── Notifications: the bell and its panel ──────────────────────────────────
   Tokens only, no raw literals - the colour cleanup pass made that the rule.
   The bell is quiet by default: it takes the tertiary text colour and only the
   dot carries the accent, because the empty inbox is the normal state. */
.notif-bell { position:relative; background:none; border:none; cursor:pointer; color:var(--text-tertiary); font-size: var(--fs-body); line-height:1; padding:4px 6px; border-radius:var(--radius-control); flex-shrink:0; }
.notif-bell:hover { color:var(--text-primary); background:var(--bg-panel-raised); }
.notif-dot { position:absolute; top:0; right:0; min-width:14px; padding:0 4px; font-family:var(--font-mono); font-size: var(--fs-small); line-height:14px; text-align:center; border-radius:var(--radius-pill); background:var(--blue); color:var(--bg-app); }

.notif-panel { position:absolute; left:12px; bottom:64px; width:340px; max-height:70vh; display:flex; flex-direction:column; background:var(--bg); border:1px solid var(--border); border-radius:var(--radius-panel); box-shadow:0 12px 40px rgba(0,0,0,0.4); }
.notif-head { display:flex; align-items:center; justify-content:space-between; padding:14px 16px 10px; border-bottom:1px solid var(--border-subtle); }
.notif-head-title { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-dim); }
.notif-list { overflow-y:auto; padding:6px; }
.notif-item { display:flex; gap:10px; align-items:flex-start; padding:9px 10px; border-radius:var(--radius-control); }
.notif-item.clickable { cursor:pointer; }
.notif-item.clickable:hover { background:var(--bg-panel-raised); }
.notif-item-icon { color:var(--text-tertiary); font-size: var(--fs-small); line-height:16px; flex-shrink:0; }
.notif-item.unread .notif-item-icon { color:var(--blue); }
.notif-item-body { display:flex; flex-direction:column; min-width:0; }
.notif-item-text { font-family:var(--font-ui); font-size: var(--fs-label); color:var(--text-primary); }
.notif-item.unread .notif-item-text { font-weight:500; }
.notif-item-meta { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); margin-top:2px; }


/* Keyboard shortcut overlay (?) */
#shortcut-overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:9600; align-items:center; justify-content:center; }
#shortcut-overlay .ui-panel { width:380px; max-width:92vw; }
.shortcut-row { display:flex; align-items:center; justify-content:space-between; padding:7px 0; border-bottom:1px solid var(--border-subtle); font-family:var(--font-ui); font-size:var(--text-sm); color:var(--text-secondary); }
.shortcut-row:last-child { border-bottom:none; }
.shortcut-key { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-primary); background:var(--bg-panel-raised); border:1px solid var(--border-strong); border-radius:4px; padding:2px 8px; }

/* ═══ VIEW LAYOUT (Pass 2) ═══ */
/* ── Screen shell: the outer container panels nest inside ── */
.shell {
  background: var(--bg-panel);
  border: var(--card-border);
  border-radius: var(--card-radius);
  padding: var(--space-5) var(--space-6) var(--space-7, 28px);
  position: relative;
}
/* A shelled panel does not need the full-bleed 80px tail — the shell closes the page. */
.panel:has(> .shell) { padding-bottom: 32px; }
/* R2: THE RAINBOW IS GONE. This drew a five-colour gradient hairline across the top edge of the
   Produce shell, in pink, blue, purple and cyan, none of which the brand has. It is the single
   most visible leftover of the old aura and it sat on a CARD EDGE, which is exactly where the
   one card style says nothing belongs. The rule is kept as an empty marker rather than deleted
   so the next person looking for it finds this note instead of nothing. */
.shell::before { content: none; }
/* Produce headline band: numbers column beside the flexing clicks chart. */
/* R2: the band stacks, so the stats row gets the full width of the card and the chart sits
   under it rather than competing with it for a 180px column. */
.ph-band { display:flex; flex-direction:column; align-items:stretch; gap:var(--space-5); padding-top:var(--space-4); }
/* R2: ONE HORIZONTAL ROW. This was a 180px column with the three figures stacked vertically
   beside the chart, which is why the card read as a list of unrelated numbers. They sit side by
   side now, each one label over figure, and the row wraps rather than squeezing on a narrow
   window. 26px was its own size and is gone: a figure is the title size at weight 800. */
.ph-nums { flex:1 1 auto; min-width:0; display:flex; flex-direction:row; flex-wrap:wrap; align-items:flex-start; gap:var(--space-6); }
.ph-stat { display:flex; flex-direction:column; gap:var(--space-1); min-width:132px; }
.ph-num { font-family:var(--font-ui); font-size:var(--fs-stat); font-weight:800; letter-spacing:-0.02em; color:var(--text-primary); line-height:1.1; }
.ph-label { font-family:var(--font-ui); font-size:var(--fs-label); font-weight:500; color:var(--text-secondary); }
.ph-delta { font-family:var(--font-ui); font-size:var(--fs-small); color:var(--text-tertiary); }
.ph-sub { font-family:var(--font-ui); font-size:var(--fs-small); color:var(--text-tertiary); }
.ph-chart { flex:1; min-width:0; }

/* This week strip (Produce): seven equal day cells in the card-row idiom.
   Today = the aura current-day treatment (matches .cal-cell.today). */
/* R3: the day cells are the same row pattern laid out sideways, so they get the same treatment:
   no box of their own, one hairline between them, consistent padding. The strip's own gap is
   gone, because a divider and a gap do the same job and doing both is what made seven little
   cards. Today keeps a mark, but on the LEFT EDGE as an accent rule rather than a ring: a whole
   bordered cell among six flat ones was the loudest thing on the screen. */
.pw-row { display:flex; gap:0; }
.pw-cell { flex:1 1 0; min-width:0; min-height:78px; background:none; border:none;
  border-left:1px solid var(--border-subtle); border-radius:0; padding:var(--space-2) var(--space-3); }
.pw-cell:first-child { border-left:none; }
.pw-cell.pw-today { box-shadow:inset 2px 0 0 var(--accent); }
.pw-cell.pw-today .pw-day { color:var(--text-secondary); }
.pw-day { font-family:var(--font-mono); font-size: var(--fs-small); letter-spacing:0.05em; color:var(--text-tertiary); margin-bottom:6px; }
.pw-chip { display:block; font-family:var(--font-ui); font-size:var(--fs-small); color:var(--text-primary); background:rgba(255,255,255,0.07); border:1px solid rgba(255,255,255,0.08); border-radius:6px; padding:2px 7px; margin-bottom:4px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pw-chip.pw-done { color:var(--text-tertiary); background:transparent; }
.pw-chip.pw-missed { color:var(--negative); border-color:color-mix(in srgb, var(--negative) 35%, transparent); }
/* ⚠ R4: "NOTHING SCHEDULED" IS NOT A CHIP, IT IS THE ABSENCE OF ONE.
   It was drawn as a dashed bordered box in every empty day, so a week with nothing in it showed
   seven little outlines, which is the one thing R3 took out of this strip. A chip is a scheduled
   page; where there is none, the cell says so in quiet text and draws nothing. Same for the
   "n ready" note on today, which is a count rather than a scheduled page. */
.pw-chip.pw-ghost { color:var(--text-tertiary); background:transparent; border:none; padding:2px 0; }
.pw-more { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); padding-top:2px; }

.ui-stack { display:flex; flex-direction:column; gap:var(--gap-grid-row); min-width:0; }
.ui-stat-strip { display:grid; grid-template-columns:repeat(5,1fr); gap:var(--gap-grid); }
@media (max-width:1100px){ .ui-stat-strip { grid-template-columns:repeat(2,1fr); } }
.produce-ring-wrap { display:flex; flex-direction:column; align-items:center; gap:8px; padding:8px 0 4px; }
.produce-ring-counts { display:flex; gap:8px; }

/* ═══ INTELLIGENCE (Pass 2): KPI strip + tree rows per spec §4 ═══ */
.intel-stats-strip { padding: 14px 28px; border-bottom: 1px solid var(--border-subtle); flex-shrink: 0; }
/* Counts are numbers: every sem-* KPI reads as text. The classes stay for the Intelligence strip. */
.ui-stat-num.sem-negative { color: var(--text-secondary); }
.ui-stat-num.sem-warning  { color: var(--text-secondary); }
.ui-stat-num.sem-positive { color: var(--text-primary); }
.itree-folder-row { min-height: var(--row-h); border-bottom: 1px solid var(--border-subtle); }
.itree-folder-row:hover { background: var(--bg-panel-raised); }
.itree-subfolder-row, .itree-page { min-height: 36px; }
.itree-subfolder-row:hover, .itree-page:hover { background: var(--bg-panel-raised); }
/* Child pages indent with a subtle left rule */
.itree-sub-children { border-left: 1px solid var(--border-subtle); margin-left: 14px; }


/* ═══ QUALITY (Pass 2): ring hero + breakdown ═══ */
.quality-hero { display:flex; align-items:center; gap:24px; margin-bottom:20px; flex-wrap:wrap; }
.quality-strip { flex:1; min-width:280px; grid-template-columns:repeat(4,1fr); }
.quality-score-cell { font-family:var(--font-mono); font-weight:500; color:var(--text-primary); }   /* a score is a number; no band */

/* ═══ PUBLISH (Pass 2): view toggle + calendar grid layout ═══ */
/* ── PUBLISH (settled Produce language) ──
   Raised bordered row cards, color means danger only, aura means live/current.
   Status styling rides pub-st-* modifiers set by the renderers — pubStatusMeta's
   color slot is no longer consumed. Missed matches the week strip's treatment
   (.pw-chip.pw-missed — red family). */
.pub-toolbar { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:2px 2px 12px; margin-bottom:var(--gap-grid); flex-wrap:wrap; }
.pub-view-toggle { display:flex; gap:6px; }
/* R5: a selected view is the accent wash, like every other selected control. Solid white read
   louder than the primary action beside it. */
.pub-vt.active, .camp-view-btn.active { background:var(--accent-muted); color:var(--text-primary); border-color:var(--accent); }
.pub-cal-grid { display:grid; grid-template-columns:300px 1fr; gap:var(--gap-grid); align-items:start; }
#pub-ready-list { max-height:60vh; overflow-y:auto; }
@media (max-width:1100px){ .pub-cal-grid { grid-template-columns:1fr; } }
.pub-note { font-family:var(--font-mono); font-size:var(--text-xs); color:var(--text-tertiary); padding:8px 0; }
.pub-danger { color:var(--negative); }
.btn-sm.pub-danger { border-color:var(--negative); }
/* Bulk bar: neutral raised card — selection is not a warning. */
.pub-bulk-bar { align-items:center; gap:8px; flex-wrap:wrap; background:var(--bg-panel-raised); border:1px solid var(--border-strong); border-radius:var(--radius-control); padding:6px 10px; margin-bottom:8px; }
.pub-bulk-label { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-secondary); }
/* Rail chips: bordered row card, raised surface, hover raise. */
.pub-chip { background:var(--bg-panel-raised); border:1px solid rgba(255,255,255,0.055); border-left-width:3px; border-radius:var(--radius-control); padding:8px 10px; margin-bottom:8px; cursor:grab; font-size: var(--fs-label); transition:background 0.12s, border-color 0.12s; }
.pub-chip:hover { background:rgba(255,255,255,0.07); border-color:rgba(255,255,255,0.10); }
.pub-chip:active { cursor:grabbing; }
.pub-chip-top { display:flex; align-items:flex-start; gap:6px; }
.pub-chip-top .pub-sel { margin-top:1px; }
.pub-chip-title { font-weight:500; margin-bottom:4px; word-break:break-word; flex:1; }
.pub-chip-meta { display:flex; align-items:center; gap:6px; flex-wrap:wrap; }
.pub-chip-status { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-secondary); }
.pub-chip-kind { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); }
.pub-chip-sm { font-size: var(--fs-small); padding:1px 5px; }
.pub-chip-go { font-size: var(--fs-small); padding:2px 6px; margin-left:auto; }
/* Status modifiers: quiet white for scheduled, secondary for ready, week-strip
   red for missed. No green anywhere. */
.pub-st-ready { border-left-color:var(--text-tertiary); }
.pub-st-scheduled { border-left-color:rgba(255,255,255,0.55); }
.pub-st-scheduled .pub-chip-status { color:var(--text-primary); }
.pub-st-missed { border-left-color:color-mix(in srgb, var(--negative) 55%, transparent); }
.pub-st-missed .pub-chip-status { color:var(--negative); }
/* Glyph buttons (✕ ↩ 🗑): borderless, dim until hover; danger stays red. */
.pub-glyph { background:none; border:none; cursor:pointer; font-size: var(--fs-small); padding:0 3px; color:var(--text-tertiary); line-height:1; }
.pub-glyph:hover { color:var(--text-primary); }
.pub-glyph.pub-danger { color:var(--negative); }
/* Calendar grid. */
.pub-cal { display:grid; grid-template-columns:repeat(7,1fr); gap:4px; }
.pub-cal-dow { font-family:var(--font-mono); font-size: var(--fs-small); letter-spacing:0.1em; color:var(--text-tertiary); text-align:center; padding:2px; }
.pub-cal-day { min-height:62px; background:var(--bg-panel-raised); border:1px solid rgba(255,255,255,0.055); border-radius:var(--radius-control); padding:4px; font-size: var(--fs-small); overflow:hidden; }
/* Today: the week strip's aura ring (aura = current). */
.pub-cal-day.pub-today { border-color:var(--accent); }
/* Drag target: aura, it marks the current drop cell. */
.pub-cal-day.drop-hover { outline:2px dashed var(--accent-glow-strong); outline-offset:-2px; }
.pub-cal-num { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); margin-bottom:2px; }
.pub-cal-item { display:flex; align-items:center; gap:2px; background:rgba(255,255,255,0.07); border:1px solid rgba(255,255,255,0.08); border-left:2px solid rgba(255,255,255,0.35); border-radius:4px; padding:1px 3px; margin-bottom:2px; }
.pub-cal-item .pub-glyph { font-size: var(--fs-small); padding:0 1px; }
.pub-cal-kw { flex:1; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
/* Published: quiet done — dim check, plain white text, no green. */
.pub-cal-item.pub-st-published { display:block; color:var(--text-primary); background:transparent; border-left-color:rgba(255,255,255,0.25); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.pub-check { color:var(--text-tertiary); margin-right:2px; }
.pub-cal-item.pub-link { cursor:pointer; }
.pub-cal-item.pub-st-missed { color:var(--negative); border-color:color-mix(in srgb, var(--negative) 35%, transparent); border-left-color:color-mix(in srgb, var(--negative) 55%, transparent); }
.pub-tag-missed { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--negative); border:1px solid color-mix(in srgb, var(--negative) 35%, transparent); border-radius:2px; padding:0 2px; margin-right:2px; }

/* ═══ WRITE (Pass 2): two-column form + live summary rail + idea grid ═══ */
.write-grid { display:grid; grid-template-columns:minmax(0,1fr) 300px; gap:var(--gap-grid); align-items:start; padding:0 0 40px; }
@media (max-width:1100px){ .write-grid { grid-template-columns:1fr; } }
.write-form-col { min-width:0; }
.write-summary-rail { position:sticky; top:80px; }
.write-sum-row { display:flex; align-items:baseline; justify-content:space-between; gap:10px; padding:7px 0; border-bottom:1px solid var(--border-subtle); font-size:var(--text-sm); }
.write-sum-row:last-of-type { border-bottom:none; }
.write-sum-key { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); flex-shrink:0; }
.write-sum-val { color:var(--text-primary); text-align:right; min-width:0; overflow-wrap:anywhere; }
.write-sum-warn { margin-top:10px; padding:9px 11px; background:var(--warning-muted); border:1px solid var(--warning); border-radius:var(--radius-control); font-size:var(--text-sm); color:var(--text-primary); }
.write-sum-warn a { color:var(--warning); }
/* ── Write screen de-inline (settled language). Amber survives only where a
   decision is pending (warncards, slug collision); running status is quiet. ── */
.write-doors { display:flex; gap:10px; flex-wrap:wrap; }
.write-change-link { background:none; border:none; color:var(--text-tertiary); font-size: var(--fs-small); cursor:pointer; padding:6px 2px; text-decoration:underline; }
.write-scorecard { margin-top:28px; padding-top:24px; border-top:1px solid var(--border); }
.write-score-head { display:flex; align-items:baseline; gap:14px; margin-bottom:20px; }
.write-score-label { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); }
.write-score-num { font-size: var(--fs-title); font-weight:500; letter-spacing:-0.04em; line-height:1; }
.write-score-den { font-size: var(--fs-heading); color:var(--text-tertiary); font-weight:400; }
.write-score-badge { font-family:var(--font-mono); font-size: var(--fs-small); font-weight:500; padding:4px 10px; margin-left:4px; }
.write-score-checks { display:grid; grid-template-columns:1fr 1fr; gap:4px 40px; margin-bottom:16px; }
.write-score-notes { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); letter-spacing:0.04em; margin-bottom:8px; }
/* Running status, not a pending decision: quiet, no amber. */
.write-score-rewriting { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-secondary); }
.write-warncard { border:1px solid var(--warning); border-radius:var(--radius-control); padding:16px 20px; margin-bottom:20px; background:color-mix(in srgb, var(--warning) 5%, transparent); }
.write-warncard-title { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--warning); margin-bottom:8px; }
.write-warncard-msg { font-size: var(--fs-label); color:var(--text-primary); margin-bottom:12px; line-height:1.5; }
.write-warncard-note { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); }
.write-url-preview { font-family:var(--font-mono); font-size: var(--fs-label); padding:6px 8px; border:1px solid var(--border-subtle); border-radius:var(--radius-control); background:var(--bg-panel-raised); color:var(--text-primary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.write-slug-warn { font-size: var(--fs-label); color:var(--warning); margin-top:5px; }
.write-kids-head { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); margin-bottom:4px; }
.write-kids-list { max-height:140px; overflow:auto; border:1px solid var(--border-subtle); border-radius:var(--radius-control); }
.write-kid { font-size: var(--fs-label); padding:4px 8px; border-bottom:1px solid var(--border-subtle); }
.write-kid-collide { color:var(--warning); font-weight:500; }
.write-kid-slug { opacity:.6; font-family:var(--font-mono); }
.write-kids-empty { font-size: var(--fs-label); color:var(--text-tertiary); }
.write-kept-bar { margin:4px 0 12px; }
.write-kept-bar .ui-progress { width:100%; }
/* Idea cards: grid, no reflow jump on replace */
#gen-spokes-ideas .spoke-idea-card { border-radius:var(--radius-control); }

/* ═══ SETTINGS (Pass 2): two-column with sticky section nav ═══ */
#panel-settings { max-width:1240px; }
/* ══ R6b: SETTINGS, AND ONLY SETTINGS, IS SET IN IBM PLEX MONO ═══════════════════════════════
   Two rules do the whole of it.

   The first redefines the five steps ON THE PANEL. They are rem, so they are measured against
   the root and a parent font-size cannot touch them; redefining the tokens here is what lets
   one screen have its own scale without a second scale existing anywhere else. The factor is
   0.9375, which is 15/16: it lands Settings on exactly the sizes R6 measured as right when the
   whole application was mono, and it is one number rather than five, so the ratios hold.

   The second is the font. `#panel-settings *` beats the class selectors inside it on
   specificity, which is the point: every label, hint, value, input and button in there is mono
   whatever rule drew it, and there is nowhere for a straggler to hide.

   ⚠ WHAT IS DELIBERATELY NOT COVERED: a modal opened from Settings. Modals are appended to the
   body, outside this panel, so they stay in the system stack. The brief names the panel and its
   parts; a dialog that is not inside it is a different surface, and silently restyling every
   modal in the app because one route to it starts here is how an app-wide change happens by
   accident for the second time. */
#panel-settings {
  --settings-scale: 0.9375;
  --fs-title: calc(1.25rem * var(--settings-scale));
  --fs-heading: calc(1rem * var(--settings-scale));
  --fs-body: calc(0.875rem * var(--settings-scale));
  --fs-label: calc(0.75rem * var(--settings-scale));
  --fs-small: calc(0.6875rem * var(--settings-scale));
  --fs-stat: var(--fs-title);
  /*
   * ⚠ THE LEGACY NAMES HAVE TO BE REDEFINED HERE TOO, AND THE REASON IS EASY TO GET WRONG.
   * `--text-xs: var(--fs-small)` on :root is substituted ON :root, so what inherits into this
   * panel is the root's computed value, not a live reference. Leaving them out would have given
   * any rule still saying --text-sm the full-size step while its neighbour saying --fs-label
   * scaled, which is a half-scaled screen and far harder to spot than an unscaled one.
   */
  --text-xs: var(--fs-small);
  --text-sm: var(--fs-label);
  --text-base: var(--fs-body);
  --text-lg: var(--fs-heading);
  --text-xl: var(--fs-title);
  --text-stat: var(--fs-title);
  /*
   * ⚠ AND EVERY FONT TOKEN POINTS AT THE SETTINGS FACE INSIDE THIS PANEL.
   *
   * The descendant rule below cannot reach an INLINE style, and the Settings markup carries
   * `style="font-family:var(--mono)"` in two places. --mono is an alias of --font-ui resolved
   * on :root, so those two lines stayed in the system stack with mono all around them, which
   * is exactly the kind of near-miss a screenshot does not show. Redefining the tokens here
   * means an inline style written tomorrow lands in the right font without anybody remembering
   * this rule exists.
   */
  --font-ui: var(--font-settings);
  --font-mono: var(--font-settings);
  --mono: var(--font-settings);
  --sans: var(--font-settings);
  /*
   * ⚠ AND THE PANEL SETS ITS OWN BODY SIZE, because redefining the tokens only moves what USES
   * them. An element inside here with no font-size rule of its own inherits from `body`, which
   * is outside the panel and still 14px: .feat-list was rendering at the full body size with
   * everything around it scaled. One declaration fixes the whole class of them.
   */
  font-size: var(--fs-body);
}
#panel-settings, #panel-settings * { font-family: var(--font-settings); }
/*
 * ⚠ A BUTTON DOES NOT INHERIT font-size, and .mq-opt never set one, so the three model-quality
 * cards rendered at the user agent's 13.333px while everything around them was on the scale.
 * That predates this unit; scoping the panel's scale is what made it visible, because it was
 * the one size in here that did not move with the rest.
 */
#panel-settings .mq-opt { font-size: var(--fs-body); }

.settings-grid { display:grid; grid-template-columns:180px minmax(0,1fr); gap:var(--gap-grid); align-items:start; }
@media (max-width:1100px){ .settings-grid { grid-template-columns:1fr; } .settings-nav { position:static; display:flex; gap:8px; flex-wrap:wrap; } }
.settings-nav { position:sticky; top:80px; display:flex; flex-direction:column; gap:2px; }
.settings-nav-item { font-family:var(--font-ui); font-size:var(--fs-body); color:var(--text-secondary); text-decoration:none; padding:var(--space-2) var(--space-3); border-radius:var(--radius-control); }
.settings-nav-item:hover { color:var(--text-primary); background:var(--bg-panel-raised); }
.settings-col { min-width:0; }
#set-platform, #set-model, #set-integrations, #set-quality, #set-danger { scroll-margin-top: 84px; }

/* ── Bulk review modal (Launch All / Queue All) — panel tokens ─────────────── */
.ui-modal-overlay { display:none; position:fixed; inset:0; background:rgba(0,0,0,.55); z-index:9500; align-items:center; justify-content:center; }
.ui-modal-overlay.open { display:flex; }
.ui-modal { background:var(--bg-panel); border:1px solid var(--border-subtle); border-radius:var(--radius-panel); width:560px; max-width:94vw; max-height:82vh; overflow:auto; padding:var(--pad-panel); }
.ui-modal-head { display:flex; justify-content:space-between; align-items:center; margin-bottom:6px; }
.ui-modal-close { background:none; border:none; color:var(--text-tertiary); font-size: var(--glyph-md); cursor:pointer; line-height:1; }
.ui-modal-close:hover { color:var(--text-primary); }
.ui-modal-intro { font-size:var(--text-sm); color:var(--text-secondary); margin-bottom:12px; }
.ui-modal-list { margin-bottom:12px; }
.ui-modal-row { display:flex; align-items:flex-start; gap:9px; padding:8px 4px; border-top:1px solid var(--border-subtle); cursor:pointer; min-height:var(--row-h); box-sizing:border-box; }
.ui-modal-row:hover { background:var(--bg-panel-raised); }
.ui-modal-row input[type=checkbox] { margin-top:2px; accent-color:var(--accent); }
.ui-modal-row-body { flex:1; min-width:0; }
.ui-modal-row-label { font-size: var(--fs-label); color:var(--text-primary); }
.ui-modal-row-meta { font-family:var(--font-mono); font-size:var(--text-xs); color:var(--text-tertiary); margin-left:8px; }
.ui-modal-cost { font-family:var(--font-mono); font-size:var(--text-xs); color:var(--text-tertiary); margin-bottom:14px; }
.ui-modal-foot { display:flex; gap:10px; justify-content:flex-end; }
/* Campaign wizard on the primitive: the primitive has no sticky head/foot
   affordance, so this variant makes the shell a flex column — only .wiz-body
   scrolls, head and foot hold position naturally. Paddings/borders carry the
   old inline values verbatim. */
.ui-modal.wiz-modal { display:flex; flex-direction:column; padding:0; overflow:hidden; width:620px; max-height:88vh; }
.wiz-modal-head { padding:24px 28px 16px; border-bottom:1px solid var(--border); margin-bottom:0; flex-shrink:0; }
.wiz-kicker { font-family:var(--font-ui); font-size:var(--fs-small); color:var(--text-tertiary); margin-bottom:4px; }
.wiz-step-label { font-size: var(--fs-body); font-weight:500; color:var(--text); }
.wiz-head-right { display:flex; align-items:center; gap:12px; }
.wiz-dots { display:flex; gap:5px; }
.wiz-body { padding:28px; min-height:320px; overflow-y:auto; flex:1; }
.wiz-modal-foot { padding:16px 28px 24px; border-top:1px solid var(--border); justify-content:space-between; flex-shrink:0; }
.wiz-foot-right { margin-left:auto; display:flex; gap:10px; }
.wiz-cancel { opacity:.5; }

/* ── Client edit modal + Clients admin list ────────────────────────────────── */
.ec-modal { width:640px; }
.ec-kicker { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); margin-bottom:4px; }
.ec-section-label { font-family:var(--font-ui); font-size:var(--fs-label); font-weight:500; color:var(--text-secondary); margin:var(--space-5) 0 var(--space-3); padding-top:var(--space-4); border-top:1px solid var(--border-subtle); }
.ec-section-label:first-of-type { border-top:none; padding-top:0; margin-top:8px; }
.ec-row { margin-bottom:14px; gap:16px; }
.ec-row .field input, .ec-row .field select { width:100%; }
.ec-hint { font-weight:400; color:var(--text-tertiary); text-transform:none; letter-spacing:0; font-size:var(--fs-small); }
.ec-note { font-size: var(--fs-small); color:var(--text-secondary); background:var(--accent-muted); border:1px solid var(--border-subtle); border-radius:var(--radius-control); padding:8px 12px; margin-bottom:14px; }
.ec-check { display:flex; align-items:center; gap:8px; font-size: var(--fs-label); color:var(--text-secondary); cursor:pointer; padding-bottom:8px; }
.ec-check input { width:auto; accent-color:var(--accent); }
#ec-code[readonly] { color:var(--text-tertiary); font-family:var(--font-mono); }
.ec-test-row { display:flex; align-items:center; gap:10px; margin-bottom:8px; }
.ec-test-result { font-family:var(--font-ui); font-size:var(--fs-small); margin-bottom:var(--space-2); padding:var(--space-2) var(--space-3); background:var(--bg-panel-raised); border-radius:var(--radius-control); }
.ec-check-line { padding:2px 0; }
.ec-check-line.ok { color:var(--status-positive); }
.ec-check-line.fail { color:var(--red); }   /* a failed check is danger; --status-negative is aliased white */
.client-code { font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); font-weight:400; margin-left:8px; }
.client-col-num { font-family:var(--font-mono); font-size: var(--fs-label); color:var(--text-primary); text-align:right; }

/* ── Archived clients section (Settings → Clients) ─────────────────────────── */
.archived-clients { margin-top:18px; border-top:1px solid var(--border-subtle); padding-top:4px; }
.archived-clients summary { cursor:pointer; font-family:var(--font-mono); font-size: var(--fs-small); color:var(--text-tertiary); padding:10px 0; list-style:none; }
.archived-clients summary::before { content:'▸ '; }
.archived-clients[open] summary::before { content:'▾ '; }
.archived-clients summary:hover { color:var(--text-secondary); }
.archived-row { opacity:.75; }
.archived-row .client-name { color:var(--text-secondary); }

/* ── Danger Zone (Settings) ────────────────────────────────────────────────── */
.danger-zone { border-top:1px solid var(--negative-muted); }
.danger-row { display:flex; align-items:flex-start; justify-content:space-between; gap:var(--space-5); }
.danger-copy { max-width:560px; }
.danger-title { font-size:var(--fs-body); font-weight:500; color:var(--negative); margin-bottom:var(--space-1); }
.ui-btn.ghost.danger { color:var(--negative); border-color:var(--negative); flex-shrink:0; }
.ui-btn.ghost.danger:hover { background:var(--negative-muted); }
.settings-nav-item.danger { color:var(--negative); opacity:.8; }

/* ══ R4: THE FEATURE SWITCHES HAD NO STYLES AT ALL ═══════════════════════════════════════════
   Unit 125 built the panel and unit 120 the list before it, and neither ever wrote a rule for
   .feat-row and its parts, so the switches rendered as unstyled stacked divs: the name, the
   explanation, the state and the button all ran together on one line at the body size, with
   nothing to tell one switch from the next. That is the "cramped labels, misaligned controls"
   on this screen.

   Built as the app's row pattern, the same one .ui-feed-item and .org-mem-row use since R3:
   flat, one hairline between rows, the label level for the explanation, the controls pushed to
   the right and vertically centred against the text. */
.feat-intro { font-size:var(--fs-label); color:var(--text-secondary); line-height:1.5; margin-bottom:var(--space-3); }
.feat-picker { display:flex; align-items:center; gap:var(--space-3); margin-bottom:var(--space-4); }
.feat-picker label { margin:0; white-space:nowrap; }
.feat-picker select { width:auto; min-width:220px; }
.feat-err { font-size:var(--fs-small); color:var(--negative); margin-bottom:var(--space-3); }
.feat-list { display:flex; flex-direction:column; }
.feat-row {
  display:flex; align-items:center; gap:var(--space-3);
  padding:var(--space-3) 0;
  border-top:1px solid var(--border-subtle);
}
.feat-row:first-child { border-top:none; }
.feat-text { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
.feat-name { font-size:var(--fs-body); color:var(--text-primary); }
.feat-why { font-size:var(--fs-small); color:var(--text-tertiary); line-height:1.5; }
/* The state is the answer to "is this on", so it is the loudest thing on the row when it is on
   and the quietest when it is off. Green and grey, not the accent: this is data meaning. */
.feat-state {
  font-size:var(--fs-small); font-weight:500; letter-spacing:.06em;
  padding:2px var(--space-2); border-radius:var(--radius-pill); flex-shrink:0;
  color:var(--text-tertiary); background:rgba(255,255,255,0.06);
}
.feat-state.on { color:var(--positive); background:var(--positive-muted); }
.feat-source { font-size:var(--fs-small); color:var(--text-tertiary); flex-shrink:0; }
.feat-set {
  font-family:var(--font-ui); font-size:var(--fs-small); font-weight:500;
  padding:var(--space-1) var(--space-3); border-radius:var(--radius-control); cursor:pointer;
  background:transparent; border:1px solid var(--border-strong); color:var(--text-secondary);
  flex-shrink:0; transition:all .12s;
}
.feat-set:hover { color:var(--text-primary); background:var(--bg-panel-raised); }
.feat-set:disabled { opacity:.5; cursor:not-allowed; }
.feat-managed { font-size:var(--fs-small); color:var(--text-tertiary); line-height:1.5; margin-top:var(--space-3); }

/* ══ FRAMELESS WINDOW (Electron: win32 titleBarOverlay, macOS hiddenInset) ══
   Gated on body.wco (set when navigator.windowControlsOverlay is visible) or
   body.mac-inset (Electron UA on a Mac); both come from the index.html boot
   snippet. Browsers and old framed exes never get either class, so nothing
   below applies to them. The top strip (sidebar logo + main header) becomes
   the drag region; every interactive child opts back out. */
body.wco .main-header,
body.wco .sidebar-logo,
body.mac-inset .main-header,
body.mac-inset .sidebar-logo {
  -webkit-app-region: drag;
}
body.wco .sidebar-collapse-btn,
body.wco #main-actions,
body.wco #main-actions button,
body.wco #site-mode-ctrl,
body.wco .sm-btn,
body.wco #client-switcher-btn,
body.wco #client-dropdown,
body.wco #org-switcher-btn,
body.wco #org-dropdown,
body.mac-inset .sidebar-collapse-btn,
body.mac-inset #main-actions,
body.mac-inset #main-actions button,
body.mac-inset #site-mode-ctrl,
body.mac-inset .sm-btn,
body.mac-inset #client-switcher-btn,
body.mac-inset #client-dropdown,
body.mac-inset #org-switcher-btn,
body.mac-inset #org-dropdown {
  -webkit-app-region: no-drag;
}
/* Clear the native overlay buttons in the top-right corner (Windows only). */
body.wco .main-header { padding-right: 160px; }
/* macOS hiddenInset: the traffic lights sit at 16,16 (main.js trafficLightPosition).
   The sidebar header drops below them and the collapse button rides with it. No
   right-hand clearance: there are no overlay buttons on that side. */
body.mac-inset .sidebar-logo { padding-top: 48px; }
body.mac-inset .sidebar-collapse-btn { top: 48px; }
/* The collapsed rail (44px) is narrower than the lights, so the title clears them. */
body.mac-inset .sidebar.sidebar-collapsed + .main .main-header { padding-left: 88px; }

/* Two-factor enrol: GoTrue's QR is an inline SVG, rendered as markup inside this box */
.mfa-qr { width: 160px; height: 160px; background: #fff; padding: 6px; border-radius: 6px; box-sizing: border-box; flex: none; }
.mfa-qr svg, .mfa-qr img { display: block; width: 100%; height: 100%; }

/* What's new: the release card over the app and the history under Settings. Containment as
   .ui-panel; the image sits in its own bordered panel with the top-edge light. No color. */
.wn-backdrop { position: fixed; inset: 0; z-index: 5000; background: rgba(0,0,0,0.62); display: flex; align-items: center; justify-content: center; padding: 24px; }
.wn-backdrop[hidden] { display: none; }
.wn-card { width: min(560px, 100%); max-height: calc(100vh - 48px); overflow: auto; background: var(--bg-panel); border: 1px solid rgba(255,255,255,0.10); border-radius: 16px; box-shadow: inset 0 1px 0 rgba(255,255,255,0.06); padding: 22px 24px 20px; }
.wn-note { background: var(--bg-panel); border: 1px solid rgba(255,255,255,0.10); border-radius: 16px; box-shadow: inset 0 1px 0 rgba(255,255,255,0.06); padding: 20px 22px 16px; max-width: 640px; }
.wn-note + .wn-note { margin-top: 16px; }
.wn-eyebrow { font-family: var(--font-mono); font-size: var(--fs-small); color: var(--text-tertiary); }
.wn-title { font-family: var(--font-ui); font-size: var(--fs-title); font-weight:500; letter-spacing: -0.02em; color: var(--text-primary); margin: 4px 0 12px; }
.wn-figure { margin: 0 0 14px; padding: 6px; background: var(--bg-panel-raised); border: 1px solid rgba(255,255,255,0.10); border-radius: 16px; box-shadow: inset 0 1px 0 rgba(255,255,255,0.06); }
.wn-figure img { display: block; width: 100%; height: auto; border-radius: 10px; }
.wn-summary { font-size: var(--text-base); color: var(--text-secondary); line-height: 1.5; margin: 0 0 12px; }
.wn-body { font-size: var(--text-base); color: var(--text-primary); line-height: 1.55; }
.wn-body h2, .wn-body h3, .wn-body h4 { font-family: var(--font-ui); font-weight:500; letter-spacing: -0.015em; color: var(--text-primary); margin: 14px 0 4px; }
.wn-body h2 { font-size: var(--fs-body); } .wn-body h3 { font-size: var(--fs-body); } .wn-body h4 { font-size: var(--fs-label); }
.wn-body p { margin: 0 0 10px; } .wn-body ul { margin: 0 0 10px; padding-left: 20px; } .wn-body li { margin: 3px 0; }
.wn-body code { font-family: var(--font-mono); font-size: var(--fs-label); background: var(--bg-panel-raised); border-radius: 4px; padding: 1px 5px; }
.wn-body a { color: var(--text-primary); text-decoration: underline; text-underline-offset: 2px; }
.wn-body img { display: block; max-width: 100%; margin: 10px 0; padding: 6px; background: var(--bg-panel-raised); border: 1px solid rgba(255,255,255,0.10); border-radius: 16px; box-shadow: inset 0 1px 0 rgba(255,255,255,0.06); }
.wn-actions { display: flex; justify-content: flex-end; margin-top: 8px; }

/* ── Assignment and comments on job rows: two people can work the same queue ── */
/* The chips match the app's pills: 12px UI text, text-secondary on bg-panel-raised, the 0.10 white border. */
.assign-chip, .comment-chip { display: inline-flex; align-items: center; gap: 6px; padding: 2px 9px 2px 3px; border: 1px solid rgba(255, 255, 255, 0.10); border-radius: var(--radius-pill); background: var(--bg-panel-raised); color: var(--text-secondary); font-family: var(--font-ui); font-size: var(--fs-label); font-weight: 500; line-height: 1.4; cursor: pointer; vertical-align: middle; white-space: nowrap; }
.assign-chip:hover, .comment-chip:hover { color: var(--text-primary); }
.assign-chip.assigned { color: var(--text-primary); }
.assign-chip .org-mem-avatar { width: 16px; height: 16px; font-size: var(--fs-small); }
.assign-chip.unassigned .assign-name { color: var(--text-secondary); }
.assign-empty { background: transparent; border: 1px dashed rgba(255, 255, 255, 0.25); }
.comment-chip { padding: 2px 9px; position: relative; }
.comment-chip .comment-glyph { color: var(--text-secondary); }
.comment-chip.unread { color: var(--text-primary); }
.comment-chip.unread .comment-glyph { color: var(--text-primary); }
.comment-dot { position: absolute; top: -3px; right: -3px; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
/* Where the chips sit in a row: their own cell on History; one non-wrapping span beside the keyword elsewhere. */
.hist-owner { white-space: nowrap; }
.hist-owner .assign-chip { margin-right: 4px; }
.row-chips { white-space: nowrap; margin-left: 6px; }
.assign-list { display: flex; flex-direction: column; gap: 4px; }
.assign-row { display: flex; align-items: center; gap: 10px; padding: 6px 8px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); color: var(--text); cursor: pointer; text-align: left; font: inherit; }
.assign-row:hover { background: var(--accent-muted); }
.assign-row .assign-role { margin-left: auto; font-family: var(--mono); font-size: var(--fs-small); color: var(--text-secondary); }
.comments-thread { max-height: 360px; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; }
.comment-row { display: flex; gap: 10px; align-items: flex-start; }
.comment-row.reject .comment-body { border-left: 2px solid var(--text-sub); padding-left: 8px; }
.comment-meta { font-family: var(--mono); font-size: var(--fs-small); color: var(--text-secondary); margin-bottom: 2px; }
.comment-kind { color: var(--text-sub); }
.comment-body { font-size: var(--fs-label); line-height: 1.5; color: var(--text); white-space: pre-wrap; }
.comments-input { flex: 1; resize: vertical; min-height: 44px; }
.ap-reject-note { margin-top: 6px; font-size: var(--fs-small); line-height: 1.45; color: var(--text); border-left: 2px solid var(--text-sub); padding-left: 8px; }
.ap-reject-who { color: var(--text-secondary); font-family: var(--mono); font-size: var(--fs-small); }

/* The roster as a member sees it: the role as a label where owners and admins get the dropdown. */
.org-mem-rolelabel { font-family: var(--font-ui); font-size: var(--fs-small); color: var(--text-secondary); }

/* ── Unit 60: the help surface ─────────────────────────────────────────────
   A small ? beside the screen title, and a side panel holding that screen's text.

   A SIDE PANEL AND NOT A MODAL, on purpose: the point of the text is to be read against the
   screen it describes, and a modal covers the thing you are trying to understand. It is fixed to
   the right edge, slides in, and leaves the layout alone so opening it never reflows the screen
   underneath. */
.help-dot {
  flex-shrink: 0;
  width: 16px; height: 16px;
  border-radius: 50%;
  border: 1px solid var(--border-heavy);
  background: transparent;
  color: var(--text-dim);
  font-family: var(--font-ui);
  font-size: var(--fs-small); line-height: 1;
  cursor: pointer;
  padding: 0;
  align-self: center;
  transition: color .15s ease, border-color .15s ease;
}
.help-dot:hover { color: var(--text); border-color: var(--text-sub); }
.help-dot:focus-visible { outline: 2px solid var(--text-sub); outline-offset: 2px; }

.help-panel {
  position: fixed;
  top: 0; right: 0;
  width: min(380px, 92vw);
  height: 100%;
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: -18px 0 40px rgba(0, 0, 0, .35);
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform .18s ease;
  z-index: 1200;
  /* Not reachable by keyboard or screen reader while closed. A panel that is merely off screen is
     still in the tab order, which is how a hidden surface becomes a trap. */
  visibility: hidden;
}
.help-panel.open { transform: translateX(0); visibility: visible; }
.help-panel-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
  padding: 18px 20px 12px;
  border-bottom: 1px solid var(--border);
}
.help-panel-title { font-size: var(--fs-body); font-weight:500; letter-spacing: -0.01em; }
.help-panel-close {
  background: transparent; border: 0; cursor: pointer;
  color: var(--text-dim); font-size: var(--glyph-md); line-height: 1; padding: 0 2px;
}
.help-panel-close:hover { color: var(--text); }
.help-panel-body {
  padding: 16px 20px 24px;
  font-size: var(--fs-label);
  line-height: 1.65;
  color: var(--text-sub);
  overflow-y: auto;
}

/* ══ Unit 70: the Versions view. Read only: a timeline on the left, one body or a diff
   on the right. No restore control, deliberately: restoring is per job and lives on the
   edit page, and most entries here store a text projection rather than the page itself. */
.pv-modal { width:min(1100px,94vw); max-height:88vh; display:flex; flex-direction:column; padding:0; }
.pv-top { display:flex; align-items:center; justify-content:space-between; gap:12px;
  padding:14px 16px; border-bottom:1px solid var(--border); }
.pv-title { font-weight:500; font-size: var(--fs-label); }
.pv-grid { display:grid; grid-template-columns:minmax(300px,42%) 1fr; gap:0; min-height:0; flex:1; }
.pv-list { overflow:auto; border-right:1px solid var(--border); padding:6px; }
.pv-bodybox { overflow:auto; padding:12px 14px; min-width:0; }
.pv-row { display:grid; grid-template-columns:54px 1fr; gap:2px 8px; width:100%; text-align:left;
  background:none; border:1px solid transparent; border-radius:4px; padding:7px 8px;
  cursor:pointer; color:var(--text); font:inherit; }
.pv-row:hover { background:var(--bg-hover); }
.pv-row.selected { border-color:var(--accent); background:var(--bg-hover); }
.pv-pos { grid-row:1/3; font-family:var(--mono); font-size: var(--fs-small); color:var(--text-dim); padding-top:2px; }
.pv-src { font-size: var(--fs-label); font-weight:500; }
/* Unit 71: one meta cell, not four. The four separate spans each took their own grid cell and
   stacked, so the ::after separators trailed at the ends of lines and an absent label left a gap.
   The row joins its own parts now, so the separator lives in the markup and only ever sits between
   two parts that are both present. */
.pv-meta { font-size: var(--fs-small); color:var(--text-sub); }
.pv-gone { color:var(--negative); }
.pv-hint, .pv-empty { font-size: var(--fs-label); color:var(--text-sub); padding:10px 4px; line-height:1.5; }
.pv-head { font-size: var(--fs-small); color:var(--text-sub); margin-bottom:8px; font-family:var(--mono); }
.pv-text, .pv-diff { font-family:var(--mono); font-size: var(--fs-small); line-height:1.55; white-space:pre-wrap;
  word-break:break-word; margin:0; }
.pv-add { background:rgba(34,153,84,0.16); display:block; }
.pv-del { background:rgba(192,57,43,0.16); display:block; }
.pv-same { color:var(--text-dim); display:block; }
/* The one sentence a cross-shape pair gets. Not an error colour: it is a fact about how the
   two were stored, not something the operator did wrong. */
.pv-nocompare { font-size: var(--fs-label); color:var(--text-sub); line-height:1.6; padding:10px;
  border:1px dashed var(--border); border-radius:4px; }
