/* ═══════════════════════════════════════════════════════════════════════════
   BOARDROOM — THE APPROVED DESIGN SYSTEM
   ═══════════════════════════════════════════════════════════════════════════

   Source of truth: mockups/pack-00-task-first-navigation.html,
   mockups/pack-01-crm-pipeline.html, mockups/pack-01-filter-drawer.html,
   mockups/pack-02-client-workspace.html, mockups/pack-02-call-intelligence.html,
   mockups/layout-contract.html. Values below are read off those files, not
   chosen nearby.

   WHY A FILE AND NOT AN EDIT IN PLACE. There are already three global
   stylesheets and each was created to get the last word over the one before it.
   Editing redesign.css in place would mean auditing 5,300 lines to find which
   of them the new geometry contradicts. This loads last and does two things,
   in this order:

     1. RE-POINTS THE EXISTING TOKENS at the approved palette and rhythm. Every
        screen in the product draws from --rp-*; moving those moves all of them
        at once, which is what "one design across the whole product" means in
        practice. Nothing is restyled screen by screen to look like the pack —
        the pack IS the token set now.

     2. ADDS the geometry the new screens need, under .pk-*, which is a
        namespace no legacy rule can reach.

   The one thing this file must never do is decorate the old look. Where a
   legacy rule and one of these disagree, this one is the approved package.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ВЫСОТА ПАНЕЛИ ВОРОНКИ — ОДНИМ ЧИСЛОМ НА ВСЮ СТРОКУ.
     Владелец просил уменьшить эти кнопки дважды: 21 августа (44 → 34) и
     30-го (34 → 30). В первый раз число пришлось править в шести местах, и
     одно — подпись воронки — забыли: у пространства с единственной воронкой
     панель ещё месяц оставалась высокой из-за одной этой строки. Теперь
     число одно, и следующий, кто его тронет, подвинет всю строку целиком. */
  --pk-row-h: 30px;
  /* ── the approved palette ─────────────────────────────────────────────── */
  --pk-bg: #0b0f16;
  --pk-panel: #121821;
  --pk-card: #182029;
  --pk-card-hi: #1c2532;
  --pk-line: rgba(148, 178, 255, 0.10);
  --pk-line-2: rgba(148, 178, 255, 0.18);
  --pk-text: #e9eef7;
  --pk-muted: #94a3b8;
  --pk-dim: #6b7a90;
  --pk-faint: #55637a;
  --pk-blue: #2f7bff;
  --pk-blue-soft: rgba(47, 123, 255, 0.13);
  --pk-blue-line: rgba(47, 123, 255, 0.40);
  --pk-high: #f87171;
  --pk-med: #60a5fa;
  --pk-low: #4ade80;
  --pk-green: #4ade80;
  --pk-amber: #fbbf24;

  /* ── the ten stage-name colours ────────────────────────────────────────
     Offered in pipeline settings, applied to a stage NAME and nothing else.
     They are a separate scale from the three above on purpose.

     --pk-green / --pk-amber / --pk-high are the product's SEMANTIC set: they
     mean live, attention and critical, and they are only ever spent on filled
     shapes — a StatusChip, a priority dot. These ten are spent only on text.
     So the two scales differ in form before they differ in hue, and a client
     who colours «Оплата» is decorating a label, not lighting an alarm.

     Hue was then checked as well, because form alone is a thin defence. Every
     entry is at least 102 away (redmean) from the nearest semantic colour, so
     the mint is visibly not the live green and the sand is visibly not the
     attention amber. There is deliberately NO red: rose and coral are pushed
     toward magenta and orange respectively, well clear of #f87171, so no stage
     name can be mistaken for a failure.

     Contrast was checked against both surfaces a stage name can sit on,
     --pk-panel (#121821) and --pk-card (#182029). The worst of the ten is
     8.02:1; 17px/600 text needs 4.5:1. Any replacement must clear that bar —
     the check lives in scripts/test-stage-colours.mjs and runs in the gate. */
  --pk-stage-blue:    #7FB3FF;
  --pk-stage-indigo:  #A5A8FF;
  --pk-stage-violet:  #C39BFF;
  --pk-stage-magenta: #F09BE0;
  --pk-stage-rose:    #FF9BB5;
  --pk-stage-coral:   #FFA98A;
  --pk-stage-sand:    #E8C46A;
  --pk-stage-lime:    #C3DB6A;
  --pk-stage-mint:    #6FE3B4;
  --pk-stage-teal:    #6FDCE3;

  /* ── the approved geometry ────────────────────────────────────────────── */
  /* «первый блок... сделай компактнее ширину, тем самым основной рабочий блок
     станет больше», 2026-08-21: was 220px. Still comfortably fits every rail
     label ("Медиафабрика", "Администрирование") — just narrower than the
     220px floor this comment used to call unmovable. */
  --pk-nav-w: 200px;        /* global rail — never collapses with a panel      */
  --pk-local-w: 300px;      /* local section rail: Settings, AI Agents, …      */
  --pk-client-w: 360px;     /* Client Workspace panel                          */
  --pk-queue-w: 300px;      /* Dialogues / Voice queue                         */
  --pk-drawer-w: 380px;     /* right contextual drawer                         */
  --pk-filter-w: 360px;     /* filter drawer                                   */
  --pk-top-h: 72px;
  --pk-pad: 32px;
  /* «и вот карточки чуть чуть уже чтобы больше поместилось на экране»,
     2026-08-21: narrowed to the floor this file already documented instead of
     sitting 16px above it, so more stages fit before the board scrolls at all. */
  --pk-col: 280px;          /* kanban column, floor 280                        */
  --pk-gap: 14px;

  /* ── EVERY SCREEN MOVES WITH THESE ────────────────────────────────────────
     The product's existing surfaces all draw from --rp-*. Re-pointing them here
     is what makes one approved system apply to pages this pass has not opened
     yet, instead of leaving them on the older, denser palette and calling the
     product consistent. */
  --rp-bg: var(--pk-bg);
  --rp-rail: #0d121a;
  --rp-panel: var(--pk-panel);
  --rp-panel-2: var(--pk-card);
  --rp-line: var(--pk-line);
  --rp-line-2: var(--pk-line-2);
  --rp-ink: var(--pk-text);
  --rp-ink-2: var(--pk-muted);
  --rp-ink-3: var(--pk-dim);
  --rp-blue: var(--pk-blue);
  --rp-blue-soft: var(--pk-blue-soft);
  --rp-green: var(--pk-green);
  --rp-amber: var(--pk-amber);

  /* Rounder and calmer than the dense system it replaces: 8–14, per the pack. */
  --rp-r: 14px;
  --rp-r-sm: 10px;

  /* AIR. The old rhythm topped out at 30px and the shell padding was tuned for
     a 176px rail. The approved shell is 28–32 of content padding against a
     220px rail, and the owner's instruction for the whole product is space. */
  --rp-1: 4px; --rp-2: 9px; --rp-3: 14px; --rp-4: 18px; --rp-5: 24px; --rp-6: 32px;

  /* THE GLOBAL RAIL IS 220 AND DOES NOT COLLAPSE WITH A CONTEXT PANEL.
     It was 176 — measured against two reference PNGs that predate this pack.
     The approved rail is 220–240 and carries a two-line brand block. */
  --rp-rail-w: var(--pk-nav-w);
}

/* ═══ SHELL ══════════════════════════════════════════════════════════════ */

body { background: var(--pk-bg); color: var(--pk-text); }

/* NO PAGE EVER SCROLLS SIDEWAYS. The layout contract says it in words; this is
   the enforcement. Horizontal scrolling belongs to the board's columns and to
   nothing else, so it is granted there explicitly and denied here globally. */
.app-shell { max-width: 100%; overflow-x: clip; }

/* ── THE SHELL IS THE VIEWPORT, AND THE PAGE SCROLLS INSIDE IT ─────────────
   The document itself scrolled: the rail, the top bar and the page header all
   slid away as a board grew, and a five-column pipeline at 1920 ran 130px past
   the fold with its toolbar somewhere above the window. That is the wrong
   scroll — the layout contract says scrolling happens only inside assigned
   regions, and the shell is not one of them.
   min-height:0 the whole way down, or a flex child measures its own content
   and grows the shell instead of scrolling within it. */
html, body.has-rail { height: 100%; overflow: hidden; }
.app-shell { height: 100vh; min-height: 0; overflow: hidden; }
.app-shell > * { min-height: 0; }
main.workspace {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  padding-bottom: 0;
}
/* The chrome of a page keeps its height; the page body takes the rest. */
main.workspace > * { flex: 0 0 auto; }
main.workspace > .page-stack {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  /* BORO'S CORNER IS RESERVED BY THE PAGE, NOT BY BORO.
     He is position:fixed and mounted outside the render tree — deliberately, so
     he survives a full-DOM repaint — which means nothing in the page can flow
     around him. Whatever is beneath him is simply covered.
     Measured at the owner's 1536x830: his resting box is [1434, 706, 90, 112]
     and `document.elementsFromPoint` at its centre returned
     ARTICLE.control-card "Meeting schedule". The old --rp-5 reserve was 32px
     short of his 112px + 12px gap, so the last row of every scrolled page ended
     underneath him.
     This closes the END of the page. It does not and cannot close mid-scroll:
     a fixed companion passes over scrolling content by definition, and putting
     him somewhere he never overlaps means giving him a column of his own —
     which is a design decision about where the companion lives, not a bug fix.
     See the session report. */
  padding-bottom: 132px;
  /* A REGRESSION THIS FILE CAUSED, FIXED WHERE IT WAS CAUSED.
     `.page-stack` is `display: grid` with implicit auto rows. Giving it
     `flex: 1 1 auto` — which is what makes the page scroll inside the shell
     instead of scrolling the shell — also made it TALLER than its content on
     any short page, and a grid taller than its content stretches its auto rows
     to fill. Measured on Voice: two cards holding 105px of text rendered 294px
     tall, so the screen read as three boxes that had failed to load rather than
     as a page with room to breathe. Rows size to their content; the leftover
     height stays leftover. */
  align-content: start;
}

/* ── the page header: a crumb, not a cover ───────────────────────────────── */
.pk-header {
  display: flex; align-items: center; gap: 14px;
  /* ONE ROW HEIGHT, SO THE CONTENT BELOW ALWAYS STARTS AT THE SAME PLACE.
     Measured at 1536 before this rule: 41px with a title alone, 50px with a
     primary action, 54px with a crumb parent — so the first card of the page
     landed at three different heights depending on which optional slots that
     page happened to fill. "Inconsistent spacing to the content beneath" is
     half of the defect; a title that is always in the same place is worth
     little if the thing under it is not.
     36px is the primary button, the tallest thing the row may legitimately
     carry, plus the 14px inset. Nothing here asserts a height on any CHILD. */
  /* «давай уменьшим 2 отделения... нижнее пространство станет больше»,
     2026-08-21: was 50px/14px, then 38px/10px — shrunk again per the same
     instruction, this time pointed at this exact block. .pk-back-button's
     margin-top below must track this same number, or the back arrow drifts
     off the crumb's line. */
  min-height: 34px;
  /* .workspace already pads the content column; a second inset here would
     push the crumb out of line with the toolbar under it. */
  padding: 8px 0 0;
  /* ONE GAP TO THE CONTENT, STATED HERE RATHER THAN INHERITED.
     `.workspace-header` picked up `margin-bottom: var(--rp-4)` from
     redesign.css, where --rp-4 is 16px — but this file redefines --rp-4 as
     18px, so the gap under the header was whichever token won the cascade
     that day rather than a number anyone chose. It is now --rp-3, declared
     against the same scale the cards below it use, so the first row of every
     page begins the same distance under its title. On the pipeline, where the
     board pays for every pixel above it, that is 4px back. */
  margin-bottom: var(--rp-3);
  background: none; border: 0;
}
.pk-crumb { display: flex; align-items: baseline; gap: 9px; min-width: 0; }
.pk-crumb-sec {
  border: 0; background: none; padding: 0;
  color: var(--pk-dim); font-size: 13px; cursor: pointer;
}
/* THE CRUMB PARENT IS TEXT THAT HAPPENS TO BE CLICKABLE.
   It is a <button> for keyboard and screen-reader reasons, and this codebase
   carries a legacy bare `button { min-height: 40px }` — measured, not assumed:
   getComputedStyle on `.pk-crumb-sec` returned minHeight "40px", which is why
   a 13px word was making the whole header row 13px taller than the same row
   without a parent. `min-height: 0` is the instrument that works here; an
   explicit `height` does NOT, because min-height beats height at any
   specificity. That mistake has already cost this project a day and a set of
   14x40 ellipses where colour swatches should have been. */
.app-shell .pk-header .pk-crumb-sec { min-height: 0; }
.pk-crumb-sec:hover:not(:disabled) { color: var(--pk-muted); }
/* A crumb parent with no route is a label, not a control. It must not offer a
   hand cursor or a hover state for a click that goes nowhere — "Action Center"
   was a breadcrumb parent that is not a destination anywhere in the product. */
.pk-crumb-sec:disabled { cursor: default; opacity: 1; }
.pk-crumb-sep { color: var(--pk-faint); font-size: 11px; }
/* THE ONE TITLE SIZE. Every screen's name is 18px here and nowhere else.
   `.pk-title` is an h1 as of the PageHeader component, so the browser's own
   2em/0.67em-margin default has to be overridden explicitly — it is not
   inherited away, and a bare `font-size` would have left the margins in place
   and pushed the row 30px taller than the screens that still used a span.

   SPECIFICITY, NOT ORDER, DECIDES THIS ONE — measured, not reasoned.
   The first draft used `.pk-crumb-cur, .pk-title` (0,1,0) and this file loads
   last, so it looked settled. The running page said 30px: redesign.css carries
   `.app-shell .workspace-header h1 { font-size: clamp(23px, 2.3vw, 30px) }`
   at (0,2,1), and the element became an h1 the moment it stopped being a span.
   Every screen would have shipped a 30px title in a row sized for 18px — the
   defect this component exists to close, reintroduced by the fix for it.
   `.app-shell .pk-header .pk-title` is (0,3,0) and clears it on class count.
   Do not lower this back to a single class. */
.app-shell .pk-header .pk-title,
.pk-crumb-cur, .pk-title {
  margin: 0;
  font-size: 18px; font-weight: 600; letter-spacing: -0.01em; color: var(--pk-text);
  line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The state of the page, beside its name — the third slot of the header, and
   the only place a page-level chip belongs. Baseline-aligned rather than
   centred, because the row is a baseline row. */
.pk-header-status { display: inline-flex; align-items: center; flex: 0 0 auto; }
.pk-header-action { margin-inline-start: auto; flex: 0 0 auto; }

/* ── the equal-height card shell ──────────────────────────────────────────
   A ROW OF CARDS SHOULD READ AS A ROW.

   Measured at 1536 on 2026-08-16: /roi's three-card row rendered 103, 103 and
   72px; /settings' two panels 215 and 159; /setup's two choice cards were the
   same height but their footnotes and buttons landed 15px apart, because the
   left body wrapped to two lines and the right did not.

   Those are two different faults and they need two different rules:

     the BOX  ragged because the container was told `align-items: start`, so a
              card stopped at its own content instead of filling its row. Fixed
              on the CONTAINER, never by pinning a height on a card — a height
              on a card is a promise about content the card does not make, and
              `min-height` on a grid item is how a 34px box came to hold 93px
              of content in this codebase.

     the FOOT ragged because the card's action is simply the last thing in the
              flow, so it sits wherever the paragraph above it ended. Fixed by
              making the card a column and giving the action `margin-top: auto`,
              which pushes it to the bottom of whatever height the row settled
              on. No height is asserted anywhere.

   `.pk-cardrow` / `.pk-card-foot` are the shell for new work. The selector list
   under them retrofits the rows that already exist, so a call site does not
   have to be edited to stop being ragged. */
.pk-cardrow { display: grid; gap: var(--rp-3, 14px); align-items: stretch; }
.pk-cardrow > * { min-width: 0; display: flex; flex-direction: column; }
/* The floor of a card. Everything that qualifies the action travels with the
   action — a footnote anchored on its own is a footnote stranded mid-card,
   which is what anchoring only the button produced on /setup (22px apart, up
   from the 11px it was meant to fix). No height is asserted; `auto` simply
   collects whatever slack the row settled on, above this block. */
.pk-card-foot { margin-top: auto; display: grid; gap: 10px; align-content: end; }

/* Rows that were told to stop at their content. Stretch is the grid default;
   these had opted out of it. */
.set13,
.detail-grid,
.detail-grid.trio,
.setup-choice-grid,
.setup-two-column,
.billing-plan-grid,
.billing-control-grid { align-items: stretch; }

/* Cards whose action floated. `space-between` was distributing the slack
   BETWEEN the paragraph and the footnote as well as below it, which is why one
   card's footnote sat 15px lower than its neighbour's on /setup. Anchoring the
   last child instead leaves the slack in exactly one place: above the action,
   where nobody can see it. */
.setup-choice-card,
.billing-plan-card { justify-content: flex-start; }
.setup-choice-card > :last-child,
.billing-plan-card > :last-child { margin-top: auto; }

/* ═══ THE CRM PIPELINE — Pack 01 ═════════════════════════════════════════
   THE LAYOUT CONTRACT, in one rule.

     default      centre minmax(0,1fr)
     drawer open  centre minmax(0,1fr) · drawer 360

   The centre is ALWAYS minmax(0,1fr) and takes back every pixel a closed panel
   gives up. The drawer is a COLUMN of this grid — position:static, never an
   overlay over the board — because a filter you cannot read the board through
   is a filter you apply blind. A closed panel is 0px; there is no intermediate
   rail. */
.pk-page {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  align-items: stretch;
  min-height: 0;
  min-width: 0;
  height: 100%;
}
.pk-page.has-drawer { grid-template-columns: minmax(0, 1fr) var(--pk-filter-w); }
.pk-page > * { min-width: 0; min-height: 0; }
/* ФИЛЬТРЫ CRM НА ТЕЛЕФОНЕ (24.09.2026, мобильный проход; замер нажатием на
   «Фильтры», 375×812). Колонка фильтров — 360 px и 12 px отступа, а страница —
   337: доска сжималась до нуля, а сама панель уходила за правый край на 55 px
   — «Закрыть» и «Применить» наполовину за краем. На телефоне панель — во всю
   ширину вместо доски (доска и так была нулевой ширины); «Закрыть» и
   «Применить» возвращают её. На рабочем столе колонка остаётся колонкой
   (ниже, «THE DRAWER STAYS A COLUMN»). */
@media (max-width: 560px) {
  .pk-page.has-drawer { grid-template-columns: minmax(0, 1fr); }
  .pk-page.has-drawer > .pk-centre { display: none; }
  .pk-page.has-drawer > .pk-drawer { width: auto; margin-inline-start: 0; }
}

/* THE PIPELINE FILLS THE FOLD AND SCROLLS NOWHERE.
   The board's columns scroll sideways and each column scrolls its own cards;
   the page around them does neither. Anything the CRM route carries below the
   board — the external-CRM line a client sees — keeps its height and the board
   takes what is left. */
.page-stack.crm-page {
  display: flex;
  flex-direction: column;
  gap: var(--rp-3);
  min-height: 0;
  height: 100%;
  overflow: hidden;
  /* NO SECOND INSET. .workspace pads the content column already; padding here
     as well cost the board 64px at every width — enough that the fifth stage
     no longer fitted at 1920 and the column scrolled for want of 16px. */
  padding: 0 0 6px;
}
.page-stack.crm-page > * { flex: 0 0 auto; min-width: 0; }

/* THE BOARD IS NOT THE SHOCK ABSORBER.  Measured 2026-08-15, admin view, 53
   deals: this column has a DEFINITE height (924px at 1920, 844px at 1600) and
   every sibling the CRM route carries — the snapshot banner, the four audit
   tiles, the reconciliation card — is `flex: 0 0 auto`. They therefore claim
   their height first, 414-448px of it, and the board, as the only flexible
   item, absorbed the entire shortfall: 444px at 1920, 330px at 1600, and on a
   shorter viewport nothing at all. That is the "thin blue bar under the
   toolbar" the owner photographed — the board crushed to its top edge while
   the legacy cards took the page.

   Nothing reported it, either, because the board scrolls INSIDE itself: its
   scrollHeight always equals its height, so it never signals that it wanted
   more room. A layout can be silently wrong and still pass every overflow
   check.

   `flex-shrink: 0` is the whole fix. The board keeps the full fold it is
   promised two rules above, and anything else the route carries overflows
   below it — where `overflow-y: auto` (inherited from `main.workspace >
   .page-stack`) scrolls it, instead of the board paying for it. No minimum
   height, no viewport magic number: the fold is `height: 100%` of a container
   whose height is already definite.

   ── 2026-08-16: THE BASIS WAS `auto`, AND THAT IS WHY «ПРИМЕНИТЬ» WAS OFF THE
   SCREEN. ──────────────────────────────────────────────────────────────────

   «справа выбор есть, но когда выбрал… не нажимается, то есть не сохраняется —
   выбирать могу, сохранять не могу.» The Apply handler was never the problem:
   it copies the draft by value into a patch and calls crmView. The button was
   simply not on the screen.

   `flex: 1 0 auto` resolves its basis from `height: 100%` — but that percentage
   is INDEFINITE here (main.workspace has no specified height), so the basis
   falls back to `content`. With `flex-shrink: 0` on top, .pk-page then takes
   its tallest column's intrinsic height and never comes back down. The filter
   drawer's chip list is that tallest column, so opening the drawer grew the
   page to fit it — which also meant `.pk-drawer-body { overflow-y: auto }`
   never engaged, because the drawer was never constrained. Nothing scrolled
   inside; the whole page grew instead.

   Measured at 1536x864, drawer open, silence panel showing:

     scrollport            766 px      .pk-page   1232 px
     drawer body           scrollHeight 1099 = clientHeight 1099 (no scrollbar)
     .pk-drawer-foot       top 1376    569 px below the fold
     click at «Применить»  landed on a .pk-opt chip

   `flex: 1 0 0` gives the basis a definite zero and lets `flex-grow` hand the
   page exactly the fold that is left. The board still cannot be shrunk by a
   sibling — grow only ever distributes free space — and everything downstream
   becomes definite, so the drawer body finally scrolls inside itself. Same
   viewport, after:

     scrollport overflow   647 px → 0 px   (one scroll container, as promised)
     .pk-page              585 px          board 585 px on a clean day, 703 px
     drawer body           1099 → 452 px visible, own scrollbar
     «Применить»           top 744, inside the fold; the hit test lands on it

   The trade-off has moved since `1 0 auto` was written. Back then the admin
   audit stack rendered EXPANDED by default and took 414-448px, so letting it
   push the board off the fold was the lesser evil. It is a collapsed 44px
   `<details>` now. Expanded deliberately it does still squeeze the board (214px
   at 414px of diagnostics, measured) — but that is one admin's reversible
   click, not the default every client saw. dev/crm-filter-drawer-harness.html
   reports all of it in one page load. */
.page-stack.crm-page > .pk-page { flex: 1 0 0; min-height: 0; }

/* The admin audit stack, closed: one quiet row under the board. It must read as
   an engineer's drawer, not as an unfinished section of the client's screen. */
.crm-admin-audit {
  border: 1px solid var(--pk-line, rgba(255, 255, 255, 0.08));
  border-radius: var(--rp-r, 10px);
  background: var(--pk-card, rgba(255, 255, 255, 0.02));
}
.crm-admin-audit > summary {
  padding: 12px 14px;
  color: var(--pk-dim, rgba(255, 255, 255, 0.55));
  font-size: 11.5px;
  cursor: pointer;
  list-style: none;
}
.crm-admin-audit > summary::-webkit-details-marker { display: none; }
.crm-admin-audit > summary::before { content: "▸ "; }
.crm-admin-audit[open] > summary::before { content: "▾ "; }
.crm-admin-audit > summary:hover { color: var(--pk-text, #fff); }
.crm-admin-audit[open] > summary { border-bottom: 1px solid var(--pk-line, rgba(255, 255, 255, 0.08)); }
/* The stack keeps its own rhythm once opened. */
.crm-admin-audit > :not(summary) { margin: var(--rp-3, 14px); }

/* min-height:0 the whole way down, or flex:1 measures the content and the board
   grows past the fold instead of scrolling inside itself. */
.pk-centre {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  gap: var(--pk-gap);
}

.pk-note { color: var(--pk-muted); font-size: 14px; padding: var(--pk-pad) 0; }
.pk-note-bad { color: var(--pk-high); }

/* Строка свежести над доской (25.09.2026, BoardFreshness в CrmPipelinePage.js):
   «данные на 14:05 — обновляем…», неудачное обновление с «Повторить»,
   догружающиеся оценки. Не растёт вместе с доской и не сдвигает её больше
   чем на строку. */
.crm-fresh { flex: 0 0 auto; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.crm-fresh-line { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 2px 0; font-size: 13px; }
.crm-fresh-line .compact-button { flex: 0 0 auto; }
.crm-fresh-quiet { font-size: 12px; }

/* ── the toolbar ─────────────────────────────────────────────────────────
   PINNED. It is not part of the scrolling region and never scrolls sideways
   with the board: flex:0 0 auto keeps it out of the board's growth. The search
   is the only element allowed to give up width, and `+ New lead` is the only
   one that may never shrink — so it cannot be pushed off the right edge no
   matter what else is in the row. */
.pk-bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  flex-wrap: nowrap;
}

.pk-ctl {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  /* «карточки по верхним двум блокам… сократить», 2026-08-21: was 44px, along
     with every other control in this row (search, nav stepper, primary
     button) so the whole toolbar shrinks as one, not just its label. */
  height: var(--pk-row-h);
  /* «Сделай такие же маленькие, как сосед», 30 августа. Высота у всей строки
     уже общая; тяжёлыми «Filter» и «More» делали боковые поля и кегль — рядом
     с компактной группой стрелок (её поля 4px) они читались крупнее. */
  padding: 0 9px;
  border: 1px solid var(--pk-line-2);
  border-radius: 11px;
  background: var(--pk-panel);
  color: var(--pk-text);
  font-size: 13px;
  white-space: nowrap;
  cursor: pointer;
}
.pk-ctl:hover { border-color: var(--pk-blue-line); }
.pk-ctl select {
  height: 100%;
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--pk-text);
  font-size: 14px;
  cursor: pointer;
}
.pk-ctl select:focus { outline: none; }
.pk-caret { color: var(--pk-dim); font-size: 10px; }

.pk-search { position: relative; flex: 1 1 0; min-width: 140px; max-width: 420px; }
.pk-search input,
.crm-search input {
  width: 100%;
  height: var(--pk-row-h);
  min-height: var(--pk-row-h);
  padding-block: 0 0; padding-inline: 11px 58px;
  border: 1px solid var(--pk-line-2);
  border-radius: 11px;
  background: var(--pk-panel);
  color: var(--pk-text);
  font-size: 14px;
}
.pk-search input::placeholder { color: var(--pk-dim); }
.pk-search input:focus { border-color: var(--pk-blue-line); outline: none; }
/* The toolbar's search is a flex item, not a positioned block: without this the
   legacy `.crm-search { flex: 1 1 260px; max-width: 420px }` and this row's own
   sizing disagree and the field jumps width when a chip appears. */
.pk-bar .crm-search { position: relative; flex: 1 1 0; min-width: 140px; max-width: 420px; }

.pk-filter.is-on { border-color: var(--pk-blue-line); background: var(--pk-blue-soft); color: var(--t349); }
.pk-filter-badge {
  display: grid; place-items: center;
  min-width: 20px; height: 20px; padding: 0 6px;
  border-radius: 999px;
  background: var(--pk-blue);
  color: var(--rp-on-accent); font-size: 11px; font-weight: 660;
}

/* Applied filters only. A chip for something not yet applied would be a second
   answer to "what am I looking at". */
.pk-chips { display: flex; align-items: center; gap: 8px; min-width: 0; overflow: hidden; }
.pk-chip {
  flex: 0 0 auto;
  height: 32px;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 0 12px;
  border: 1px solid var(--pk-blue-line);
  border-radius: 999px;
  background: var(--pk-blue-soft);
  color: var(--t349);
  font-size: 13px;
  white-space: nowrap;
  cursor: pointer;
}
.pk-chip-x { color: var(--pk-muted); font-size: 11px; }
.pk-chip-reset {
  flex: 0 0 auto;
  border: 0; background: none;
  color: var(--pk-dim); font-size: 13px; padding: 0 4px;
  white-space: nowrap; cursor: pointer;
}
.pk-chip-reset:hover { color: var(--t349); }

.pk-bar-count { margin-inline-start: auto; flex: 0 0 auto; color: var(--pk-dim); font-size: 13px; white-space: nowrap; }

.pk-more { position: relative; flex: 0 0 auto; }
.pk-more-menu {
  position: absolute; top: calc(100% + 8px); inset-inline-end: 0; z-index: 60;
  min-width: 248px;
  padding: 8px;
  border: 1px solid var(--pk-line-2);
  border-radius: 12px;
  background: var(--t79);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
  display: grid;
  gap: 2px;
}
.pk-more-menu button {
  display: block; width: 100%; text-align: start;
  height: 38px; padding: 0 12px;
  border: 0; border-radius: 8px;
  background: none; color: var(--pk-muted);
  font-size: 13.5px; cursor: pointer;
}
.pk-more-menu button:hover { background: var(--pk-blue-soft); color: var(--t349); }
.pk-more-sep { height: 1px; margin: 5px 4px; background: var(--pk-line); }

/* Was "the one control that may never shrink" — overridden 2026-08-21: the
   owner circled this exact row (view toggle through this button) and asked
   for the whole toolbar shorter, and a taller button here would only force
   the row back to its old height via .pk-bar's align-items: center. Tracks
   .pk-ctl/.pk-nav's own 38px so the row reads as one height, not two. */
.pk-new {
  flex: 0 0 auto;
  height: var(--pk-row-h);
  padding: 0 15px;
  border: 0;
  border-radius: 11px;
  background: var(--pk-blue);
  color: var(--rp-on-accent);
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(47, 123, 255, 0.22);
}
.pk-new:disabled { opacity: 0.55; cursor: not-allowed; box-shadow: none; }

/* ── the board ───────────────────────────────────────────────────────────
   Grows to fill a wide screen, never below the pack's 280px floor, and scrolls
   HORIZONTALLY — and only horizontally, and only here — once the columns no
   longer fit. The toolbar above is outside this box and does not move with it. */
.pk-board {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  gap: var(--pk-gap);
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 6px;
}
.pk-col {
  flex: 1 1 var(--pk-col);
  min-width: var(--pk-col);
  display: flex;
  flex-direction: column;
  min-height: 0;
  border: 1px solid var(--pk-line);
  border-radius: 14px;
  background: var(--pk-panel);
  overflow: hidden;
}
.pk-col-rule { height: 3px; flex: 0 0 auto; }

/* THE SEPARATION THE OWNER DREW.
   He annotated a board screenshot with a red line between the stage name and
   the stack of cards below it. That line is the spec: the name area is a
   heading for the column, not the first item in the list, and it was reading
   as the latter because nothing but 14px of padding stood between "Оплата"
   and the first deal card.

   Two devices, both deliberately quiet. The head takes a slightly lifted
   background so it reads as a different surface from the scroll area, and a
   1px rule closes it. The annotation's weight is read as emphasis in a
   marker-pen drawing rather than a literal 3px bar: a heavy divider repeated
   down a seven-column board would fight the cards for attention, which is the
   opposite of what a heading is for. The separation is what was asked for;
   the loudness was how it was pointed at.

   The rule and the tint stay NEUTRAL even when the stage has a colour. The
   colour is the name's, not the column's. */
.pk-col-head {
  flex: 0 0 auto;
  padding: 16px 18px 13px;
  background: rgba(255, 255, 255, 0.014);
  border-bottom: 1px solid var(--pk-line-2);
}
.pk-col-name { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; color: var(--pk-text); }

/* How much of the PREVIOUS column made it here — a plain ratio of visible
   headcounts, not a claim about why. Small and muted on purpose: it sits
   inside the same line as the stage name (17px, 600 weight) and must read
   as a footnote to it, never compete with it. */
.pk-col-conv {
  font-size: 11.5px; font-weight: 500; color: var(--pk-muted);
  margin-inline-start: 8px; padding: 1px 6px; border-radius: 999px;
  background: rgba(148, 163, 184, 0.12); vertical-align: middle;
}

/* THE COLOUR ITSELF — the name, and only the name.
   Not the column, not the cards, not the counts row. Each rule sets exactly
   one property on exactly one element, which is what keeps that promise
   enforceable: there is no rule here that could bleed onto a sibling.

   A stage with no colour matches nothing below and keeps var(--pk-text) from
   the rule above — the same weight, size and colour every stage name has
   today. "No colour set" therefore looks like a decision rather than a
   failure to load, and no backfill was needed to make it so. */
.pk-col-name.is-blue    { color: var(--pk-stage-blue); }
.pk-col-name.is-indigo  { color: var(--pk-stage-indigo); }
.pk-col-name.is-violet  { color: var(--pk-stage-violet); }
.pk-col-name.is-magenta { color: var(--pk-stage-magenta); }
.pk-col-name.is-rose    { color: var(--pk-stage-rose); }
.pk-col-name.is-coral   { color: var(--pk-stage-coral); }
.pk-col-name.is-sand    { color: var(--pk-stage-sand); }
.pk-col-name.is-lime    { color: var(--pk-stage-lime); }
.pk-col-name.is-mint    { color: var(--pk-stage-mint); }
.pk-col-name.is-teal    { color: var(--pk-stage-teal); }

/* The folded column shows the same name in a smaller slot, so it carries the
   same colour — it is still the stage's name. */
.pk-col-foldname.is-blue    { color: var(--pk-stage-blue); }
.pk-col-foldname.is-indigo  { color: var(--pk-stage-indigo); }
.pk-col-foldname.is-violet  { color: var(--pk-stage-violet); }
.pk-col-foldname.is-magenta { color: var(--pk-stage-magenta); }
.pk-col-foldname.is-rose    { color: var(--pk-stage-rose); }
.pk-col-foldname.is-coral   { color: var(--pk-stage-coral); }
.pk-col-foldname.is-sand    { color: var(--pk-stage-sand); }
.pk-col-foldname.is-lime    { color: var(--pk-stage-lime); }
.pk-col-foldname.is-mint    { color: var(--pk-stage-mint); }
.pk-col-foldname.is-teal    { color: var(--pk-stage-teal); }
.pk-col-meta {
  display: flex; align-items: center; gap: 12px;
  margin-top: 6px; font-size: 13px; color: var(--pk-dim);
}
.pk-col-n { color: var(--pk-muted); }
.pk-col-sep { width: 1px; height: 12px; background: var(--pk-line-2); }
/* ═══ THE STATUS CHIP ══════════════════════════════════════════════════════
   One shape for all five states. `text-transform: none` is load-bearing, not
   tidiness: the same state shipped as `NEEDS SETUP` in letter-spaced caps on
   the integrations shelf, `Needs setup` in title case in the legacy block
   below it, and `LIVE` against the dashboard's `Live` — three casings of two
   words on adjoining screens. Casing is the chip's decision and no module may
   take it back, so this rule is deliberately hard to override.

   Tone is decoration over a word that is already readable without it. Draft
   and Local only share the neutral tone because neither is a failure and
   neither is a success; giving either its own alarm colour would let the chip
   assert something its word does not. */
.status-chip {
  display: inline-flex;
  align-items: center;
  width: fit-content;
  min-height: 22px;
  padding: 3px 9px;
  border: 1px solid var(--pk-line-2);
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 650;
  line-height: 1;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
}
.status-chip.good { color: var(--t380); background: var(--live-bg); border-color: rgba(22, 163, 74, 0.34); }
.status-chip.warning { color: var(--t446); background: var(--warning-bg); border-color: rgba(245, 158, 11, 0.34); }
.status-chip.risk { color: var(--t462); background: var(--danger-bg); border-color: rgba(225, 29, 72, 0.34); }
/* rgba(255,255,255,.04) на белой панели — это белое на белом: контраст плашки
   к фону ровно 1.00:1, оставалась одна рамка. Светлая арка — тот же нейтраль,
   которым уже залит .status-pill.neutral. */
.status-chip.neutral { color: var(--pk-muted); background: light-dark(rgba(85, 98, 116, 0.12), rgba(255, 255, 255, 0.04)); }

/* The single-funnel name. It sits where the picker sits, so it must read as a
   heading and NOT as a control that failed to render — no border, no chrome,
   no hover. The eyebrow «ВОРОНКА» that used to sit above it was removed on
   12 Sep at the owner's word; the hairline divider (§15) and the heading
   weight now carry the "this is a name, not a control" reading alone. */
.pk-pipename {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  /* Tracks .pk-ctl's own height, 2026-08-21: was 44px — a single-pipeline
     workspace's toolbar was still forced to the old height by this label
     alone even after every control beside it shrank. */
  height: var(--pk-row-h);
  padding-block: 0 0; padding-inline: 0 13px;
  min-width: 0;
}
.pk-pipename > strong {
  color: var(--pk-text);
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pk-col-sum { color: var(--pk-dim); }
/* A column of deals nobody has quoted yet. Quieter than a figure, because it
   is the absence of one — it must not be mistaken for a number at a glance. */
.pk-col-unpriced { color: var(--pk-faint); font-style: italic; }
.pk-col-fold {
  margin-inline-start: auto;
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border: 1px solid var(--pk-line-2); border-radius: 8px;
  background: none; color: var(--pk-dim);
  font-size: 12px; line-height: 1; cursor: pointer;
}
.pk-col-fold:hover { color: var(--pk-text); border-color: var(--pk-blue-line); }
.pk-col-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Was `0 12px 14px`. The head now closes with a rule, and a card flush
     against that rule undoes the separation the rule was added to make. */
  padding: 12px 12px 14px;
  display: flex; flex-direction: column; gap: 12px;
}
.pk-col-empty { margin: 2px; padding: 18px 16px; border: 1px dashed var(--pk-line-2);
  border-radius: 11px; color: var(--pk-faint); font-size: 12.5px; line-height: 1.55; }
.pk-col-more { display: grid; gap: 5px; }
.pk-col-more > span { color: var(--pk-faint); font-size: 11.5px; }
.pk-col-morebtn {
  height: 34px; border: 1px dashed var(--pk-line-2); border-radius: 9px;
  background: none; color: var(--pk-muted); font-size: 12.5px; cursor: pointer;
}
.pk-col-morebtn:hover { border-color: var(--pk-blue-line); color: var(--t349); }
.pk-col-add {
  flex: 0 0 auto;
  height: 40px; margin: 0 12px 12px;
  border: 1px dashed var(--pk-line-2); border-radius: 10px;
  background: none; color: var(--pk-dim); font-size: 13px; cursor: pointer;
}
.pk-col-add:hover:not(.is-off) { border-color: var(--pk-blue-line); color: var(--t254); }
.pk-col-add.is-off { opacity: 0.45; cursor: not-allowed; }
.pk-col.is-won { border-color: rgba(74, 222, 128, 0.30); }
.pk-col.is-lost { border-color: rgba(248, 113, 113, 0.26); }

/* Folded keeps the name, the count and its colour: hiding what a column is
   worth is how a column stays folded forever. */
.pk-col-folded { flex: 0 0 56px; min-width: 56px; }
.pk-col-unfold {
  flex: 1 1 auto; width: 100%;
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 16px 0;
  border: 0; background: none; color: var(--pk-muted); cursor: pointer;
}
.pk-col-foldname { writing-mode: vertical-rl; font-size: 13px; white-space: nowrap; }
.pk-col-foldcount { font-size: 12px; color: var(--pk-dim); }

/* ── the lead card ───────────────────────────────────────────────────────
   Company, person, next action, how cold, whose. No money — that is a column
   total, and twenty copies of it is twenty numbers nobody adds up. */
.pk-lead {
  border: 1px solid var(--pk-line);
  border-radius: 11px;
  background: var(--pk-card);
  padding: 15px 16px 13px;
  cursor: pointer;
}
.pk-lead:hover { background: var(--pk-card-hi); border-color: var(--pk-line-2); }
.pk-lead.is-picked { border-color: var(--pk-blue-line); background: rgba(47, 123, 255, 0.10); }
.pk-lead-head { display: flex; align-items: flex-start; gap: 10px; }
.pk-lead-who { min-width: 0; flex: 1 1 auto; }
.pk-lead-name {
  display: block;
  font-size: 14.5px; font-weight: 600; letter-spacing: -0.005em; color: var(--pk-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pk-lead-person {
  display: block; margin-top: 3px;
  color: var(--pk-dim); font-size: 12.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* An honest stand-in — «Клиент WhatsApp · …7903» — rather than a name the
   customer gave us. Italic and a shade quieter: enough to read as a
   description, not so much that it looks like an error state. */
.pk-lead-person.is-standin { font-style: italic; opacity: .78; }
/* Первое сообщение клиента, когда оно было названием сделки (11 сентября):
   тихая цитата под именем — видно, с чего начался разговор. */
.pk-lead-quote {
  display: block; margin-top: 3px;
  color: var(--pk-dim); font-size: 12px; font-style: italic; opacity: .85;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Same rule in the List view's Contact column and on the deal card. */
.crm-contact-name.is-standin { font-style: italic; opacity: .78; }
.pk-lead-tick {
  flex: 0 0 auto; width: 20px; height: 20px; margin-top: 1px;
  display: grid; place-items: center;
  border: 1px solid var(--pk-line-2); border-radius: 6px;
  color: var(--t349); font-size: 11px;
}
.pk-lead-tick.on { border-color: var(--pk-blue-line); background: var(--pk-blue); color: var(--rp-on-accent); }
.pk-lead-go {
  flex: 0 0 auto; width: 26px; height: 26px;
  display: grid; place-items: center;
  border: 1px solid var(--pk-line-2); border-radius: 8px;
  background: none; cursor: pointer;
}
.pk-lead-go:hover { border-color: var(--pk-blue-line); background: var(--pk-blue-soft); }
.pk-lead-go-glyph {
  width: 13px; height: 13px; display: block; background-color: var(--pk-muted);
  -webkit-mask: var(--pk-arrow) center / contain no-repeat;
  mask: var(--pk-arrow) center / contain no-repeat;
  --pk-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h13M12.5 5.5 19 12l-6.5 6.5'/%3E%3C/svg%3E");
}
.pk-lead-go:hover .pk-lead-go-glyph { background-color: var(--t254); }

.pk-lead-next {
  display: flex; align-items: center; gap: 8px;
  margin-top: 13px; font-size: 13px; color: var(--pk-muted); min-width: 0;
}
.pk-lead-next-ic { color: var(--pk-dim); font-size: 12px; flex: 0 0 auto; }
.pk-lead-next-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pk-lead-next.is-late { color: var(--t438); }
.pk-lead-next.is-late .pk-lead-next-ic { color: var(--pk-high); }

.pk-lead-when { margin-top: 9px; font-size: 12px; color: var(--pk-faint); }
/* Over 7 days since anything happened on this lead — same threshold the lead
   card's own stage-age indicator uses, on a different fact (last activity,
   not stage entry), so it gets its own colour rather than borrowing that
   indicator's "stale" name for a different claim. */
.pk-lead-when-cold { color: var(--pk-high); font-weight: 500; }

/* СКОРИНГ ЛИДА (13 сентября 2026) — чип «🔥 72 горячий» в строке активности.
   Цвета — из семантического набора (--pk-high / --pk-amber / --pk-blue), не
   новые: горячий зовёт, тёплый напоминает, холодный сообщает. Подсказка
   (title) несёт три главные причины — без неё число нельзя объяснить. */
.pk-lead-when { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.pk-score {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; line-height: 1.3; padding: 1px 7px; border-radius: 999px;
  white-space: nowrap; border: 1px solid transparent; font-weight: 600; cursor: help;
  margin-inline-start: auto;
}
.pk-score-ic { font-size: 11px; }
.pk-score-w { font-weight: 500; opacity: .85; }
.pk-score-hot { color: var(--pk-text); background: color-mix(in srgb, var(--pk-high) 18%, transparent); border-color: color-mix(in srgb, var(--pk-high) 42%, transparent); }
.pk-score-warm { color: var(--pk-text); background: color-mix(in srgb, var(--pk-amber) 14%, transparent); border-color: color-mix(in srgb, var(--pk-amber) 34%, transparent); }
.pk-score-cold { color: var(--pk-muted); background: color-mix(in srgb, var(--pk-blue) 10%, transparent); border-color: color-mix(in srgb, var(--pk-blue) 24%, transparent); }
.pk-score-lg { font-size: 12.5px; padding: 2px 9px; margin-inline-start: 0; }
.pk-score-sort.is-on { border-color: color-mix(in srgb, var(--pk-high) 45%, transparent); }
/* Карточка лида: полный список причин под именем. */
.lw-score { margin: 8px 0 0; font-size: 12.5px; color: var(--pk-muted); }
.lw-score-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.lw-score-list { margin: 6px 0 0; padding: 0; list-style: none; display: grid; gap: 3px; }
.lw-score-list li { font-variant-numeric: tabular-nums; }
.lw-score-list .is-minus { color: var(--pk-high); }
.lw-score-note { margin: 4px 0 0; font-size: 11.5px; color: var(--pk-faint); }

/* МЕТКИ СОСТОЯНИЯ ПЕРЕПИСКИ НА КАРТОЧКЕ.
   Две, и они намеренно разного веса. «Ждёт ответа» загорается редко — сегодня
   ноль карточек из 59 — и потому имеет право быть заметной. «Мария выключена»
   стоит на 38 карточках: будь она такой же яркой, доска превратилась бы в
   сплошную заливку и перестала что-либо сообщать. Приглушённая, но читаемая. */
.pk-lead-chat { display: flex; flex-wrap: wrap; gap: 4px; margin: 4px 0 0; }
.pk-chat-mark {
  font-size: 10.5px; line-height: 1.3; padding: 2px 6px; border-radius: 999px;
  white-space: nowrap; border: 1px solid transparent;
}
.pk-chat-waiting {
  font-weight: 600;
  color: light-dark(#9b1c1c, #fca5a5);
  background: rgba(220, 38, 38, .14);
  border-color: rgba(220, 38, 38, .34);
}
.pk-chat-off {
  color: light-dark(#6b5100, #e8b155);
  background: rgba(232, 177, 85, .10);
  border-color: rgba(232, 177, 85, .24);
}

.pk-lead-foot {
  display: flex; align-items: center; gap: 9px;
  margin-top: 12px; padding-top: 12px;
  border-top: 1px solid rgba(148, 178, 255, 0.07);
  min-width: 0;
}
.pk-lead-ava {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%;
  background: linear-gradient(140deg, light-dark(#c6d3e4, #3a4d6b), light-dark(#dfe7f2, #63809f));
  display: grid; place-items: center;
  font-size: 10px; font-weight: 600; color: var(--pk-text);
}
.pk-lead-owner {
  font-size: 13px; color: var(--pk-muted); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pk-lead-owner.muted { color: var(--pk-faint); }
.pk-lead-right { margin-inline-start: auto; display: flex; align-items: center; gap: 9px; flex: 0 0 auto; }
.pk-lead-ch { display: inline-flex; }
.pk-lead-ch .provider-avatar { width: 20px; height: 20px; min-width: 20px; }
.pk-lead-ch .provider-avatar img { width: 20px; height: 20px; }
.pk-pri { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--pk-muted); }
.pk-pri-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--pk-med); }
.pk-pri-high .pk-pri-dot { background: var(--pk-high); }
.pk-pri-normal .pk-pri-dot { background: var(--pk-med); }
.pk-pri-low .pk-pri-dot { background: var(--pk-low); }

/* ── the filter drawer, 360 ──────────────────────────────────────────────
   A COLUMN of .pk-page, not an overlay. Its own lighter surface and a hard edge
   against the board, a body that scrolls and a footer that stays put. */
.pk-drawer {
  display: flex;
  flex-direction: column;
  min-height: 0;
  width: var(--pk-filter-w);
  margin-inline-start: var(--pk-gap);
  border: 1px solid var(--pk-line-2);
  border-radius: 14px;
  background: var(--t79);
  overflow: hidden;
}
.pk-drawer-head {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 9px;
  height: 60px; padding: 0 18px;
  border-bottom: 1px solid var(--pk-line-2);
  background: var(--t106);
}
.pk-drawer-title { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.pk-drawer-count {
  height: 22px; padding: 0 9px; border-radius: 999px;
  display: inline-flex; align-items: center;
  font-size: 12px; color: var(--t349);
  background: var(--pk-blue-soft); border: 1px solid var(--pk-blue-line);
}
/* Every panel closes with a control that says what it does. */
.pk-drawer-x {
  margin-inline-start: auto; height: 32px; padding: 0 12px;
  border: 1px solid var(--pk-line-2); border-radius: 9px;
  background: var(--pk-panel); color: var(--pk-muted);
  font-size: 13px; cursor: pointer;
}
.pk-drawer-x:hover { color: var(--pk-text); border-color: var(--pk-blue-line); }
.pk-drawer-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 4px 18px 18px; }
.pk-fg { padding: 16px 0; border-bottom: 1px solid rgba(148, 178, 255, 0.09); }
.pk-fg:last-child { border-bottom: 0; }
.pk-fg-label {
  display: flex; align-items: center; gap: 8px;
  font-size: 10.5px; letter-spacing: 0.11em; text-transform: uppercase;
  color: var(--u14); margin-bottom: 10px; font-weight: 600;
}
/* A role marker, not a lock on something a manager can see and not press: the
   whole group is absent for a manager. */
.pk-fg-only {
  height: 17px; padding: 0 7px; border-radius: 999px;
  display: inline-flex; align-items: center;
  letter-spacing: 0.06em; font-size: 9px; color: var(--t349);
  background: var(--pk-blue-soft); border: 1px solid var(--pk-blue-line);
}
.pk-fg-opts { display: flex; flex-wrap: wrap; gap: 8px; }
.pk-opt {
  height: 32px; display: inline-flex; align-items: center; gap: 7px;
  padding: 0 12px;
  border: 1px solid var(--pk-line-2); border-radius: 9px;
  background: var(--rp-plate); color: var(--pk-muted);
  font-size: 13px; cursor: pointer;
}
.pk-opt:hover { border-color: var(--pk-blue-line); color: var(--pk-text); }
.pk-opt.is-on { border-color: var(--pk-blue-line); background: rgba(47, 123, 255, 0.20); color: var(--t372); font-weight: 500; }
.pk-opt-dot { width: 7px; height: 7px; border-radius: 50%; }
.pk-drawer-foot {
  flex: 0 0 auto;
  display: flex; gap: 10px; padding: 14px 18px;
  background: var(--t106); border-top: 1px solid var(--pk-line-2);
}
.pk-btn-ghost {
  flex: 0 0 auto; height: 42px; padding: 0 20px;
  border: 1px solid var(--pk-line-2); border-radius: 11px;
  background: var(--rp-plate); color: var(--pk-muted);
  font-size: 14px; cursor: pointer;
}
.pk-btn-ghost:hover { color: var(--pk-text); border-color: var(--pk-blue-line); }
.pk-btn-primary {
  flex: 1 1 auto; height: 42px;
  display: flex; align-items: center; justify-content: center;
  border: 0; border-radius: 11px;
  background: var(--pk-blue); color: var(--rp-on-accent);
  font-size: 14px; font-weight: 500; cursor: pointer;
}

/* Scrollbars, only where scrolling is allowed. */
.pk-board::-webkit-scrollbar, .pk-col-body::-webkit-scrollbar,
.pk-drawer-body::-webkit-scrollbar { height: 9px; width: 9px; }
.pk-board::-webkit-scrollbar-thumb, .pk-col-body::-webkit-scrollbar-thumb,
.pk-drawer-body::-webkit-scrollbar-thumb { background: rgba(148, 178, 255, 0.15); border-radius: 9px; }
.pk-board::-webkit-scrollbar-track, .pk-col-body::-webkit-scrollbar-track,
.pk-drawer-body::-webkit-scrollbar-track { background: transparent; }

/* ═══ THE CLIENT WORKSPACE — Pack 02 ═════════════════════════════════════
   THE LAYOUT CONTRACT, the same four states as the pipeline and, later, the
   Dialogues desk.

     default            client 360 · centre minmax(0,1fr)
     client hidden      centre minmax(0,1fr)
     drawer open        client 360 · centre minmax(0,1fr) · drawer 380
     both closed        centre minmax(0,1fr)                ← the whole canvas

   The centre is ALWAYS minmax(0,1fr). A closed panel is 0px: the track is gone,
   not narrowed to a sliver, and the only trace it leaves is one labelled button
   in the header of the thing that took its space. Nothing unmounts — the state
   lives in the module, so the selected client, the loaded thread and the chosen
   call all survive every transition. */
.lw-page {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--pk-gap);
  height: 100%;
  min-height: 0;
  padding: 0 0 6px;
}
.lw-page.has-card { grid-template-columns: var(--pk-client-w) minmax(0, 1fr); }
.lw-page.has-drawer { grid-template-columns: minmax(0, 1fr) var(--pk-drawer-w); }
.lw-page.has-card.has-drawer {
  grid-template-columns: var(--pk-client-w) minmax(0, 1fr) var(--pk-drawer-w);
}
.lw-page > * { min-width: 0; min-height: 0; }

/* Each zone is its own surface, not three regions of one sheet divided by
   hairlines — one visual surface per block, per the approved pack. */
.lw-card, .lw-main, .lw-drawer {
  border: 1px solid var(--pk-line);
  border-radius: 14px;
  background: var(--pk-panel);
  overflow: hidden;
  min-height: 0;
}
/* The panel is a grid TRACK now, not a fixed-width flex child, so its old
   `width:380px` would fight the track and its `padding:16px` was dropped with
   it — which clipped every right-aligned value in the card against the panel
   edge. The padding belongs here, and the panel scrolls: at 1080 this card is
   taller than the fold with an AI summary, contacts, calls and qualification
   on it, and a panel that cannot scroll simply hides its last section. */
.lw-card {
  width: auto; min-width: 0; max-width: none;
  padding: 0 16px 16px;
  overflow-y: auto;
  overflow-x: hidden;
  display: block;
}
.lw-card-head {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 0 10px;
  /* Anchors the "•••" menu (Add a task / Delete lead / …) so it works from
     the card header too, not only the conversation header — a lead with no
     connected dialogue renders ONLY this card, and until 2026-08-22 that
     meant Delete lead was completely unreachable for it. */
  position: relative;
}
.lw-card .lw-back { padding: 0; }
.lw-main { display: flex; flex-direction: column; }
.lw-drawer { display: flex; flex-direction: column; background: var(--t79); border-color: var(--pk-line-2); }
.lw-drawer-head {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 10px;
  padding: 15px 18px;
  border-bottom: 1px solid var(--pk-line-2);
  background: var(--t106);
}
.lw-drawer-title { font-size: 15px; font-weight: 600; color: var(--pk-text); }

/* Every panel closes with a control that says what it does. */
.lw-panel-hide, .lw-drawer-x {
  margin-inline-start: auto; flex: 0 0 auto;
  height: 28px; padding: 0 11px;
  border: 1px solid var(--pk-line-2); border-radius: 8px;
  background: var(--rp-plate); color: var(--pk-muted);
  font-size: 12px; cursor: pointer;
}
.lw-panel-hide:hover, .lw-drawer-x:hover { color: var(--pk-text); border-color: var(--pk-blue-line); }
.lw-panel-show {
  flex: 0 0 auto;
  height: 34px; padding: 0 12px;
  border: 1px solid var(--pk-line-2); border-radius: 9px;
  background: var(--rp-plate); color: var(--pk-muted);
  font-size: 13px; white-space: nowrap; cursor: pointer;
}
.lw-panel-show:hover { color: var(--pk-text); border-color: var(--pk-blue-line); }
.lw-panel-show.is-on { border-color: var(--pk-blue-line); background: rgba(47, 123, 255, 0.16); color: var(--t372); }

/* THE DRAWER CARRIES THE PANE, NOT A SECOND COPY OF ITS CHROME. CallPane keeps
   its own head and scroller exactly as they were — this only gives them a
   column to live in. */
.lw-drawer .lw-callpane { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; border: 0; }
/* A LIVE CHAT ANCHORS TO THE BOTTOM; A FINISHED CALL DOES NOT.
   `.lw-thread` carries margin-top:auto so a conversation you are still having
   sits on the composer. Inside this drawer the same markup is a transcript of
   something already over — read from the top — and the auto margin left a
   400px hole under the facts that reads as "the rest failed to load". */
.lw-drawer .lw-thread { margin-top: 0; }

/* THREE COLUMNS NEED THE ROOM FOR THREE COLUMNS.
   At 1920 the centre keeps 1920 − 220 rail − 64 padding − 360 − 380 − 36 gaps
   = 860px, which is a conversation. At 1440 the same sum leaves 380px, which is
   not. So below 1600 the client panel yields to the drawer the operator just
   asked for, and comes back with the "Client" button in the header — the
   contract's rule that the sides give way before the centre does. */
/* The "Client" button is always in the markup and hidden while the panel it
   summons is actually on screen — see the comment beside it for why it cannot
   be conditional on the open flag alone. */
.lw-page.has-card .lw-panel-client { display: none; }

@media (max-width: 1599px) {
  .lw-page.has-card.has-drawer { grid-template-columns: minmax(0, 1fr) var(--pk-drawer-w); }
  .lw-page.has-card.has-drawer > .lw-card { display: none; }
  /* …and it comes back the moment the panel is dropped for the drawer. */
  .lw-page.has-card.has-drawer .lw-panel-client { display: inline-flex; }
}

/* ═══ THE AI AGENT CABINET ═══════════════════════════════════════════════
   The owner's instruction for this section was space: "свобода нужна,
   пространство, не всё в одном страничке". The structure was already right —
   every section of the cabinet has its own route — and the geometry was not: a
   232px menu of eighteen rows against a page with no room to breathe.

   The local section rail is 300px, per the approved geometry, and the page
   beside it is one task with air around it. */
.agent-cabinet-layout {
  display: grid;
  grid-template-columns: var(--pk-local-w) minmax(0, 1fr);
  gap: var(--pk-gap);
  align-items: start;
  min-width: 0;
}
.agent-cabinet-layout > * { min-width: 0; }
.agent-cabinet-nav {
  position: sticky; top: 0;
  padding: 14px 12px;
  border: 1px solid var(--pk-line);
  border-radius: 14px;
  background: var(--pk-panel);
}
.agent-nav-group + .agent-nav-group { margin-top: 18px; }
.agent-nav-group > p {
  margin: 0 0 8px; padding: 0 10px;
  font-size: 9.5px; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--pk-faint); font-weight: 600;
}
.agent-cabinet-nav button {
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: 38px;
  padding: 0 10px; margin: 0;
  border: 0; border-radius: 9px;
  background: none; color: var(--pk-muted);
  font-size: 13.5px; text-align: start; cursor: pointer;
}
.agent-cabinet-nav button:hover { background: rgba(148, 178, 255, 0.06); color: var(--pk-text); }
.agent-cabinet-nav button.active { background: var(--pk-blue-soft); color: var(--t349); font-weight: 500; }
.agent-nav-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The per-row state is a quiet marker, not a second column of shouting. */
.agent-nav-state {
  flex: 0 0 auto; height: 18px; padding: 0 8px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; border: 1px solid var(--pk-line-2);
  /* «NOT CONNECTED» is thirteen characters and was overrunning its own pill.
     A marker that spills out of its border reads as a rendering fault, which
     is a bad first impression of a row that is merely not set up yet. */
  font-size: 8.5px; letter-spacing: 0.04em; line-height: 1; text-transform: uppercase;
  white-space: nowrap;
  color: var(--pk-faint); background: transparent;
}
.agent-nav-state-live { color: var(--t293); border-color: rgba(74, 222, 128, 0.32); }
.agent-nav-state-partial_live { color: var(--pk-amber); border-color: rgba(251, 191, 36, 0.30); }

/* ONE VISUAL SURFACE PER BLOCK. The cabinet's page was a card inside a card
   inside a card; the approved system is one surface, generously padded. */
.agent-cabinet-page { gap: var(--rp-4); }
.agent-cabinet-header {
  display: flex; align-items: flex-start; gap: var(--pk-gap);
  padding: 18px 22px;
  border: 1px solid var(--pk-line); border-radius: 14px;
  background: var(--pk-panel);
}
.agent-cabinet-identity h2 { margin: 6px 0 4px; font-size: 22px; letter-spacing: -0.02em; }
.agent-cabinet-identity p { margin: 0; color: var(--pk-muted); font-size: 13.5px; }
.agent-cabinet-readiness { margin-inline-start: auto; flex: 0 0 auto; }

/* Two tiles that mean something beat five where three are empty. The strip
   sizes itself to what it has rather than stretching two facts across a row
   built for five. */
.agent-kpis { grid-template-columns: repeat(auto-fit, minmax(240px, 320px)); }

/* ── the section: landing OR cabinet, never both ─────────────────────────
   This was a two-column board with the preset catalogue on the left and the
   whole cabinet on the right, under a KPI strip — three products deep, and the
   section you picked from the menu appeared in the middle of the third one.
   Each route now renders one of the two, full width. */
.agent-board.is-overview,
.agent-board.is-cabinet { display: block; grid-template-columns: none; }

/* THE LOCAL SECTION RAIL, 300px, per the approved geometry. */
.agent-cabinet {
  display: grid;
  grid-template-columns: var(--pk-local-w) minmax(0, 1fr) var(--pk-drawer-w);
  gap: var(--pk-gap);
  align-items: start;
  min-width: 0;
}
.agent-cabinet > * { min-width: 0; }
.ac-nav {
  width: auto;
  padding: 14px 12px;
  border: 1px solid var(--pk-line);
  border-radius: 14px;
  background: var(--pk-panel);
  align-self: start;
}
.ac-nav-head {
  padding: 0 10px 12px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--pk-line);
  font-size: 13.5px; font-weight: 600; color: var(--pk-text);
}
.ac-nav-group + .ac-nav-group { margin-top: 16px; }
.ac-nav-label {
  margin: 0 0 6px; padding: 0 10px;
  font-size: 9.5px; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--pk-faint); font-weight: 600;
}
/* КРУПНЫЕ НАДПИСИ В СТОЛБЦЕ КАБИНЕТА.
   Владелец просил это дважды — 31 августа про левое меню и 1 сентября про
   кабинет: «большие надписи», «большие кнопки». Строка была 13.5px при
   высоте 36px — мельче, чем текст страниц, к которым она ведёт, и по ней
   ходят весь день. 15.5px и 44px: тот же размер, что у главного меню слева,
   чтобы два столбца на одном экране не спорили друг с другом. */
.ac-nav-item {
  display: flex; align-items: center; gap: 11px;
  width: 100%; min-height: 44px;
  padding: 0 12px; margin: 0;
  border: 0; border-radius: 10px;
  background: none; color: var(--pk-muted);
  font-size: 15.5px; text-align: start; cursor: pointer;
  /* Длинное название переносится, а не обрезается: «Контроль качества» и
     «Готовые агенты» в узком столбце иначе теряют хвост. */
  white-space: normal; line-height: 1.3;
}
.ac-nav-item:hover { background: rgba(148, 178, 255, 0.06); color: var(--pk-text); }
.ac-nav-item.on { background: var(--pk-blue-soft); color: var(--t349); font-weight: 500; }
.ac-nav-ic { flex: 0 0 auto; width: 20px; text-align: center; font-size: 15px; }
/* Заголовок группы — это вопрос, на который отвечают строки под ним, и он
   должен читаться, а не служить разделителем. */
.ac-nav-label { font-size: 12px; letter-spacing: .07em; }
.ac-nav-group { margin-bottom: 14px; }

/* ═══ ОДНА НАВИГАЦИЯ РАЗДЕЛА «AI-ОТДЕЛ ПРОДАЖ» (26.09.2026) ══════════════
   Столбец разделов стоит у каждой страницы раздела — посадочной (итоги, под
   ними каталог), отдельных страниц и кабинета: сетка «столбец · страница»
   (.agent-cabwrap .agent-cabinet.agent-cabinet-wide в redesign.css). Когда
   сетка складывается в одну колонку (≤1080px), столбец становится одной
   строкой с прокруткой вбок: двадцать строк меню не встают над итогами.
   Прокручивается сама строка, не страница. */
.agent-section .agent-landing-body,
.agent-section .agent-fullpage { align-content: start; min-width: 0; }
@media (max-width: 1080px) {
  .agent-cabwrap .ac-nav {
    display: flex; flex-direction: row; flex-wrap: nowrap; align-items: center;
    gap: 4px; padding: 6px; max-width: 100%; min-width: 0; position: static;
    overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: thin;
  }
  .agent-cabwrap .ac-nav-head,
  .agent-cabwrap .ac-nav-label { display: none; }
  .agent-cabwrap .ac-nav-group { display: contents; }
  .agent-cabwrap .ac-nav-item {
    flex: 0 0 auto; width: auto; min-height: 40px;
    padding: 0 12px; white-space: nowrap; font-size: 14px;
  }
}

/* ONE PAGE, ONE TASK, WITH ROOM AROUND IT. */
.ac-body {
  min-width: 0;
  padding: 4px 0 0;
}
/* Колонка кабинета — по ширине экрана (24.09.2026, мобильный проход). .ac-body
   и .agent-fullpage-body — сетки с неявной колонкой auto; на телефоне её
   распирало до самого широкого блока: «Каналы агента» — 1175 px, «Рассылка» —
   875, «Лестница дожима» — 372 в экране 375, и правый край срезался. */
@media (max-width: 980px) {
  .ac-body, .agent-fullpage-body { grid-template-columns: minmax(0, 1fr); }
}
/* ОТСТУП ВЕРНУЛСЯ. Здесь стояло `.ac-section { padding: 0 }`, и поскольку этот
   файл грузится последним, он побеждал `padding: var(--rp-4)` из redesign.css.
   Замер на собранной странице: заголовок и текст стояли в ОДНОМ пикселе от
   рамки панели — во всех вкладках кабинета агентов сразу, потому что правило
   одно на всю секцию. Владелец сообщал об этом много раз («отодвинь от
   бортика»), и каждый раз это выглядело как частный случай, хотя причина была
   одна.

   Ноль ставился, судя по соседнему комментарию, чтобы не удваивать отступ с
   `.ac-body` — но у `.ac-body` горизонтального отступа нет вовсе
   (`padding: 4px 0 0`), так что удваивать было нечего. */
.ac-section { padding: var(--rp-4, 18px); }

@media (max-width: 1599px) {
  /* The right-hand rail is the first thing to go: it holds one card of prose
     and a link, and the page beside it is the work. */
  .agent-cabinet { grid-template-columns: var(--pk-local-w) minmax(0, 1fr); }
  .agent-cabinet > .agent-rail { display: none; }
}

/* ═══ BUSINESS OVERVIEW ══════════════════════════════════════════════════
   ROWS SIZE TO WHAT THEY HOLD.

   Both rows were fixed four-column grids, so removing the two blocks that
   could never report anything — the «Marketing spend» tile whose value was a
   hard-coded dash, and the «Action centre» card of eight links to the rail —
   left a quarter of each row as a hole. A gap where a card used to be reads as
   a card that failed to load, which is the same misreading the dashes caused.
   auto-fit lets three cards share the row the way four did. */
.rp-kpis, .rp-grid.rp-ov-row {
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

/* ═══ MARKETING — the not-connected state ════════════════════════════════
   One answer instead of forty dashes. Two surfaces: the one missing thing with
   the one action, and the source data the product genuinely has. */
.mk-board-setup { display: grid; gap: var(--rp-4); max-width: 940px; }
.mk-setup, .mk-setup-known {
  border: 1px solid var(--pk-line); border-radius: 14px;
  background: var(--pk-panel); padding: 22px 24px;
}
.mk-setup h3, .mk-setup-known h3 { margin: 0; font-size: 18px; font-weight: 600; letter-spacing: -0.01em; }
.mk-setup-lede, .mk-setup-known p {
  margin: 8px 0 0; color: var(--pk-muted); font-size: 13.5px; line-height: 1.6; max-width: 76ch;
}
.mk-setup-accounts { margin-top: 18px; display: flex; flex-direction: column; }
.mk-setup-acc {
  display: flex; align-items: center; gap: 14px;
  padding-block: 11px 11px; padding-inline: 12px 0;
  border-top: 1px solid var(--pk-line);
  border-inline-start: 3px solid transparent;
  font-size: 13.5px;
}
.mk-setup-accounts > .mk-setup-acc:first-child { border-top: 0; }
.mk-setup-acc strong { flex: 1 1 auto; color: var(--pk-text); font-weight: 500; }
.mk-setup-acc span { flex: 0 0 auto; color: var(--pk-dim); font-size: 12.5px; }
/* Connectable, connected-through-another, and no connector at all are three
   different answers and are told apart before a word is read. */
.mk-setup-acc-on { border-inline-start-color: var(--pk-green); }
.mk-setup-acc-off { border-inline-start-color: var(--pk-amber); }
.mk-setup-acc-na { border-inline-start-color: var(--pk-line-2); }
.mk-setup-actions { display: flex; gap: 10px; margin-top: 20px; }
.mk-setup-known button { margin-top: 16px; }

/* The Action Center reports block: reasons as sentences, not dashes. */
.ac15-missing { display: grid; gap: 2px; margin-top: 12px; }
.ac15-missingrow {
  display: flex; align-items: baseline; gap: 12px; margin: 0;
  padding: 9px 0; border-top: 1px solid var(--pk-line);
  font-size: 13px;
}
.ac15-missing > .ac15-missingrow:first-child { border-top: 0; }
.ac15-missingrow strong { flex: 0 0 auto; min-width: 168px; color: var(--pk-text); font-weight: 500; }
.ac15-missingrow span { color: var(--pk-muted); }

/* ═══ MARKETING — the live Meta Ads desk ═════════════════════════════════ */
.mk-desk { display: grid; gap: var(--rp-4); }
.mk-desk-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--pk-gap); }
.mk-desk-tile {
  display: grid; gap: 4px; align-content: start;
  padding: 18px 20px;
  border: 1px solid var(--pk-line); border-radius: 14px; background: var(--pk-panel);
}
.mk-desk-label { color: var(--pk-muted); font-size: 12.5px; }
.mk-desk-value { color: var(--rp-ink-max); font-size: 26px; font-weight: 660; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.mk-desk-sub { color: var(--pk-faint); font-size: 11.5px; }

.mk-risks, .mk-campaigns {
  border: 1px solid var(--pk-line); border-radius: 14px; background: var(--pk-panel); padding: 20px 22px;
}
.mk-risks h3, .mk-campaigns h3 { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.mk-risks-note, .mk-camp-foot { margin: 6px 0 0; color: var(--pk-dim); font-size: 12.5px; line-height: 1.55; max-width: 78ch; }
.mk-risk-rows { margin-top: 14px; display: flex; flex-direction: column; }
.mk-risk {
  display: flex; align-items: baseline; gap: 14px;
  padding-block: 12px 12px; padding-inline: 14px 0;
  border-top: 1px solid var(--pk-line);
  border-inline-start: 3px solid transparent;
  font-size: 13.5px;
}
.mk-risk-rows > .mk-risk:first-child { border-top: 0; }
.mk-risk-high { border-inline-start-color: var(--pk-high); }
.mk-risk-warn { border-inline-start-color: var(--pk-amber); }
.mk-risk strong { flex: 0 0 auto; max-width: 34ch; color: var(--pk-text); font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mk-risk span { flex: 1 1 auto; color: var(--pk-muted); }

.mk-camp-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 96px 84px 84px 116px;
  gap: 14px; align-items: center;
  margin-top: 16px; padding-block: 0 8px; padding-inline: 14px 0;
  border-bottom: 1px solid var(--pk-line);
  color: var(--pk-faint); font-size: 10.5px; letter-spacing: 0.09em; text-transform: uppercase; font-weight: 600;
}
.mk-camp-head > span:not(:first-child):not(:last-child) { text-align: end; }
.mk-camp-rows { display: flex; flex-direction: column; }
.mk-camp {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 96px 84px 84px 116px;
  align-items: center; gap: 14px;
  padding-block: 13px 13px; padding-inline: 14px 0;
  border-top: 1px solid var(--pk-line);
  border-inline-start: 3px solid transparent;
}
.mk-camp-rows > .mk-camp:first-child { border-top: 0; }
.mk-camp.is-live { border-inline-start-color: var(--pk-green); }
.mk-camp-main { min-width: 0; }
.mk-camp-main strong { display: block; color: var(--pk-text); font-size: 13.5px; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mk-camp-meta { display: block; margin-top: 3px; color: var(--pk-dim); font-size: 12px; }
.mk-camp-n { text-align: end; color: var(--pk-muted); font-size: 13px; font-variant-numeric: tabular-nums; }
.mk-camp-act {
  height: 32px; padding: 0 12px;
  border: 1px solid var(--pk-line-2); border-radius: 9px;
  background: var(--rp-plate); color: var(--pk-muted); font-size: 12.5px; cursor: pointer;
}
.mk-camp-act:hover:not(:disabled) { color: var(--pk-text); border-color: var(--pk-blue-line); }
.mk-camp-act:disabled { opacity: 0.5; cursor: progress; }
/* Armed: one more click changes a live campaign, so it stops looking like the
   other buttons on the row. */
.mk-camp-act.is-armed {
  border-color: var(--pk-high); background: rgba(248, 113, 113, 0.14); color: var(--t438); font-weight: 500;
}
/* КАМПАНИИ НА ТЕЛЕФОНЕ (24.09.2026). Четыре колонки 96 + 84 + 84 + 116 px и
   три промежутка — 436 px неподвижной ширины в карточке на 338: колонка с
   названием кампании сжималась до 0 px, а «Остановить» уезжало за край экрана.
   Теперь название — своей строкой, под ним расход, конверсии, CPL и кнопка;
   шапка перестраивается так же, поэтому подписи стоят над своими числами. */
@media (max-width: 560px) {
  .mk-camp-head, .mk-camp {
    grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
    gap: 6px 10px; padding-inline-end: 10px;
  }
  .mk-camp-head > :first-child, .mk-camp > .mk-camp-main { grid-column: 1 / -1; }
  .mk-camp-head > span:not(:first-child):not(:last-child), .mk-camp-n { text-align: start; }
  .mk-camp-head { font-size: 12px; letter-spacing: 0.04em; }
  .mk-camp-act { height: 36px; }
}
/* Same "arm, then a second press confirms" shape as armConfirm() call sites
   that are not the campaign row above (Media Factory delete, Meta
   disconnect, ...) — a plain, unprefixed class so any button using the
   shared helper gets the same danger tint without a per-page rule. */
.is-armed { border-color: var(--pk-high, #f87171) !important; background: rgba(248, 113, 113, 0.14) !important; color: var(--t438, #fca5a5) !important; font-weight: 600; }
.mk-note { color: var(--pk-muted); font-size: 13.5px; }

/* ═══ MEDIA FACTORY ══════════════════════════════════════════════════════
   The same task-first shape as the agent cabinet, for the same reason: eleven
   scenes already had routes and screens, and the only way to reach them was a
   row of 12.5px tabs in the dimmest ink on the palette with no background.
   A menu nobody can see is a menu nobody uses — so the landing page grew into
   a dumping ground, carrying what the sections were supposed to. */
.media-workspace-body {
  display: grid;
  grid-template-columns: var(--pk-local-w) minmax(0, 1fr);
  gap: var(--pk-gap);
  align-items: start;
  min-width: 0;
}
.media-workspace-body > * { min-width: 0; }
.media-workspace-main { display: grid; gap: var(--rp-3); min-width: 0; align-content: start; }

.media-workspace-nav {
  display: block !important;
  position: sticky; top: 0;
  padding: 14px 12px !important;
  border: 1px solid var(--pk-line) !important;
  border-bottom: 1px solid var(--pk-line) !important;
  border-radius: 14px !important;
  background: var(--pk-panel) !important;
  overflow: visible;
}
.mw-nav-group + .mw-nav-group { margin-top: 16px; }
.mw-nav-label {
  margin: 0 0 6px; padding: 0 10px;
  font-size: 9.5px; letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--pk-faint); font-weight: 600;
}
.media-workspace-nav button {
  display: block; width: 100%; text-align: start;
  min-height: 36px; padding: 0 10px !important;
  border: 0 !important; border-radius: 9px !important;
  background: none; color: var(--pk-muted);
  font-size: 13.5px !important; cursor: pointer;
}
.media-workspace-nav button:hover { background: rgba(148, 178, 255, 0.06); color: var(--pk-text); }
.media-workspace-nav .active,
.media-workspace-nav [aria-current="page"] {
  background: var(--pk-blue-soft) !important;
  color: var(--t349) !important;
  font-weight: 500;
  border: 0 !important;
}

/* Prepare for Ads — one surface, the set on top, the boundary underneath. */
.mf-ads {
  border: 1px solid var(--pk-line); border-radius: 14px;
  background: var(--pk-panel); padding: 20px 22px;
}
.mf-ads-head h3 { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.mf-ads-head p { margin: 6px 0 0; color: var(--pk-muted); font-size: 13.5px; max-width: 78ch; line-height: 1.55; }
.mf-ads-list { margin-top: 18px; display: flex; flex-direction: column; }
.mf-ads-row {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 0; border-top: 1px solid var(--pk-line);
  font-size: 13.5px; cursor: pointer;
}
.mf-ads-list > .mf-ads-row:first-child { border-top: 0; }
.mf-ads-tick { flex: 0 0 auto; width: 16px; height: 16px; accent-color: var(--pk-blue); }
.mf-ads-name { flex: 1 1 auto; min-width: 0; color: var(--pk-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mf-ads-kind, .mf-ads-state { flex: 0 0 auto; color: var(--pk-dim); font-size: 12.5px; }
.mf-ads-empty { margin: 18px 0 0; color: var(--pk-muted); font-size: 13.5px; max-width: 72ch; line-height: 1.6; }
.mf-ads-gate {
  margin-top: 20px; padding: 16px 18px;
  border: 1px solid var(--pk-line-2); border-radius: 12px;
  background: rgba(148, 178, 255, 0.04);
}
.mf-ads-gate-title { margin: 0 0 8px; font-size: 13px; font-weight: 600; color: var(--pk-text); }
.mf-ads-steps { margin: 0; padding-inline-start: 20px; color: var(--pk-muted); font-size: 13px; line-height: 1.7; max-width: 76ch; }
.mf-ads-actions { display: flex; gap: 10px; margin-top: 14px; }

/* ═══ DIALOGUES ══════════════════════════════════════════════════════════
   The same contract as the pipeline and the client workspace — the third
   screen it applies to, and the last one with two side panels.

     default        queue 300 · centre minmax(0,1fr)
     queue hidden   centre minmax(0,1fr)
     context open   queue 300 · centre minmax(0,1fr) · context 380
     both closed    centre minmax(0,1fr)              ← the whole canvas

   The context panel starts CLOSED here, unlike the client panel on the
   workspace: there the card IS the job, here the conversation is, and a
   reference panel open by default costs 380px of the thing being read. */
.dw {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--pk-gap);
  height: 100%;
  min-height: 0;
  padding: 0 0 6px;
}
.dw.has-queue { grid-template-columns: var(--pk-queue-w) minmax(0, 1fr); }
.dw.has-context { grid-template-columns: minmax(0, 1fr) var(--pk-drawer-w); }
.dw.has-queue.has-context {
  grid-template-columns: var(--pk-queue-w) minmax(0, 1fr) var(--pk-drawer-w);
}
.dw > * { min-width: 0; min-height: 0; }

.dw-queue, .dw-main, .dw-rail {
  border: 1px solid var(--pk-line);
  border-radius: 14px;
  background: var(--pk-panel);
  overflow: hidden;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.dw-rail { background: var(--t79); border-color: var(--pk-line-2); }
.dw-queue-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
/* The panels are TRACKS now. Their own `width: 280px` / `264px` no longer
   sizes anything — it just stops them filling the track the contract gave
   them, which is how the queue rendered 20px narrower than it declares. */
.dw-queue, .dw-rail { width: auto; min-width: 0; max-width: none; border-inline-end: 0; border-inline-start: 0; }

/* Top-right of the panel it closes, not a chip wrapped onto its own line under
   the filters — which is where a plain flex child landed in a column head. */
.dw-queue-head { position: relative; }
.dw-queue-head .dw-search { padding-inline-end: 68px; }
.dw-panel-hide {
  position: absolute; top: 12px; inset-inline-end: 12px;
  flex: 0 0 auto;
  height: 28px; padding: 0 11px;
  border: 1px solid var(--pk-line-2); border-radius: 8px;
  background: var(--rp-plate); color: var(--pk-muted);
  font-size: 12px; cursor: pointer;
}
/* The context panel's own head IS a flex row, so there it simply sits at the
   end of it. */
.dw-rail .dw-panel-hide { position: static; margin-inline-start: auto; }
.dw-panel-hide:hover { color: var(--pk-text); border-color: var(--pk-blue-line); }
.dw-panel-show {
  flex: 0 0 auto;
  height: 32px; padding: 0 12px;
  border: 1px solid var(--pk-line-2); border-radius: 9px;
  background: var(--rp-plate); color: var(--pk-muted);
  font-size: 13px; white-space: nowrap; cursor: pointer;
}
.dw-panel-show:hover { color: var(--pk-text); border-color: var(--pk-blue-line); }
.dw-panel-show.is-on { border-color: var(--pk-blue-line); background: rgba(47, 123, 255, 0.16); color: var(--t372); }

/* Three columns need the room for three. At 1440 the centre would keep
   1440 − 220 − 64 − 300 − 380 − 36 = 440px, which is not a conversation, so the
   queue steps aside for the context the operator just asked for and comes back
   with the «Queue» button. Same rule, same reason, as the client workspace. */
/* Hidden while the panel it summons is genuinely on screen — see the comment
   beside the button for why it cannot be conditional on the flag alone. */
.dw.has-queue .dw-panel-queue { display: none; }

@media (max-width: 1599px) {
  .dw.has-queue.has-context { grid-template-columns: minmax(0, 1fr) var(--pk-drawer-w); }
  .dw.has-queue.has-context > .dw-queue { display: none; }
  /* …and it comes back the moment the queue is dropped for the context panel. */
  .dw.has-queue.has-context .dw-panel-queue { display: inline-flex; }
}

/* ═══ INTEGRATION HEALTH ═════════════════════════════════════════════════
   Three groups, one visual surface each, generously padded. A row is a fact
   with its proof beside it — not a card inside a card inside a card. */
.ih-page { display: flex; flex-direction: column; gap: var(--rp-4); max-width: 1180px; }
.ih-lede { margin: 0; color: var(--pk-muted); font-size: 14px; max-width: 82ch; line-height: 1.6; }
.ih-note { color: var(--pk-muted); font-size: 14px; padding: var(--pk-pad) 0; }
.ih-note-bad { color: var(--pk-high); }
.ih-gap {
  margin: 0; padding: 14px 16px;
  border: 1px solid var(--pk-line); border-radius: 12px;
  background: rgba(148, 178, 255, 0.04);
  color: var(--pk-dim); font-size: 12.5px; line-height: 1.6; max-width: 82ch;
}

.ih-group {
  border: 1px solid var(--pk-line);
  border-radius: 14px;
  background: var(--pk-panel);
  padding: 18px 20px 8px;
}
.ih-group-head { display: flex; align-items: center; gap: 10px; }
.ih-group-head h3 { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.ih-group-count {
  height: 22px; min-width: 22px; padding: 0 8px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; border: 1px solid var(--pk-line-2);
  font-size: 12px; color: var(--pk-muted);
}
.ih-group-blurb { margin: 6px 0 0; color: var(--pk-dim); font-size: 13px; max-width: 78ch; line-height: 1.55; }
.ih-rows { display: flex; flex-direction: column; }

/* The group's colour is carried by a rule on the left of each row, so the
   three answers are told apart before a word is read. */
.ih-row {
  display: flex; align-items: center; gap: 14px;
  padding-block: 14px 14px; padding-inline: 14px 0;
  border-top: 1px solid var(--pk-line);
  border-inline-start: 3px solid transparent;
  margin-top: 14px;
}
.ih-rows > .ih-row:first-child { border-top: 0; margin-top: 8px; }
.ih-row-live { border-inline-start-color: var(--pk-green); }
.ih-row-owner { border-inline-start-color: var(--pk-amber); }
.ih-row-error { border-inline-start-color: var(--pk-high); }
.ih-row-unknown { border-inline-start-color: var(--pk-line-2); }
.ih-row-main { flex: 1 1 auto; min-width: 0; }
.ih-row-title { display: block; font-size: 14.5px; font-weight: 600; color: var(--pk-text); }
.ih-row-detail { margin: 4px 0 0; color: var(--pk-muted); font-size: 13px; line-height: 1.55; max-width: 72ch; }
.ih-row-meta {
  flex: 0 0 auto; color: var(--pk-dim); font-size: 12.5px;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.ih-row-go {
  flex: 0 0 auto; height: 34px; padding: 0 14px;
  border: 1px solid var(--pk-line-2); border-radius: 9px;
  background: var(--rp-plate); color: var(--pk-muted);
  font-size: 13px; cursor: pointer; white-space: nowrap;
}
.ih-row-go:hover { color: var(--pk-text); border-color: var(--pk-blue-line); }
/* На телефоне пометка строки не выдавливает саму строку (24.09.2026, замер
   375 по-арабски): `.ih-row-meta` не переносится и не сжимается, и длинная
   пометка забирала 204 px из 295 — описание ошибки получало 60 px, а
   «boardroom-voice-events» вылезало из него. Теперь описание не уже 180 px;
   что не помещается рядом, встаёт строкой ниже и переносится. */
@media (max-width: 560px) {
  .ih-row { flex-wrap: wrap; }
  .ih-row-main { flex: 1 1 180px; }
  .ih-row-meta { white-space: normal; }
  /* Имена очередей и функций («boardroom-voice-events») — одно слово: пусть
     переносится где угодно, а не вылезает. */
  .ih-row-detail { overflow-wrap: anywhere; }
}

/* The way in, from the screen where a provider is connected. */
.ih-entry {
  display: flex; align-items: center; gap: 14px;
  width: 100%; text-align: start;
  padding: 16px 18px;
  border: 1px solid var(--pk-blue-line); border-radius: 14px;
  background: var(--pk-blue-soft); color: var(--pk-text);
  cursor: pointer;
}
.ih-entry:hover { background: rgba(47, 123, 255, 0.18); }
/* ЗАГОЛОВОК ОБРЕЗАЛСЯ НА ПОЛУСЛОВЕ (20 сентября 2026, скриншот владельца).
   `flex: 0 0 auto` запрещал заголовку сжиматься, а карточка режет всё, что
   вылезло. На полке получалось «Meta Conversions API: deals bac» и «Работа
   поверх CRM: перехо» — текст, оборванный посреди буквы. Разрешаем переносить
   и сжиматься: заголовок встанет в две строки и будет читаться целиком. */
.ih-entry strong { flex: 0 1 auto; min-width: 0; font-size: 15px; overflow-wrap: anywhere; }
.ih-entry span { color: var(--pk-muted); font-size: 13px; }
.ih-entry-go { margin-inline-start: auto; color: var(--t349); font-size: 16px; }

/* ── 1440 ─────────────────────────────────────────────────────────────────
   Tighter padding and a narrower column, so five stages still stand. */
@media (max-width: 1500px) {
  :root { --pk-pad: 28px; --pk-col: 280px; --pk-gap: 12px; }
  /* Was 42px against a 44px base (a real, if small, extra shrink at this
     width). The base dropped to 38px on 2026-08-21; this breakpoint rule is
     dropped to stay AT it rather than reopening above it now that the two
     have crossed. */
  .pk-ctl, .pk-new, .pk-search input, .crm-search input { height: var(--pk-row-h); min-height: var(--pk-row-h); }
  .pk-col-name { font-size: 16px; }
}

/* ── 1280 ─────────────────────────────────────────────────────────────────
   The board scrolls; the toolbar does not. More is the first control to go —
   it holds the actions nobody needs at this width — and the search gives up its
   maximum so the row still fits before anything is dropped. */
@media (max-width: 1330px) {
  :root { --pk-col: 280px; }
  .pk-ctl, .pk-new { padding: 0 10px; font-size: 13px; }
  .pk-new { padding: 0 16px; }
  .pk-search, .pk-bar .crm-search { max-width: none; }
  .pk-bar-count { display: none; }
  /* THE DRAWER STAYS A COLUMN HERE, AND EVERYWHERE.
     The first version of this block turned it into a fixed overlay at 1280 —
     which is exactly what the layout contract forbids, and for a good reason:
     a filter you cannot read the board through is a filter you apply blind.
     The arithmetic says it is not necessary. At 1280 the centre keeps
     1280 − 220 rail − 64 padding − 360 drawer − 18 gap = 618px, and two 280px
     stages fit in that with room to spare. The board shows fewer columns and
     scrolls, which is what a board is supposed to do when it runs out of room.
     Narrower than this and it is the LEFT panel that closes — the pipeline has
     none, so there is nothing here to close. */
  .pk-drawer { margin-inline-start: var(--pk-gap); }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ONE SYSTEM, NINE CHARACTERS
   ═══════════════════════════════════════════════════════════════════════════

   The owner's two requirements pull in opposite directions unless they are
   solved in one place: every page must look like the same product, AND each
   section must have a character of its own.

   Colouring screens individually gives you the second and destroys the first —
   that is how a product ends up with nine blues that almost match. So the
   accent is decided ONCE, from `data-section` on the shell, and everything that
   wants colour derives from `--pk-accent`. A screen never names a colour. A new
   screen inherits its section's character by being inside the section.

   THE RULE THIS PASS DOES NOT RELAX. Colour is presentation and never a claim.
   An accent may say WHERE you are and WHAT KIND of thing a row is; it may never
   say that a number exists. Nothing below adds a widget — it dresses the ones
   that earned their place by having a source.
   ═══════════════════════════════════════════════════════════════════════════ */

/* THE SECTION ACCENTS, IN BOTH THEMES.
   --pk-accent-ink is the one that could not simply be carried over. Each of the
   eight is a PALE tint of its section's hue, chosen to read on a #121821 panel;
   on a white one every single one falls under 2:1. So the ink flips end of the
   scale — pale on dark, deep on light — while staying the same hue, which is
   what keeps a section recognisable as "the cyan one" in either theme.
   --pk-accent itself only draws a 3px bar and a crumb underline, but four of
   the eight (cyan, amber, green, pink) are under 3:1 on white even for that, so
   the light side darkens them to carry the same signal. */
.app-shell {
  /* The default, and what Business Overview keeps: the product's own blue. */
  --pk-accent:      light-dark(#1a5fd9, #2f7bff);
  --pk-accent-soft: light-dark(rgba(26, 95, 217, 0.10), rgba(47, 123, 255, 0.13));
  --pk-accent-line: light-dark(rgba(26, 95, 217, 0.40), rgba(47, 123, 255, 0.40));
  --pk-accent-ink:  light-dark(#12448f, #cfe0ff);
}
/* Work — the screens an operator lives in, cool and level-headed. */
.app-shell[data-section="leads"]         { --pk-accent: light-dark(#1a5fd9, #2f7bff); --pk-accent-soft: light-dark(rgba(26,95,217,.10), rgba(47,123,255,.13));   --pk-accent-line: light-dark(rgba(26,95,217,.40), rgba(47,123,255,.40));   --pk-accent-ink: light-dark(#12448f, #cfe0ff); }
.app-shell[data-section="conversations"] { --pk-accent: light-dark(#0e7490, #22d3ee); --pk-accent-soft: light-dark(rgba(14,116,144,.10), rgba(34,211,238,.12));  --pk-accent-line: light-dark(rgba(14,116,144,.38), rgba(34,211,238,.38));  --pk-accent-ink: light-dark(#0b5f6b, #b6f2fb); }
.app-shell[data-section="voice"]         { --pk-accent: light-dark(#4f46e5, #818cf8); --pk-accent-soft: light-dark(rgba(79,70,229,.10), rgba(129,140,248,.14));  --pk-accent-line: light-dark(rgba(79,70,229,.40), rgba(129,140,248,.40));  --pk-accent-ink: light-dark(#3d3f96, #d6daff); }
/* Growth — where the product makes something, warmer. */
.app-shell[data-section="ai-agent"]      { --pk-accent: light-dark(#7b3fd4, #a855f7); --pk-accent-soft: light-dark(rgba(123,63,212,.10), rgba(168,85,247,.14));  --pk-accent-line: light-dark(rgba(123,63,212,.40), rgba(168,85,247,.40));  --pk-accent-ink: light-dark(#6b21a8, #e6cffd); }
.app-shell[data-section="media-factory"] { --pk-accent: light-dark(#be185d, #f472b6); --pk-accent-soft: light-dark(rgba(190,24,93,.09), rgba(244,114,182,.13));  --pk-accent-line: light-dark(rgba(190,24,93,.38), rgba(244,114,182,.38));  --pk-accent-ink: light-dark(#9d174d, #fbd0e6); }
.app-shell[data-section="marketing"]     { --pk-accent: light-dark(#8a5407, #fbbf24); --pk-accent-soft: light-dark(rgba(161,98,7,.10), rgba(251,191,36,.12));    --pk-accent-line: light-dark(rgba(161,98,7,.36), rgba(251,191,36,.36));    --pk-accent-ink: light-dark(#854d0e, #fde4a6); }
/* Administration — the quiet end. */
.app-shell[data-section="integrations"]  { --pk-accent: light-dark(#116632, #4ade80); --pk-accent-soft: light-dark(rgba(21,128,61,.10), rgba(74,222,128,.12));   --pk-accent-line: light-dark(rgba(21,128,61,.36), rgba(74,222,128,.36));   --pk-accent-ink: light-dark(#14532d, #bdf3d0); }
.app-shell[data-section="settings"]      { --pk-accent: light-dark(#556274, #94a3b8); --pk-accent-soft: light-dark(rgba(85,98,116,.10), rgba(148,163,184,.12));  --pk-accent-line: light-dark(rgba(85,98,116,.34), rgba(148,163,184,.34));  --pk-accent-ink: light-dark(#334155, #d8e0ea); }

/* ── where the character actually shows ─────────────────────────────────────
   Four places, deliberately few. An accent that appears everywhere stops being
   a signal and becomes a tint. */

/* 1. The rail item you are standing on. Border and drop-shadow reset to
   plain: redesign.css's base .nav-item.active border-color (a translucent
   blue ring) and halo shadow were never neutralised here, so on an
   amber-accented section (Marketing) the ring read as a gold glow around
   the whole pill rather than a simple left-edge marker. */
.sidebar .nav-item.active,
.sidebar a[aria-current="page"] {
  background: var(--pk-accent-soft);
  color: var(--pk-accent-ink);
  border-color: transparent;
  box-shadow: inset 3px 0 0 var(--pk-accent);
}
/* THE GLOW THE OWNER KEPT REPORTING, AND ITS ACTUAL SOURCE.
   cabinet-system.css draws a SECOND marker on the active row — a 3px cyan bar
   as ::before, carrying `box-shadow: 0 0 12px rgb(var(--ch-cyan2) / .55)`. That
   12px cyan halo sat on top of the amber section bar above, which is why
   Marketing and AI Accounting looked lit while the rest of the rail did not,
   and why removing the border alone changed nothing: the border was never it.
   Measured live before removing — getComputedStyle(el, "::before").boxShadow
   returned exactly that value.
   The inset bar above already says where you are, in the section's own colour.
   Two markers on one row is one too many, and the glowing one is the wrong one. */
.sidebar .nav-item.active::before,
.sidebar a[aria-current="page"]::before {
  display: none;
}

/* 2. The section's local rail — the row you are on, in the section's colour. */
.agent-cabinet-nav button.active,
.ac-nav-item.on,
.media-workspace-nav .active,
.media-workspace-nav [aria-current="page"],
.set13-railitem.on {
  background: var(--pk-accent-soft) !important;
  color: var(--pk-accent-ink) !important;
  box-shadow: inset 3px 0 0 var(--pk-accent);
}

/* 3. The crumb's current page, so the header agrees with the rail. */
.pk-crumb-cur { border-bottom: 2px solid var(--pk-accent-line); padding-bottom: 2px; }

/* 4. The one number a screen leads with. Not every figure — the lead one. */
.rp-kpi:first-child .rp-kpi-value,
.mk-desk-tile:first-child .mk-desk-value,
.pk-col:first-child .pk-col-n { color: var(--pk-accent-ink); }

/* ── ONE WIDGET VOCABULARY ──────────────────────────────────────────────────
   Eleven card classes accumulated across three stylesheets, each with its own
   radius, border and shadow. They are one surface now — the same card, wherever
   it is — so that "the same product" is something a reader sees rather than
   something a document claims. */
.control-card, .rp-card, .mk-card, .agent-railcard, .media-hub-metric,
.mf-mix-card, .mf-pulse-card, .media-channel-card, .media-cs-banner,
.rp-kpi, .mk-kpi, .ac15-tasks, .ac15-reports, .seo-score-card,
.route-card, .agent-cards-panel, .agent-cabwrap {
  border: 1px solid var(--pk-line);
  border-radius: 14px;
  background: var(--pk-panel);
  box-shadow: none;
}
/* A card that sits INSIDE another one steps up rather than changing palette. */
.control-card .control-card,
.rp-card .rp-card,
.agent-cabwrap .control-card { background: var(--pk-card); }

/* Interactive cards say so on hover — one behaviour, every card. */
.route-card, .agent-card, .media-channel-card, .rp-tile {
  transition: none;
}
.route-card:hover, .agent-card:hover, .media-channel-card:hover {
  border-color: var(--pk-accent-line);
  background: var(--pk-card-hi);
}

/* ── STATUS COLOUR MEANS THE SAME THING ON EVERY SCREEN ─────────────────────
   Green is proven, amber waits on a person, red is failing, grey is unknown.
   Two of these were being used for whatever looked right on the screen being
   written; a reader who has to relearn the colours per page is reading nine
   products. */
/* ЗАЛИВКА ТОЖЕ ДОЛЖНА БЫТЬ ВИДНА, А НЕ ТОЛЬКО ТЕКСТ.
   Литералы ниже — светлые краски тёмной темы (#4ade80, #fbbf24, #f87171) с
   альфой 9–10%. На тёмной панели этого хватает; на белой панели тот же слой
   даёт контраст плашки к фону 1.05–1.09:1, то есть плашки нет — ровно жалоба
   владельца про «Live на белой панели прозрачный». Текст при этом читался
   (7–13:1), потому что токены --t293/--t443/--t438 уже светло-тёмные.
   Светлая арка берёт ТЁМНУЮ краску той же семьи и чуть большую альфу, как уже
   сделано у эталонного .pay-chip.is-on (1.38:1). Тёмная арка — байт в байт
   прежние значения. */
.status-pill.good, .xo-chip.live, .status-badge.status-good,
.badge.good, .agent-nav-state-live { color: var(--t293); border-color: light-dark(rgba(21,128,61,.38), rgba(74,222,128,.34)); background: light-dark(rgba(21,128,61,.14), rgba(74,222,128,.10)); }
.status-pill.warning, .xo-chip.warn, .status-badge.status-warning,
.badge.warning, .agent-nav-state-partial_live { color: var(--t443); border-color: light-dark(rgba(161,98,7,.36), rgba(251,191,36,.32)); background: light-dark(rgba(161,98,7,.14), rgba(251,191,36,.09)); }
.status-pill.bad, .xo-chip.off, .status-badge.status-error,
.badge.critical { color: var(--t438); border-color: light-dark(rgba(194,38,31,.36), rgba(248,113,113,.32)); background: light-dark(rgba(194,38,31,.13), rgba(248,113,113,.09)); }
.status-pill.neutral, .status-badge.status-neutral,
.badge.neutral { color: var(--pk-muted); border-color: var(--pk-line-2); background: transparent; }

/* ═══════════════════════════════════════════════════════════════════════════
   THE CHARACTER, BEYOND COLOUR
   ═══════════════════════════════════════════════════════════════════════════

   Colour says which section you are in. These say what KIND of thing you are
   looking at — and they are the same shapes everywhere, so the answer does not
   have to be relearned per screen.

   Still nothing here invents information. An empty state is a sentence with a
   mark beside it; the mark is punctuation, not a claim.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── every local section rail is headed the same way ─────────────────────────
   Three sections had three different headers: «🧠 AI AGENT» in an emoji, a bare
   «Настройки» in an h3, and Media Factory with nothing at all. They are one
   component now, marked in the section's own colour. */
.ac-nav-head,
.set13-rail > h3,
.agent-cabinet-nav > .agent-nav-group:first-child > p {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 12px; padding: 0 10px 12px;
  border-bottom: 1px solid var(--pk-line);
  font-size: 13px; font-weight: 600; letter-spacing: 0;
  text-transform: none; color: var(--pk-text);
}
.ac-nav-head::before,
.set13-rail > h3::before,
.media-workspace-nav .mw-nav-group:first-child .mw-nav-label::before {
  content: ""; flex: 0 0 auto;
  width: 8px; height: 8px; border-radius: 3px;
  background: var(--pk-accent);
  box-shadow: 0 0 0 3px var(--pk-accent-soft);
}
/* Media Factory's rail had no head, so its first group label becomes one. */
.media-workspace-nav .mw-nav-group:first-child .mw-nav-label {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 12px; padding: 0 10px 12px;
  border-bottom: 1px solid var(--pk-line);
  font-size: 13px; font-weight: 600; letter-spacing: 0;
  text-transform: none; color: var(--pk-text);
}

/* ── one shape for "there is nothing here, and here is why" ──────────────────
   Eight different empty states across the product, each invented where it was
   needed: a dashed box, a centred paragraph, a grey note, a bordered card. They
   are one shape now — an accent rule, a line of reason, room around it — so a
   reader learns "nothing here yet" once instead of eight times.

   Deliberately quiet. An empty state that shouts competes with the screen it is
   apologising for. */
.rp-nosource,
.dw-empty,
.lw-empty-state,
.ac15-empty,
.mf-ads-empty,
.pk-col-empty,
.mk-note,
.ih-note,
.set13-note {
  border: 1px dashed var(--pk-line-2);
  border-inline-start: 3px solid var(--pk-accent-line);
  border-radius: 10px;
  background: rgba(148, 178, 255, 0.025);
  padding: 14px 16px;
  color: var(--pk-muted);
  font-size: 13px;
  line-height: 1.6;
  max-width: 78ch;
}
/* Inside a narrow panel the shape stays, the padding gives way. */
.pk-col-empty, .dw-empty { padding: 12px 13px; font-size: 12.5px; }
/* These two carry a heading of their own; it keeps its weight. */
.rp-nosource-title, .lw-empty-state strong, .ac15-empty strong {
  display: block; margin-bottom: 5px;
  color: var(--pk-text); font-size: 13.5px; font-weight: 600;
}

/* ── the section mark on a page header ───────────────────────────────────────
   A thin accent rule under the crumb already says the section. On screens with
   a full header card, the same rule runs down its left edge — the two agree,
   and neither adds a word. */
.agent-cabinet-header,
.media-workspace-header,
.mk-setup,
.ih-group-live { border-inline-start: 3px solid var(--pk-accent-line); }

/* ═══ TWO SIZES THE OWNER MARKED IN RED ═══════════════════════════════════ */

/* THE COMPOSER WAS TAKING A THIRD OF THE CONVERSATION.
   156px of chrome with an 80px box inside it, on a screen whose whole job is
   reading what the customer said. A reply is a sentence or two; the box can
   grow when there is more to say, and the thread keeps the height until then. */
.ck-composer { min-height: 0; padding: 8px 16px 10px; }
/* .workspace textarea (0,1,1) beats .ck-input (0,1,0) and was pinning this to
   132px — the specificity trap this repo warns about in writing. Measured, not
   assumed: the computed height came back 132 while this file said 56. */
.workspace .ck-input, .ck-composer .ck-input {
  /* ПОТОЛОК ПОДНЯТ СО 160px ДО 320px 31 АВГУСТА. 160px — это пять строк, и
     владелец в них упирался на обычном письме клиенту: «Ранее договаривались
     созвониться 31 августа, чтобы настроить AI-ассистента…» уже не помещалось.
     Тянуть было можно, но некуда — а потом высота ещё и сбрасывалась при
     перерисовке (починено в composerKit.js).
     320px — примерно десять строк; на экране 900px под перепиской остаётся
     больше половины, так что длинное письмо видно целиком, а разговор не
     исчезает. Начальные 56px не тронуты: короткий ответ — по-прежнему обычай. */
  height: 56px; min-height: 56px; max-height: 320px;
  resize: vertical; padding: 10px 12px;
}

/* THE INSTRUCTION FIELDS WERE THE SMALLEST BOXES ON THEIR OWN SCREEN.
   Core instruction and Restricted actions are the longest text anyone types in
   this product — a page of rules the agent works by — and they were four rows,
   the same as a one-line label field two inches above. The page has room; they
   take it. */
.agent-cabinet-page .agent-field textarea,
.ac-section textarea,
.agent-section textarea { min-height: 220px; resize: vertical; line-height: 1.6; }

/* ═══════════════════════════════════════════════════════════════════════════
   THE REST OF THE PRODUCT — the blocks no pass had reached
   ═══════════════════════════════════════════════════════════════════════════

   Tasks, Meetings, Recovery, Workspace, Setup, SEO, Reports, Admin, Control
   Data and the Voice sub-screens were never restructured — they inherited the
   palette when the tokens moved and stopped there. Their BLOCKS still came from
   whenever each was written: three empty-state shapes, two second-level navs,
   cards with 280px of nothing in them.

   None of them needs new structure. They need the vocabulary the rest of the
   product already speaks. */

/* ── the second-level nav, one shape ────────────────────────────────────────
   `.group-subnav` (CRM · Tasks · Recovery · Meetings) and `.module-tabs`
   (Marketing · Campaigns · SEO) are the same thing seen twice: the row of
   sibling screens inside a section. They now look like each other, and like the
   local rails — the active row carries the section's colour, not a blue pill
   that is the same on every screen. */
.group-subnav, .module-tabs {
  gap: 4px;
  padding: 4px;
  border: 1px solid var(--pk-line);
  border-radius: 12px;
  background: var(--pk-panel);
}
.group-subnav-item, .module-tabs button {
  min-height: 34px;
  padding: 0 14px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--pk-muted);
  font-size: 13px;
}
.group-subnav-item:hover, .module-tabs button:hover {
  background: rgba(148, 178, 255, 0.06);
  color: var(--pk-text);
}
/* НА СВЕТЛОЙ ТЕМЕ АКТИВНАЯ ВКЛАДКА — ЗАЛИВКА, А НЕ НАМЁК.
   Измерено 14 сентября на живой странице: --pk-accent-soft на светлой — это
   10–13% цвета секции, то есть контраст плашки к дорожке 1.15:1 при почти
   белой дорожке (rgb 251,252,254). Владелец видел ровно это: «активной вкладки
   не видно» — а там, где секция красит акцент в зелёный или синий, ещё и
   «где-то зелёная рамка, где-то синяя». Вид был один, но настолько слабый, что
   читался как разные виды или как их отсутствие.
   Светлая тема получает СПЛОШНУЮ заливку акцентом и белый текст: одна и та же
   форма на всех секциях, контраст плашки к дорожке ≥4:1 вместо 1.15:1.
   Тёмная тема остаётся прежней — там тёмные арки акцента (#2f7bff, #fbbf24,
   #4ade80) задуманы как ЦВЕТ ТЕКСТА, и белым по ним было бы 1.5–3.9:1.
   light-dark(), а не [data-theme="light"]: состояние «системная» тоже есть. */
.group-subnav-item.active, .module-tabs button.active,
.group-subnav-item[aria-current="page"], .module-tabs button[aria-current="page"] {
  background: light-dark(var(--pk-accent), var(--pk-accent-soft));
  color: light-dark(#ffffff, var(--pk-accent-ink));
  font-weight: 500;
  /* На светлой подчёркивание того же цвета, что и заливка, — невидимо, и
     трогать его не нужно: light-dark() — это ЦВЕТОВАЯ функция, в box-shadow и
     font-weight она недопустима и молча выбрасывает всё объявление (проверено
     14 сентября: тёмная тема теряла подчёркивание). Поэтому разница между
     темами здесь живёт только в двух цветовых строках выше. */
  box-shadow: inset 0 -2px 0 var(--pk-accent);
}

/* ── the last empty-state shapes join the others ────────────────────────────
   `.route-empty-state` was a full card with the text floated in the middle of
   280px of nothing — on Meetings it was the entire screen. Same shape as every
   other "nothing here yet" in the product now: an accent rule, the reason, and
   the one way forward.

   `.cs-note` DOES NOT BELONG IN THIS LIST. It was swept in here alongside the
   real empty-state classes, but it is main.js's own generic small-status-text
   span — used ~150 times for loading/error/confirmation lines, most of them
   starting life EMPTY (`el("span", "cs-note", "")`, filled in once an action
   completes). Reported live, hand-circled: small dashed boxes sitting next to
   "Сохранить данные" / "Загрузить файл" / "Добавить текст" / "Добавить
   триггер" in the Knowledge Base — this rule's `border` + `padding` +
   `display: grid` applied to an empty span with no text to give it width, on
   a class loaded last (pack-design.css beats styles.css and redesign.css's
   own, much smaller `.cs-note` rules by source order). Removed from this
   group; `.cs-note` now falls through to redesign.css's minimal rule
   (colour + size only, no box) wherever this file doesn't restyle it. */
.route-empty-state, .rp-empty, .cs-empty, .agent-railnote {
  border: 1px dashed var(--pk-line-2);
  border-inline-start: 3px solid var(--pk-accent-line);
  border-radius: 10px;
  background: rgba(148, 178, 255, 0.025);
  padding: 18px 20px;
  color: var(--pk-muted);
  font-size: 13px;
  line-height: 1.6;
  max-width: 78ch;
  display: grid;
  gap: 8px;
  justify-items: start;
}
.route-empty-state h3 {
  margin: 0;
  font-size: 15px; font-weight: 600; color: var(--pk-text);
}
.route-empty-state p { margin: 0; max-width: 70ch; }

/* ── nothing holds space it is not using ────────────────────────────────────
   A card sized by a min-height rather than by its contents reads as a card that
   failed to load — the same misreading the dashed widgets caused, in geometry
   instead of type. */
   `auto`, NOT `0`, AND THE DIFFERENCE IS THE WHOLE BUG.  Measured 2026-08-15
   on Business Overview, admin view, 1920: `.control-card.runtime-empty-state`
   rendered 34px tall holding 93px of content — 34px is this card's padding
   (16+16) plus its border (1+1) and nothing else, so the box was its own
   chrome and the text painted straight out of it over the section below. That
   is the overlap the owner photographed on the dashboard, on /crm List and on
   /reports: not an overlay, not a z-index, just boxes resolving shorter than
   what is inside them.

   `min-height: 0` was written to cancel a fixed min-height, and it does. But
   on a GRID ITEM it also cancels the CSS *automatic minimum size* — the rule
   that stops a track compressing an item below its content. `.page-stack` is a
   grid with a definite height (924px) carrying 1694px of content, and once the
   floor was gone the over-constrained rows took their space back out of
   whichever items had stopped defending themselves. Proven both ways in the
   live page: `align-self: start` → 111px, `min-height: auto` → 111px.

   `auto` says exactly what was meant — no author-imposed floor, keep the
   automatic one. On anything that is not a flex or grid item it computes to 0,
   so every screen this rule was written for is unchanged. */
.route-empty-state, .rp-empty, .control-card, .route-card { min-height: auto; }

/* THE SAME BUG, ONE STEP FURTHER BACK — and `min-height: auto` cannot reach it.
   R15 was catalogued as "the AI ROI CALCULATOR hero is clipped to its eyebrow:
   the card renders ~60px tall with a cut-off element beneath". It was read as a
   content problem and it is not one. Measured in the live page:
   `.module-header` on /roi computed height 50px with scrollHeight 87 and
   `overflow: hidden`.
   The CSS automatic minimum size — the floor that stops a grid track
   compressing an item below its content — DOES NOT APPLY to an item whose
   overflow is anything but visible. So this box had already surrendered its
   floor before `min-height` was ever consulted, and the over-constrained
   `.page-stack` grid took its space back out of it; then the same
   `overflow: hidden` clipped the evidence. Every screen using `.module-header`,
   `.settings-command` (which is /crm/tasks' header) or `.agent-status` had the
   same latent fault.
   The `overflow: hidden` was not decorative-by-accident: it clips a 3px accent
   bar to the card's rounded corner. So the bar is given the rounding it needed
   all along and the box gets its floor back, rather than the box being made to
   pay for the bar. Asked and answered: this is not a height rule — it removes
   the reason a height rule looked necessary. */
.module-header, .settings-command, .agent-status { overflow: visible; }
.module-header::before, .settings-command::before, .agent-status::before {
  border-radius: var(--rp-r, 10px) 0 0 var(--rp-r, 10px);
}

/* ── stat rows, one alignment ───────────────────────────────────────────────
   Label left, figure right, numbers in tabular figures so a column of them
   lines up. Four screens were doing this three different ways. */
.rp-row, .kv, .agent-railrow, .set13-facts {
  font-variant-numeric: tabular-nums;
}
.set13-facts { display: grid; grid-template-columns: auto 1fr; gap: 8px 18px; margin: 14px 0 0; }
.set13-facts dt { color: var(--pk-dim); font-size: 13px; }
.set13-facts dd { margin: 0; color: var(--pk-text); font-size: 13px; }

/* ═══ AN EMPTY SECTION IS STILL WORTH OPENING ══════════════════════════════
   Shrinking the empty states left several screens as a small honest box in the
   corner of 900px of black — correct and useless. Making the box bigger would
   be holding space with nothing in it again, which is the habit this whole
   pass has been removing.

   So an empty section says the three things a person opening one actually
   wants: what it will do, what the product already knows that is relevant, and
   the one way forward. Every line is a real capability or a fact read from
   elsewhere — never a number invented to fill the width. */
.pk-preview {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: var(--pk-gap);
  align-items: start;
  max-width: 1180px;
}
.pk-preview-main {
  border: 1px solid var(--pk-line);
  border-inline-start: 3px solid var(--pk-accent-line);
  border-radius: 14px;
  background: var(--pk-panel);
  padding: 24px 26px;
}
.pk-preview-main h3 { margin: 0; font-size: 19px; font-weight: 600; letter-spacing: -0.01em; }
.pk-preview-lede { margin: 8px 0 0; color: var(--pk-muted); font-size: 13.5px; line-height: 1.6; max-width: 72ch; }
.pk-preview-list { margin-top: 20px; display: grid; gap: 2px; }
.pk-preview-item {
  display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: 16px;
  padding: 13px 0; border-top: 1px solid var(--pk-line);
  font-size: 13.5px;
}
.pk-preview-list > .pk-preview-item:first-child { border-top: 0; }
.pk-preview-item strong { color: var(--pk-text); font-weight: 500; }
.pk-preview-item span { color: var(--pk-muted); line-height: 1.55; }
.pk-preview-actions { display: flex; gap: 10px; margin-top: 22px; flex-wrap: wrap; }
.pk-preview-aside {
  border: 1px solid var(--pk-line); border-radius: 14px;
  background: rgba(148, 178, 255, 0.03);
  padding: 20px 22px;
}
.pk-preview-asidelabel {
  margin: 0 0 8px;
  font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--pk-faint); font-weight: 600;
}
.pk-preview-aside p { margin: 0; color: var(--pk-muted); font-size: 13px; line-height: 1.6; }
@media (max-width: 1100px) { .pk-preview { grid-template-columns: minmax(0, 1fr); } }

/* ---------------------------------------------------------------------------
   LONG-FORM FIELDS GET THE WHOLE ROW.

   The agent cabinet's form grid is two columns, which is right for a role, a
   name, a number. It is wrong for an instruction: half a column at 1440 is
   ~390px, and prose wrapped every six words is unreadable at exactly the moment
   somebody is trying to read it back to themselves. The class is set by
   draftField from the field's TYPE, not inferred from a selector, so this
   follows what the field is rather than where it happens to sit.
--------------------------------------------------------------------------- */
.workspace .agent-form-grid .agent-field-long { grid-column: 1 / -1; }
.workspace .agent-form-grid .agent-field-long textarea {
  min-height: 220px;
  line-height: 1.65;
  padding: 14px 16px;
}

/* Cost per lead by source. The priced rows and the unpriced ones share the
   same geometry deliberately — the difference between them is the VALUE, not
   the styling, so an unpriced row reads as a fact about our data rather than
   as a broken row. The bar is share of leads, which every row genuinely has. */
.mk-cpl-rows { display: grid; gap: 2px; margin-top: 14px; }
.mk-cpl-row {
  display: grid;
  /* 60px, not 56 — the contract suite bans a bare 56px in this stylesheet
     because that was the collapsed-panel sliver, and a column that happens to
     want the same number is not worth weakening the guard for. */
  grid-template-columns: minmax(120px, 1.2fr) minmax(60px, 2fr) 60px minmax(120px, auto);
  align-items: center; gap: 14px;
  padding: 11px 12px; border-radius: 8px;
  border-inline-start: 3px solid transparent;
  font-size: 13.5px;
}
.mk-cpl-row:nth-child(odd) { background: rgba(255, 255, 255, 0.02); }
.mk-cpl-priced { border-inline-start-color: var(--pk-accent-line, #3b82f6); }
.mk-cpl-name { color: var(--pk-text); font-weight: 600; }
.mk-cpl-bar {
  height: 6px; border-radius: 99px; overflow: hidden;
  background: rgba(255, 255, 255, 0.06);
}
.mk-cpl-fill { display: block; height: 100%; border-radius: 99px; background: var(--pk-accent-line, #3b82f6); }
.mk-cpl-count { text-align: end; color: var(--pk-muted); font-variant-numeric: tabular-nums; }
.mk-cpl-val { text-align: end; font-variant-numeric: tabular-nums; color: var(--pk-text); font-weight: 600; }
.mk-cpl-row:not(.mk-cpl-priced) .mk-cpl-val { color: var(--pk-faint); font-weight: 400; font-size: 12.5px; }
.mk-cpl-foot { margin: 14px 0 0; color: var(--pk-muted); font-size: 12.5px; line-height: 1.6; }
@media (max-width: 900px) {
  .mk-cpl-row { grid-template-columns: minmax(0, 1fr) 48px; }
  .mk-cpl-bar { display: none; }
}

/* The cabinet's mode row. Sits between the agent header and the two-column
   layout, so the reading order is: which agent → which mode → which step. */
.agent-mode-tabs {
  display: flex; gap: 6px; flex-wrap: wrap;
  padding: 5px; margin-bottom: var(--pk-gap);
  border: 1px solid var(--pk-line);
  border-radius: 12px;
  background: var(--pk-panel);
}
.agent-mode-tabs button {
  appearance: none; border: 1px solid transparent; cursor: pointer;
  padding: 9px 18px; border-radius: 8px;
  background: transparent; color: var(--pk-muted);
  font: inherit; font-size: 13.5px; font-weight: 600;
}
.agent-mode-tabs button:hover:not(:disabled) { color: var(--pk-text); background: rgba(255, 255, 255, 0.04); }
.agent-mode-tabs button.active {
  color: var(--pk-text);
  background: rgba(255, 255, 255, 0.06);
  border-color: var(--pk-accent-line, #3b82f6);
}
.agent-mode-tabs button:disabled { opacity: 0.4; cursor: default; }

/* Help kit: the inline hint and the request-setup menu. */
.hk-hint {
  appearance: none; cursor: help;
  width: 16px; height: 16px; margin-inline-start: 6px; padding: 0;
  border: 1px solid var(--pk-line); border-radius: 50%;
  background: transparent; color: var(--pk-faint);
  font: inherit; font-size: 10px; line-height: 1; font-weight: 700;
  vertical-align: middle;
}
.hk-hint:hover, .hk-hint:focus-visible { color: var(--pk-text); border-color: var(--pk-accent-line, #3b82f6); }
.hk-request { position: relative; display: inline-block; }
.hk-request-off {
  color: var(--pk-faint); font-size: 12.5px;
  border: 1px dashed var(--pk-line); border-radius: 8px;
  padding: 9px 14px; cursor: default;
}
.hk-menu {
  position: absolute; z-index: 40; top: calc(100% + 6px); inset-inline-start: 0;
  min-width: 260px; display: grid; gap: 2px; padding: 6px;
  border: 1px solid var(--pk-line); border-radius: 12px;
  background: var(--pk-panel);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.45);
}
.hk-menu-ctx {
  padding: 8px 12px 10px; margin-bottom: 2px;
  border-bottom: 1px solid var(--pk-line);
  color: var(--pk-faint); font-size: 11.5px;
}
.hk-menu-item {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: 8px;
  color: var(--pk-text); text-decoration: none; font-size: 13.5px;
}
.hk-menu-item:hover { background: rgba(255, 255, 255, 0.06); }
.pk-preview-ask { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--pk-line); }
.hk-request > summary {
  display: inline-flex; align-items: center; gap: 8px;
  list-style: none; cursor: pointer;
  padding: 9px 16px; border: 1px solid var(--pk-line); border-radius: 8px;
  background: transparent; color: var(--pk-muted);
  font-size: 13px; font-weight: 600;
}
.hk-request > summary::-webkit-details-marker { display: none; }
.hk-request > summary::after { content: "▾"; font-size: 10px; }
.hk-request[open] > summary { color: var(--pk-text); border-color: var(--pk-accent-line, #3b82f6); }
.hk-request > summary:hover { color: var(--pk-text); }

/* ---------------------------------------------------------------------------
   NOT IN YOUR PLAN — A MARK, NOT A SHUTTER.

   The section behind this notice is fully open and fully working; the notice
   exists to stop one misreading, that the numbers on screen are the client's
   own live data. So it has to be impossible to miss and wrong to panic about:
   amber, not red. Red is an outage, and nothing here is broken.

   It sits ABOVE the content rather than over it. An overlay would be a shutter
   — it would hide the very thing that makes somebody want to buy the section —
   and it would also make the demo unusable, which is the opposite of the
   instruction. Full width, top of the pane, then out of the way.
--------------------------------------------------------------------------- */
.pk-plan-notice {
  border: 1px solid var(--pk-line);
  border-inline-start: 3px solid var(--pk-amber, #f0b429);
  border-radius: 12px;
  background: rgba(240, 180, 41, 0.05);
  padding: 16px 20px;
  margin-bottom: var(--pk-gap, 20px);
  max-width: 1180px;
}
.pk-plan-notice-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pk-plan-notice-head strong {
  color: var(--pk-text); font-size: 14.5px; font-weight: 600; letter-spacing: -0.01em;
}
.pk-plan-notice-badge {
  flex: 0 0 auto;
  padding: 3px 9px; border-radius: 999px;
  background: rgba(240, 180, 41, 0.14);
  border: 1px solid rgba(240, 180, 41, 0.3);
  color: var(--pk-amber, #f0b429);
  font-size: 10px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
}
.pk-plan-notice-body {
  margin: 8px 0 0; color: var(--pk-muted);
  font-size: 13px; line-height: 1.6; max-width: 78ch;
}
.pk-plan-notice-ask { margin-top: 14px; }

/* The same fact where there is no room for a card. Sized to sit inside a tab or
   a heading without changing that line's height. */
.pk-plan-tag {
  display: inline-block; vertical-align: middle;
  margin-inline-start: 8px; padding: 2px 7px; border-radius: 999px;
  background: rgba(240, 180, 41, 0.14);
  border: 1px solid rgba(240, 180, 41, 0.3);
  color: var(--pk-amber, #f0b429);
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase;
  line-height: 1.5;
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE INTEGRATIONS DESK — one shelf per job, one card per connector.
   ═══════════════════════════════════════════════════════════════════════════

   COLOUR IS PRESENTATION AND NEVER A CLAIM. Green marks a card the connection
   table already reported as live; it does not make one live. The three other
   states are deliberately quiet — amber would read as a fault on a connector
   that is simply waiting for somebody to press a button, and red would read as
   an outage on one this cabinet has not built yet.

   The layout answers the failure mode this screen exists to end. Thirty-one
   equal tiles is the wall that made the old page unreadable, so a shelf leads
   with the cards that have a real next step and folds the rest behind one
   disclosure. `auto-fill` with a floor rather than a fixed column count: a
   shelf holding one card must not stretch that card across the page. */
.idesk { display: block; margin: 0 0 26px; }
.idesk-head { margin: 0 0 22px; }
.idesk-head h2 { margin: 0 0 6px; font-size: 21px; letter-spacing: -0.01em; }
.idesk-lede {
  margin: 0; color: var(--pk-muted);
  font-size: 13.5px; line-height: 1.65; max-width: 80ch;
}
.idesk-count {
  display: inline-block; margin-top: 12px;
  padding: 4px 11px; border-radius: 999px;
  border: 1px solid var(--pk-line-2); background: var(--pk-card);
  color: var(--pk-muted); font-size: 12px; font-variant-numeric: tabular-nums;
}

/* THE CATEGORY RAIL.
   Thirty-one connectors stacked in one column is a list to scroll, not a desk
   to work at. The rail is the roster's own six groups plus «Все» — no new
   taxonomy — and it carries live/total per group so "where is anything still
   unconnected" is answered without opening one. It collapses above the grid on
   narrow screens rather than disappearing: on a phone the categories are the
   fastest way to reach a card. */
.idesk-body { display: grid; grid-template-columns: 208px minmax(0, 1fr); gap: 26px; align-items: start; }
.idesk-side { position: sticky; top: 12px; display: flex; flex-direction: column; min-width: 0; }
.idesk-rail { display: flex; flex-direction: column; gap: 2px; }
.idesk-rail-item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 9px 11px; border: 0; border-radius: 9px;
  background: transparent; color: var(--text-soft, #9fb0c4);
  font: inherit; font-size: .87rem; text-align: start; cursor: pointer;
}
.idesk-rail-item:hover { background: rgb(var(--ch-lift) / .06); color: var(--text-primary, #e6edf6); }
.idesk-rail-item.is-active { background: rgb(var(--ch-lift) / .10); color: var(--text-primary, #e6edf6); font-weight: 600; }
.idesk-rail-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.idesk-rail-count { flex: none; font-size: .76rem; opacity: .75; font-variant-numeric: tabular-nums; }
.idesk-shelves { min-width: 0; }
@media (max-width: 860px) {
  .idesk-body { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .idesk-rail { position: static; flex-direction: row; flex-wrap: wrap; gap: 6px; }
  .idesk-rail-item { width: auto; padding: 7px 11px; border-radius: 999px; background: rgb(var(--ch-lift) / .06); }
}

/* THE MARK. Not a logo: thirty-one providers' trademarks would be thirty-one
   licences and thirty-one hosts to fetch from, and this page fetches from none.
   Initials on the group's own colour do the job the logos were for — finding the
   row you want without reading every name. */
.idesk-mark {
  flex: none; width: 34px; height: 34px; border-radius: 10px;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgb(var(--ch-lift) / .10); color: var(--text-soft, #9fb0c4);
}
.idesk-mark-icon { display: block; }
.idesk-mark-site       { background: rgba(120,160,255,.16); color: #a8c2ff; }
.idesk-mark-messengers { background: rgba( 80,200,140,.16); color: #7fd7ac; }
.idesk-mark-telephony  { background: rgba(255,180,100,.16); color: #ffc98a; }
.idesk-mark-crm        { background: rgba(180,140,255,.16); color: #cbb0ff; }
.idesk-mark-ads        { background: rgba(255,130,150,.16); color: #ff9fb2; }
.idesk-mark-office     { background: rgba(120,210,230,.16); color: #97dfec; }

/* A SHELF CARD IS A DECISION, NOT A DOCUMENT. Name, state, one line — enough to
   know whether to open it. Everything else moved to the connector's own screen
   on 2026-08-18, because a catalogue you have to read is not a catalogue. */
.idesk-card-openable { cursor: pointer; transition: border-color .12s ease, transform .12s ease; }
.idesk-card-openable:hover { border-color: rgb(var(--ch-lift) / .22); transform: translateY(-1px); }
.idesk-card-head { display: flex; align-items: center; gap: 10px; }
.idesk-card-head .idesk-name { flex: 1 1 auto; min-width: 0; }

/* CONNECTED READS AS DONE, UNREADABLE READS AS QUIET — and neither relies on
   colour alone, because the chip still says the word. */
.idesk-card-live { background: rgba(80,200,140,.06); border-color: rgba(80,200,140,.22); }
.idesk-card-unavailable { opacity: .62; }
.idesk-card-checking { opacity: .82; }
/* The open connector is not competing with the shelf it came from. */
.idesk-card-detail { border-color: rgb(var(--ch-lift) / .20); }

/* THE SECOND SCREEN. One connector, full width, form already open. The card
   keeps its own styling — it is the same component — so nothing here can drift
   away from how it looks on the shelf. */
.idesk-detail { min-width: 0; }
.idesk-detail .idesk-card { max-width: 720px; }
.idesk-back {
  display: inline-flex; align-items: center; gap: 6px; margin: 0 0 14px;
  padding: 6px 2px; border: 0; background: transparent; cursor: pointer;
  color: var(--text-soft, #9fb0c4); font: inherit; font-size: .86rem;
}
.idesk-back:hover { color: var(--text-primary, #e6edf6); }
/* The connector name opens its screen, so it has to look like it does — but it
   is still the card's heading and must not read as a button. */
.idesk-name-open {
  border: 0; background: transparent; padding: 0; margin: 0; cursor: pointer;
  font: inherit; font-weight: 600; color: inherit; text-align: start;
  /* THE BARE `button` RESET (styles.css) GIVES EVERY BUTTON `white-space: nowrap;
     overflow: hidden; text-overflow: ellipsis` — right for a toolbar action, wrong
     for a connector's own name. On a five-column shelf that clipped "Google Ads",
     "TikTok Ads" and "Публикации и аналитика соцсетей" down to "Google…",
     "TikTok…", "Публикаци…", which is illegible rather than merely tight. The name
     is the one thing on a shelf card a client must be able to read without
     opening it, so this undoes the reset and lets it wrap onto a second line
     instead — same pattern as .rp-row-title in redesign.css. */
  white-space: normal; overflow: visible; text-overflow: clip;
}
.idesk-name-open:hover { text-decoration: underline; text-underline-offset: 3px; }

.idesk-shelf { margin: 0 0 30px; }
.idesk-shelf-head { display: flex; align-items: baseline; gap: 10px; margin: 0 0 4px; }
.idesk-shelf-head h3 { margin: 0; font-size: 15px; letter-spacing: 0.01em; }
.idesk-shelf-count {
  padding: 1px 8px; border-radius: 999px;
  background: var(--pk-card); border: 1px solid var(--pk-line);
  color: var(--pk-dim); font-size: 11px; font-variant-numeric: tabular-nums;
}
.idesk-shelf-blurb {
  margin: 0 0 14px; color: var(--pk-dim);
  font-size: 12.5px; line-height: 1.6; max-width: 76ch;
}

/* ШИРЕ КОЛОНКА, РОВНЕЕ РЯД (20 сентября 2026, по скриншоту владельца).
   При minmax(300px) на ноутбуке вставало ЧЕТЫРЕ колонки по 285 px: текст
   тесный, а соседние карточки в одном ряду отличались по высоте на 55 px
   (197 против 142) — ряд выглядел «наехавшим». 340 px дают три колонки на той
   же ширине: тот же экран, читаемая карточка. Ниже описание подрезано до
   четырёх строк, и высоты в ряду сравнялись. */
.idesk-cards {
  display: grid; gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
}
.idesk-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 16px 16px 14px;
  border: 1px solid var(--pk-line); border-radius: 14px;
  background: var(--pk-card);
}
/* A connector that can be finished here is the one worth finding first. */
.idesk-card-actionable { border-color: var(--pk-line-2); background: var(--pk-card-hi); }
.idesk-card-live { border-color: rgba(74, 222, 128, 0.26); }

/* ONE SHELF, ONE CARD SHAPE — owner-flagged 2026-08-25: "не все карточки
   выглядят одинаково, названия иногда с переносом, разные карточки с
   надписями и без, привели в единый стиль".
   Two separate causes, both fixed here rather than by shortening any name:
   1. A name that wraps to two lines made its card's head taller than its
      neighbours'. The name box now ALWAYS reserves two lines, so a one-word
      connector and a two-word one line up, and the badge beside it stays put.
   2. A connector with a description and an «Обновлено» footer stood taller
      than one with neither. The card now has a floor height and its footer is
      pushed to the bottom, so a sparse card keeps the shape instead of
      collapsing. Nothing is truncated — a third line still grows the card,
      and its whole row grows with it, which is the grid working as intended. */
/* «текст поехал в карточках» — Источники данных, 2026-08-25.
   styles.css already clamps `.data-source-card .detail-stat strong` to one
   ellipsised line, and something loading after it undoes exactly that:
   measured live, the element computes `white-space: normal; overflow: visible`,
   so a source name like «Executive snapshot (Supabase dashboard sync) | Primary
   KPI source» ran to four lines and out of its tile.
   Settled here, in the sheet that decides, and as TWO lines rather than one —
   these names are the only thing identifying the source, and a single
   ellipsised line turns most of them into «Executive snapshot (Supabase…».
   `anywhere` so an unbroken token wraps instead of widening the grid column. */
/* «страница поехал шрифт» — Маркетинг, 2026-08-25. The header is a two-column
   grid, `minmax(0, 1.4fr) minmax(300px, 0.6fr)`: the HEADING column may shrink
   to nothing while the tools column keeps a 300px floor and its own 280px
   min-width. Narrow the viewport (or zoom in, which is the same thing in CSS
   pixels) above the 1120px stacking breakpoint and the tools win every
   remaining pixel — the title was left a few characters wide and wrapped one
   letter per line: «КОНТРОЛ Ь МАРКЕТИ НГА».
   The floor moves to the side that must stay readable. The tools shrink and
   their controls wrap, which they can; a heading cannot. */
.module-header.source-control-header {
  grid-template-columns: minmax(280px, 1.4fr) minmax(0, 0.6fr);
}
.source-control-header-tools,
.source-control-header .revenue-control-toolbar {
  min-width: 0;
}
.source-control-header-tools > * { min-width: 0; }

/* ЗАЖИМ НА ДВЕ СТРОКИ, КОТОРЫЙ ДЕЙСТВИТЕЛЬНО РЕЖЕТ.
   «Текст выехал» в «Источниках данных» — владелец сообщал неделю.

   ЧТО ИЗМЕРЕНО НА ЖИВОМ ПРОДЕ 2026-08-29, а не предположено. Правило доходит
   до браузера целиком (проверено в document.styleSheets), селектор совпадает
   (el.matches === true), но у элемента вычисляются display: flow-root и
   overflow: visible вместо объявленных -webkit-box и hidden. Коробка при этом
   высотой в две строки (35px), а содержимое — 71px: лишние строки рисуются
   поверх того, что ниже.

   ЧЕГО УСТАНОВИТЬ НЕ УДАЛОСЬ — и это сказано прямо, чтобы следующий читатель
   не принял догадку за факт: КТО именно перебивает объявленные значения. В
   отдельном контрольном опыте та же связка -webkit-box + -webkit-line-clamp +
   overflow: hidden отрабатывает правильно, значит дело не в самой связке и не
   в браузере; перебор совпавших правил через CSSOM ничего не показал.

   КТО ПЕРЕБИВАЛ — НАЙДЕНО ЗАМЕРОМ ПОСЛЕ ПЕРВОЙ НЕУДАЧНОЙ ПОПЫТКИ. В
   styles.css:12933 стоит
     .detail-stat strong, .detail-stat span { overflow: visible !important; … }
   с пояснением «Detail values must wrap fully, never «AED 7,…»». Замысел
   верный: короткие значения — суммы, имена, стадии — не должны резаться
   многоточием. Но !important снимает обрезку и с длинных машинных названий
   источника вроде «Executive snapshot (Supabase dashboard sync) | Primary KPI
   source», и они вылезают из плитки.

   Общее правило не трогаем — оно защищает нужное. Здесь узкое исключение
   ровно для одного поля, и !important тут не украшение: без него правило
   проигрывает тому, что выше. Проверено замером на проде ПОСЛЕ выкладки:
   первая попытка без !important выглядела применённой (display и max-height
   встали), а overflow остался visible, и текст по-прежнему вылезал. */
.data-source-card .detail-stat strong {
  display: block;
  line-height: 1.25;
  max-height: 2.5em; /* 2 строки × 1.25 */
  overflow: hidden !important;
  white-space: normal;
  overflow-wrap: anywhere;
  min-width: 0;
}
/* Место под две строки, чтобы соседние поля не прыгали, когда у одного
   источника имя длинное, а у другого короткое. */
.data-source-card .detail-stat { min-width: 0; }

.idesk-card { min-height: 128px; }
/* THE NAME WAS BEING CLIPPED BY ITS OWN NEATNESS — owner-flagged 2026-08-26:
   "текста и слова иногда сокрашенные не очень". A two-line clamp keeps every
   card the same height, which is right, but at this column width the state chip
   takes enough of the row that "Google Analytics 4" came out as "Google
   Analyti…" and "Публикации и аналитика соцсетей" as "Публикации и аналитик…".
   A connector truncated to a fragment of its own product name is not tidy, it
   is unreadable.

   Two changes, both about giving the name room rather than removing the floor:
   the head is allowed to WRAP, so on a narrow card the chip drops to its own
   line instead of squeezing the name into a third of the width; and the clamp
   goes to three lines, which fits every name in the roster. The min-height
   stays, so a short name still reserves the same space and rows still end
   level. */
.idesk-card-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 6px 10px; flex-wrap: wrap;
}
.idesk-name { font-size: 14.5px; letter-spacing: -0.005em; }
.idesk-card-head .idesk-name,
.idesk-card-head .idesk-name-open {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3;
  overflow: hidden;
  min-height: 2.5em; line-height: 1.25;
  /* The name may take the whole row when it needs it; the chip wraps under. */
  flex: 1 1 11ch;
}
/* The provenance line sits on the floor of the card, not right under whatever
   happens to be above it — so every card in a row ends on the same line. */
.idesk-card > .idesk-meta:last-child,
.idesk-card > small:last-child { margin-top: auto; }
.idesk-state {
  flex: 0 0 auto; padding: 3px 9px; border-radius: 999px;
  border: 1px solid var(--pk-line-2); background: rgba(148, 178, 255, 0.05);
  color: var(--pk-dim); font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap;
}
.idesk-state-live {
  border-color: rgba(74, 222, 128, 0.34); background: rgba(74, 222, 128, 0.11);
  color: var(--pk-green);
}
/* Unavailable is OUR read failing, not the connector failing, so it is grey
   rather than red. A red chip here would report an outage the client cannot
   act on and does not have. */
.idesk-state-unavailable { color: var(--pk-faint); }
/* ПЯТЬ ЧЕСТНЫХ ЗНАЧКОВ (26.09.2026): значок — одно слово из пяти, а точные
   слова карточки («Ключ проверен — пока не используется», «Входит в тариф»)
   — этой строкой во всю ширину шапки, прямо под именем и значком. */
.idesk-card-head .idesk-exact-words {
  flex: 1 0 100%;
  font-size: 12px; line-height: 1.35; color: var(--pk-dim);
  white-space: normal; overflow-wrap: anywhere;
}
.idesk-state.is-checking { letter-spacing: 0; }

.idesk-plan {
  align-self: flex-start; padding: 2px 8px; border-radius: 999px;
  background: rgba(240, 180, 41, 0.13); border: 1px solid rgba(240, 180, 41, 0.3);
  color: var(--pk-amber); font-size: 10.5px; font-weight: 600;
}
/* ОПИСАНИЕ — РОВНО ЧЕТЫРЕ СТРОКИ НА ПОЛКЕ (20 сентября 2026).
   Правило от 25 августа гласило «ничего не обрезаем, ряд растёт вместе с
   карточкой». На девяти карточках это и правда работало. На шестидесяти
   девяти — нет: у TikTok Ads (MCP) описание в четыре раза длиннее соседнего,
   и ряд разъезжался так, что владелец прислал скриншот со словом «наехали».
   Полный текст никуда не делся: карточка открывается по названию, и там он
   целиком. Подрезана ТОЛЬКО витрина. */
.idesk-gives {
  margin: 0; color: var(--pk-text); font-size: 12.5px; line-height: 1.6;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4;
  overflow: hidden;
}
/* Внутри самой карточки (не на полке) текст показывается целиком — иначе
   «Подробнее» не давало бы ничего нового. */
.idesk-single .idesk-gives, .idesk-card-open .idesk-gives {
  display: block; -webkit-line-clamp: none; overflow: visible;
}
.idesk-since {
  margin: 0; color: var(--pk-dim); font-size: 12px; font-variant-numeric: tabular-nums;
}
.idesk-needs { margin: 0; color: var(--pk-muted); font-size: 12px; line-height: 1.6; }
.idesk-needs-label { color: var(--pk-dim); }
/* One webhook per channel. Amber because it IS something to weigh before
   pressing the button — unlike everything else on the card. */
.idesk-takeover {
  margin: 0; padding: 8px 10px; border-radius: 10px;
  background: rgba(240, 180, 41, 0.07); border: 1px solid rgba(240, 180, 41, 0.2);
  color: var(--pk-amber); font-size: 11.5px; line-height: 1.55;
}

/* One click, and what it actually means. Blue rather than amber: unlike the
   takeover warning above it, this is reassurance — the client is about to be
   sent to the provider's own sign-in and will not be typing a key here. */
.idesk-oneclick {
  margin: 0; padding: 8px 10px; border-radius: 10px;
  background: var(--pk-blue-soft, rgba(47, 107, 255, 0.08));
  border: 1px solid var(--pk-blue-line);
  color: var(--pk-text); font-size: 11.5px; line-height: 1.55;
}

.idesk-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: auto; padding-top: 4px; }
.idesk-btn {
  padding: 8px 14px; border-radius: 999px;
  font: inherit; font-size: 12.5px; cursor: pointer;
}
.idesk-btn-primary { border: 1px solid var(--pk-blue-line); background: var(--pk-blue); color: var(--rp-on-accent); }
.idesk-btn-ghost { border: 1px solid var(--pk-line-2); background: none; color: var(--pk-muted); }
.idesk-btn[disabled] { opacity: 0.55; cursor: default; }

.idesk-form {
  display: flex; flex-direction: column; gap: 10px;
  margin-top: 4px; padding: 13px; border-radius: 12px;
  border: 1px solid var(--pk-line-2); background: light-dark(rgba(15, 32, 74, 0.05), rgba(11, 15, 22, 0.55));
}
.idesk-field { display: flex; flex-direction: column; gap: 5px; }
.idesk-field-label {
  display: flex; align-items: center; gap: 6px;
  color: var(--pk-muted); font-size: 11.5px;
}
/* SPECIFICITY, NOT HOPE. A bare `.ck-input { height: 56px }` (0,1,0) lost to
   `.workspace textarea` (0,1,1) on a previous pass and the field silently kept
   a height it was never given. Two classes deep, so this one wins where it is
   actually mounted. */
.idesk-form .idesk-input {
  height: 40px; padding: 0 12px; border-radius: 10px;
  border: 1px solid var(--pk-line-2); background: var(--pk-bg);
  color: var(--pk-text); font: inherit; font-size: 13px;
}
.idesk-form .idesk-input:focus { outline: none; border-color: var(--pk-blue-line); }
.idesk-form-note { margin: 0; color: var(--pk-dim); font-size: 11.5px; line-height: 1.55; }
.idesk-snippet {
  margin: 0; padding: 11px; border-radius: 10px; overflow-x: auto;
  background: var(--pk-bg); border: 1px solid var(--pk-line);
  color: var(--pk-muted); font-size: 11.5px; line-height: 1.6; white-space: pre;
}
.idesk-msg { margin: 0; font-size: 12px; line-height: 1.55; }
.idesk-msg-ok { color: var(--pk-green); }
.idesk-msg-bad { color: var(--pk-high); }

/* The fold. A shelf of twelve must not bury the one card on it that works —
   and the control that unfolds it has to be found in the first place. A dashed
   grey pill on a grey page was reported unreadable (2026-08-25): same weight as
   disabled text, on a screen where "disabled" is a real, frequent state. Filled
   instead, in the section's own accent — --pk-accent-soft/-line/-ink are already
   scoped green for data-section="integrations" (see the .app-shell[data-section]
   block above), so this reuses the page's own highlighted-pill treatment
   (.pk-opt.is-on, .lw-panel-show.is-on) rather than inventing a new colour. */
.idesk-more { margin-top: 12px; }
.idesk-more > summary {
  display: inline-block; padding: 6px 13px; border-radius: 999px;
  border: 1px solid var(--pk-accent-line, var(--pk-blue-line));
  background: var(--pk-accent-soft, var(--pk-blue-soft));
  color: var(--pk-accent-ink, var(--pk-text));
  font-size: 12px; font-weight: 600; cursor: pointer; list-style: none;
}
.idesk-more > summary::-webkit-details-marker { display: none; }
.idesk-more > summary:hover { border-color: var(--pk-accent, var(--pk-blue)); }
.idesk-cards-quiet { margin-top: 12px; }
/* Secondary, not lesser: the same card, quieter, because it carries the same
   information with a slower next step. */
.idesk-cards-quiet .idesk-card { padding: 13px 14px; background: transparent; }
.idesk-cards-quiet .idesk-name { font-size: 13.5px; }

@media (max-width: 720px) {
  .idesk-cards { grid-template-columns: 1fr; }
}

/* ---------------------------------------------------------------------------
   DESK DENSITY — the owner's note: "квадраты очень большие".

   He was right, and the cause was the column floor rather than the padding.
   minmax(300px, 1fr) means a 1440 viewport fits four columns and then stretches
   each to ~330px, so thirty-one cards became a field of large tiles and the
   shelf stopped reading as a list of choices. Dropping the floor to 244px fits
   five and lets the grid pack instead of stretch; the card keeps its structure
   and loses only the air it was never using.
--------------------------------------------------------------------------- */
/* В кабинете это правило перебивало ширину колонки сверху: 244 px давали на
   ноутбуке ЧЕТЫРЕ колонки по 285 px, и владелец прислал скриншот со словом
   «наехали». 320 px дают три колонки на той же ширине — карточка перестаёт
   мельчить, ряд остаётся ровным (описание подрезано до четырёх строк выше). */
.workspace .idesk-cards {
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.workspace .idesk-card { gap: 6px; padding: 12px 13px 11px; border-radius: 11px; }
.workspace .idesk-name { font-size: 13.5px; }
.workspace .idesk-gives { font-size: 12px; line-height: 1.5; }
.workspace .idesk-state { padding: 2px 7px; font-size: 9.5px; }
.workspace .idesk-shelf { margin-bottom: 22px; }
.workspace .idesk-cards-quiet .idesk-card { padding: 10px 12px; }

/* ---------------------------------------------------------------------------
   CONFIGURATION REGISTRY — /admin/config

   A hundred and six rows have to be scannable, so the row is a three-line block
   with the name doing the work: monospace, full width, never truncated. A name
   half-shown is a name somebody will mistype into Netlify.

   Colour carries the state and never the category: green means "found just
   now", amber means "found somewhere other than its declared home", red means
   "required and absent". Category is a word, because "secret" and "config" are
   a decision about a value, not a warning about it.
--------------------------------------------------------------------------- */
.cr-page { display: flex; flex-direction: column; gap: var(--rp-4); max-width: 1180px; }
.cr-lede { margin: 0; color: var(--pk-muted); font-size: 14px; max-width: 82ch; line-height: 1.6; }
.cr-note { color: var(--pk-muted); font-size: 14px; padding: var(--pk-pad) 0; }
.cr-note-bad { color: var(--pk-high); }
.cr-contract {
  margin: 0; padding: 12px 14px;
  border: 1px solid var(--pk-line); border-radius: 12px;
  background: rgba(148, 178, 255, 0.04);
  color: var(--pk-dim); font-size: 12.5px; line-height: 1.6; max-width: 82ch;
}
.cr-gap {
  margin: 0; padding: 14px 16px;
  border: 1px solid var(--pk-line); border-radius: 12px;
  color: var(--pk-dim); font-size: 12.5px; line-height: 1.6; max-width: 82ch;
}

.cr-stats { display: flex; flex-wrap: wrap; gap: 10px; }
.cr-stat {
  flex: 1 1 150px; min-width: 130px;
  border: 1px solid var(--pk-line); border-radius: 12px;
  background: var(--pk-panel); padding: 12px 14px;
  display: flex; flex-direction: column; gap: 2px;
}
.cr-stat-value { font-size: 22px; font-weight: 650; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.cr-stat-label { color: var(--pk-dim); font-size: 12px; }
.cr-stat-ok .cr-stat-value { color: var(--pk-green); }
.cr-stat-bad .cr-stat-value { color: var(--pk-high); }
.cr-stat-drift .cr-stat-value { color: var(--pk-amber); }
.cr-stat-soft .cr-stat-value { color: var(--pk-muted); }

.cr-filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.cr-chip {
  border: 1px solid var(--pk-line-2); border-radius: 999px;
  background: transparent; color: var(--pk-muted);
  padding: 5px 12px; font-size: 12.5px; cursor: pointer;
}
.cr-chip:hover { border-color: var(--pk-line); color: var(--pk-text); }
.cr-chip.is-active { border-color: var(--pk-accent, var(--pk-line)); color: var(--pk-text); background: rgba(148, 178, 255, 0.09); }
.cr-search {
  flex: 1 1 200px; min-width: 160px; max-width: 320px;
  border: 1px solid var(--pk-line-2); border-radius: 999px;
  background: transparent; color: var(--pk-text);
  padding: 5px 14px; font-size: 12.5px;
}

.cr-rows { display: flex; flex-direction: column; }
.cr-row {
  padding-block: 12px 12px; padding-inline: 14px 0;
  border-top: 1px solid var(--pk-line);
  border-inline-start: 3px solid transparent;
  /* The name is the widest thing on the row and must never be clipped: a
     truncated variable name is a mistyped variable name later. */
  min-width: 0;
}
.cr-rows > .cr-row:first-child { border-top: 0; }
.cr-row-ok { border-inline-start-color: var(--pk-green); }
.cr-row-bad { border-inline-start-color: var(--pk-high); }
.cr-row-drift { border-inline-start-color: var(--pk-amber); }
.cr-row-soft { border-inline-start-color: var(--pk-line-2); }
.cr-row-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cr-name {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px; color: var(--pk-text); word-break: break-all;
}
.cr-kind {
  border: 1px solid var(--pk-line-2); border-radius: 999px;
  padding: 1px 8px; font-size: 10.5px; letter-spacing: 0.02em;
  color: var(--pk-dim); white-space: nowrap;
}
.cr-kind-secret { color: var(--pk-high); }
.cr-kind-gate { color: var(--pk-amber); }
.cr-row-meta { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 4px; font-size: 12.5px; color: var(--pk-muted); }
.cr-row-bad .cr-state { color: var(--pk-high); }
.cr-row-drift .cr-state { color: var(--pk-amber); }
.cr-readers {
  margin: 4px 0 0; color: var(--pk-dim); font-size: 11.5px; line-height: 1.5;
  /* Eleven file names is a long line and a useful one; it wraps rather than
     scrolling sideways, because the count in front of it is the headline. */
  word-break: break-word;
}

.cr-orphans {
  border: 1px solid var(--pk-line); border-radius: 14px;
  background: var(--pk-panel); padding: 18px 20px;
}
.cr-orphans h3 { margin: 0 0 6px; font-size: 16px; font-weight: 600; }
.cr-orphan-list { margin: 10px 0 0; padding-inline-start: 18px; display: flex; flex-direction: column; gap: 4px; }
.cr-orphan-list code { font-size: 12.5px; color: var(--pk-muted); }

/* ═══ THE ROOM THE SCREEN WAS ALREADY GIVEN ══════════════════════════════════
   Two complaints from the owner, both photographed at 1536 CSS px (a 1920
   monitor at 125% Windows scale), both the same shape: a surface using a strip
   of the width it has, and scrolling inside a box instead of down the page.

   This block is LAST in the last stylesheet on purpose. Every selector below
   competes with rules in redesign.css, cabinet-system.css and earlier in this
   file, and the specificity arithmetic between them has been guessed wrong here
   before. Source order settles it without anyone having to count.
   ══════════════════════════════════════════════════════════════════════════ */

/* --- 1 - the lead cabinet fills the window --------------------------------
   Measured before: .lw-page ran 158 -> 802 in an 864px viewport and stopped
   62px short of the bottom, because .rp-footer (44px + 18px margin) is a flex
   child of the same column. On a screen that is pinned to the window and never
   scrolls, a footer is 62px of the fold spent on chrome nobody can scroll to
   anyway. It stays on every other route. */
.workspace:has(.lw-page) > .rp-footer { display: none; }

/* --- 2 - WITHDRAWN: a lead with no dialogue keeps the same card ----------
   This block gave the no-dialogue lead a full-width surface whose sections
   flowed into `repeat(auto-fit, minmax(300px, 1fr))` - three columns across
   ~1200px at 1536. It answered a real complaint (a 360px card beside 838px of
   empty dark) with the wrong half of the fix: it widened the CARD instead of
   asking what belongs at that width.

   The owner settled it on 2026-08-16 by pointing at our OWN two-column layout -
   the one a lead WITH a conversation already renders - and saying "вот так
   можешь сжать везде в карточках, вот норм". Measured off his screenshot at
   1913px: card ~530px, conversation the rest. docs/LEAD_CARD_TARGET_KOMMO.md.

   The branch renders `has-card` now, so this block selects nothing. Deleted
   rather than left dead: `.lw-solo` appears in no markup, and a rule set for a
   class nothing emits is a trap for whoever greps next.

   ONE FACT FROM IT IS KEPT, because it is about the markup and not about that
   layout: CSS multi-column must never be used on this card. `.lw-phone-menu` is
   position:absolute inside a position:relative row, and an abspos descendant of
   a multi-column container resolves against the column SET rather than the
   fragment it appears in - probed at 1536 the same box came back 613px wide
   across the middle of the card instead of 218px inside its own column. A grid
   track is a real containing block; a column fragment is not. */

/* --- 3 - and where there IS a conversation, the panel is not a sliver ------
   The pack's 360px was set against a three-column page. With no drawer open
   there is room to spare from 1440 up, and 360 beside 838 reads as the same
   narrow strip. The centre still keeps minmax(0,1fr): it never yields below
   what the layout contract promises it. */
@media (min-width: 1440px) {
  .lw-page.has-card:not(.has-drawer) { grid-template-columns: 420px minmax(0, 1fr); }
}

/* --- 4 - the CRM list fits the width it has -------------------------------
   Measured before, at 1536: the table was 1577px wide inside a 1176px box, so
   401px of it lived behind a horizontal scrollbar - and because the box was
   scrolled right, the leading column was cut off on its left edge ("rofesor",
   "is Yakovenko", a header reading "TAKT"). The cause is `table-layout: auto`
   plus `white-space: nowrap` on every cell: one long company name took 339px
   and the table simply grew. Nothing truncated.

   Fixed layout with declared widths inverts that: the columns are sized from
   the room available and the content ellipsises inside them. A name that does
   not fit is shortened, which is readable; a table that does not fit is
   scrolled, which is not.

   Counted from the END with :nth-last-child, because the leading checkbox
   column only exists for a role that may write, and counting from the front
   would shift every width by one column for a viewer. */
/* 126px OF THE CRM FOLD WAS BEING SPENT ON A PADDING THE ROUTE HAD ALREADY
   DECLINED. `.page-stack.crm-page` asks for `padding: 0 0 6px` and says why in
   its own comment — the board is supposed to fill the fold. It never got it:
   `main.workspace > .page-stack` (0,2,1) carries `padding-bottom: 132px` and
   outranks `.page-stack.crm-page` (0,2,0), so the CRM column has been 132px
   short of its own contract. Measured at 1536: `.pk-page` 512px instead of 638,
   which is four rows of the list and a whole card of the board. Restoring the
   route's own number, at a weight that actually wins. */
main.workspace > .page-stack.crm-page { padding-bottom: 6px; }
/* «Операции» рисуются секцией прямо в main.workspace, без .page-stack, — и не
   прокручивались вовсе (владелец, 19.09 утром: «страница не двигается»). Та же
   роль прокрутки, что у .page-stack. */
main.workspace > .page.ops-page { flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden; }

.crm-listv .crm-list { table-layout: fixed; width: 100%; }
.crm-listv .crm-list td { overflow: hidden; text-overflow: ellipsis; }
/* A VALUE MAY BE SHORTENED; A COLUMN NAME MAY NOT.
   The cells above ellipsise, which is fine — a name you can half-read tells you
   which row to open. A heading cannot: «ОТВЕТСТВ…» over «СЛЕД. З…» is a table
   nobody can read the shape of, and the Russian labels are the long ones
   («Ответственный» needs 91px at 10.5px uppercase and gets 67 at 1280). So the
   head wraps instead. `height` on a th is a minimum, so the row is 30px when
   one line is enough and grows only where it is not — measured at 1280 with the
   Russian set: 49px, nothing clipped, against 12 truncated headings before. */
.crm-listv .crm-list th {
  white-space: normal;
  line-height: 1.15;
  padding-top: 5px;
  padding-bottom: 5px;
  overflow: hidden;
}
/* AND THE HEADING ROW WAS NEVER 36px, WHATEVER IT SAID.
   A sortable heading is a <button>, and this codebase carries a bare
   `button { min-height: 40px }` that outranks the `height` on the cell around
   it. Measured at 1536: the head row was 51px — a 40px button plus padding —
   for one line of 10.5px caption. Not a wrapping cost and not new; it has been
   eating half a row of the list all along. Released here, the head is 30px and
   the same table shows seventeen deals instead of sixteen. */
.crm-listv .crm-list th > button {
  min-height: 0;
  height: auto;
  padding: 0;
  /* The heading text lives in the BUTTON, and the button was `nowrap` with
     `overflow: hidden` and no ellipsis — so «Ответственный» rendered as 92px of
     text inside a 47px box, cut mid-word with nothing to say it had been. The
     th around it measured clean the whole time, which is why this needed a
     probe of the button's own client rects to find. It wraps with the cell now,
     and `height: auto` above lets the row grow the one line it needs. */
  display: block;
  width: 100%;
  text-align: start;
  white-space: normal;
  line-height: 1.15;
  /* Some of these are one long word — «ОТВЕТСТВЕННЫЙ» is 92px of caption in a
     67px column at 1280 — and a word that cannot wrap is a word that gets cut.
     Breaking it across two lines shows the whole label; truncating it shows
     part of one. Verified at 1280 and 1536 with the Russian set. */
  overflow-wrap: anywhere;
}
.crm-listv .crm-list .c-pick { width: 34px; }
.crm-listv .crm-list th:nth-last-child(12), .crm-listv .crm-list td:nth-last-child(12) { width: 13%; }   /* deal      */
.crm-listv .crm-list th:nth-last-child(11), .crm-listv .crm-list td:nth-last-child(11) { width: 12%; }   /* contact   */
.crm-listv .crm-list th:nth-last-child(10), .crm-listv .crm-list td:nth-last-child(10) { width: 11%; }   /* phone     */
.crm-listv .crm-list th:nth-last-child(9),  .crm-listv .crm-list td:nth-last-child(9)  { width: 9%; }   /* company   */
.crm-listv .crm-list th:nth-last-child(8),  .crm-listv .crm-list td:nth-last-child(8)  { width: 9%; }  /* stage     */
.crm-listv .crm-list th:nth-last-child(7),  .crm-listv .crm-list td:nth-last-child(7)  { width: 8%; }  /* owner     */
.crm-listv .crm-list th:nth-last-child(6),  .crm-listv .crm-list td:nth-last-child(6)  { width: 6.5%; }  /* priority  */
.crm-listv .crm-list th:nth-last-child(5),  .crm-listv .crm-list td:nth-last-child(5)  { width: 6.5%; }    /* source    */
.crm-listv .crm-list th:nth-last-child(4),  .crm-listv .crm-list td:nth-last-child(4)  { width: 8%; }    /* value     */
.crm-listv .crm-list th:nth-last-child(3),  .crm-listv .crm-list td:nth-last-child(3)  { width: 6.5%; }  /* activity  */
.crm-listv .crm-list th:nth-last-child(2),  .crm-listv .crm-list td:nth-last-child(2)  { width: 5%; }    /* next task */
.crm-listv .crm-list th:nth-last-child(1),  .crm-listv .crm-list td:nth-last-child(1)  { width: 5.5%; }    /* created   */
/* Both of these were absolute caps written for the auto layout - 210px and
   130px inside columns that are now 160px and 108px. A cap wider than its own
   column is a cap that never fires. */
.crm-listv .crm-list .c-title > span, .crm-listv .crm-list .c-title > a { max-width: 100%; }
.crm-listv .crm-list .crm-list-stage { max-width: 100%; }

/* A data table, not a card list: 34px of row for 12px of text is eleven pixels
   of air per deal, and a salesperson scanning for a name reads rows. */
.crm-listv .crm-list td { height: 28px; }
.crm-listv .crm-list th { height: 30px; }

/* THE AMBER STRIP WAS NOT FLOATING - THE TABLE WAS OVERFLOWING UNDER IT.
   `.crm-ext-strip` is static, in the flow, and always has been. What put it
   over the rows: `.crm-listv > .crm-list-wrap` carried `max-height: 546px`, a
   number chosen against the board's height rather than against the room the
   fold actually has. Measured at 1536: `.pk-page` was 512px tall and
   `.crm-listv` inside it was 604 - 154px past its own parent, with
   `overflow: visible` - so the rows ran down THROUGH the strip, and the strip,
   being later in the document, painted its own background over them.

   The panel is a flex column that fills its cell instead. The table takes what
   is left after the bulk bar and the foot, so it can never exceed the box that
   contains it, and the strip lands under the panel where it was always written
   to be. `min-height: 0` here is deliberate and safe: it is on the SCROLLER,
   which is the one place the automatic minimum has to be cancelled for
   `overflow: auto` to mean anything at all. */
.crm-listv {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
.crm-listv > .crm-list-wrap {
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
  overflow-y: auto;
  /* The whole point of the widths above: nothing left to scroll sideways. */
  overflow-x: hidden;
}

/* ═══ ONE SCROLLBAR, AND IT IS THE PAGE'S ═══════════════════════════════════
   The owner's words, over a screenshot of his own board at 1536:
   «можно сделать пилплайн и карточку клиента вот так аккуратно… без вот этих
   рельсов чтобы туда сюда рельсы эти гонять, один вот обший есть справа вниз
   вверх». One rail, on the right, up and down. Nothing else.

   Measured on the live board at 1536x730 before this block — twelve stages,
   fifty-six deals:

     vertical scrollers   9  — the page (586/510) and EIGHT `.pk-col-body`,
                               each clipped to 268px: 336, 340, 666, 822, 829,
                               988, 1452 and 3343px of cards inside 268.
     horizontal scrollers 1  — `.pk-board`, 3750 inside 1206.
     columns fully visible 3, with 282px of the fourth showing at the frame
                               edge — a stage header cut mid-word, which reads
                               as breakage rather than as "scroll for more".

   A column with TWO cards still grew a rail, because the cap was never about
   the cards: `.page-stack.crm-page` has a definite height, `.pk-page` was
   `height: 100%` of it, and every column inherited the fold as a ceiling. The
   cards were incidental.

   THIS BLOCK INVERTS THE CONTRACT WRITTEN ABOVE at "THE PIPELINE FILLS THE FOLD
   AND SCROLLS NOWHERE". That rule was not wrong when it was written — it is the
   Trello model, and it keeps both rails pinned to the fold. It is simply not
   what was asked for. Read the two together: the older comment explains why the
   board used to cap itself, this one why it no longer does. Reverting is one
   deletion, which is the point of keeping it in a single block at the end.

   The cost is stated plainly because it is real: the board's horizontal rail
   now sits at the bottom of the board rather than at the bottom of the fold,
   so with a tall stage on screen it is a page-scroll away. Shift+wheel over the
   strip still works from anywhere, the toolbar is pinned (below), and each
   lateral step lands on a column edge (scroll-snap). If that trade turns out
   wrong in use, the honest fix is a pair of steppers in the pinned toolbar —
   not a second vertical rail.
   ═══════════════════════════════════════════════════════════════════════════ */

/* --- 6 - the width the route was already inside the frame for -------------
   Measured at 1536: `.rp-topbar` paints 244 -> 1524; the board ran 276 -> 1482.
   Thirty-two pixels of inset on the left, forty-two on the right, of a column
   that had already run out of room — «экран общий узкий», and it was the app's
   own padding saying so.

   THIS USED TO BE SCOPED TO `:has(> .page-stack.crm-page)` ONLY — the CRM
   route and nothing else, with the lead workspace's `.lw-page` carrying an
   identical override of its own a little further down this file (§ near
   .lw-page). 2026-08-21: the owner circled the same complaint on every OTHER
   route — Dialogues, Voice, Overview, Agents, Media Factory, Marketing,
   Integrations, Accounting, Settings — which means these two were never the
   exception, they were the answer everyone else was waiting for. `.workspace`
   is 24/12 unconditionally now (styles.css), and `.rp-topbar`'s own margin is
   0 unconditionally too (redesign.css) — both per-route overrides that used
   to carry these exact numbers are gone with them, and this comment stays
   only to explain why a plain reader will not find them here any more.

   Worth 64px on a 1536 frame, and those 64px were the difference between
   three columns and four on the CRM board specifically: 4x296 + 3x18 = 1238
   finally fit where 1206 could not. That reasoning is unchanged; only its
   scope widened to the whole product. */

/* --- 7 - the page grows; nothing inside it does ---------------------------
   `height: 100%` is what handed the fold down as a ceiling. `height: auto`
   with `min-height: 100%` keeps the promise that mattered — a short board
   still fills the screen instead of floating in the top third — and drops the
   one that did not.

   Scoped by :has() to the two CRM views rather than to `.pk-page` at large,
   because `.pk-page` is also the drawer's grid and the drawer is still a
   full-height column of it. */
.pk-page:has(.pk-board),
.pk-page:has(.crm-listv) { height: auto; min-height: 100%; }
.pk-page:has(.pk-board) > .pk-centre,
.pk-page:has(.crm-listv) > .pk-centre { height: auto; min-height: 0; }

/* A toolbar that scrolls away on a 2700px board is a search box you have to go
   back for. It is sticky against the PAGE scroller, not against the board:
   `.pk-centre` and `.pk-page` are both `overflow: visible`, so the nearest
   scrollport is `main.workspace > .page-stack`. 42px is 38 of control (was 44,
   shrunk 2026-08-21) plus the 2+2 of padding added here, and the list's table
   head sticks directly under it — one number, declared once. */
:root { --pk-bar-h: 42px; }
.pk-centre > .pk-bar {
  position: sticky;
  top: 0;
  z-index: 6;
  padding-block: 2px;
  background: var(--rp-bg, #0a0d14);
}

/* --- 8 - the board strip: the one place a horizontal rail is allowed ------
   `flex: 0 0 auto` and not `1 1 auto`: as the only flexible child of a column
   with a definite height, the board would still be handed the fold and nothing
   would have changed. `overflow-y` stays `hidden` rather than becoming
   `visible` — with `overflow-x: auto` beside it the computed value would be
   forced back to `auto` and a vertical rail would reappear on the strip. The
   box is exactly as tall as its content, so hidden clips nothing.

   `scroll-snap-align: start` is what fixes the LEFT edge. A column cut on its
   left is not an affordance, it is damage — his screenshot showed «т» and «з
   суммы» hanging at the frame. `proximity`, not `mandatory`: a drag across two
   stages must not be yanked back mid-gesture. */
.pk-board {
  flex: 0 0 auto;
  height: auto;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  padding-bottom: 4px;
}

/* --- 9 - a stage is a lane, not a card -----------------------------------
   The reference is plain: a 3px colour bar, the name in caps, one grey line
   reading "N deals - sum", then cards. No panel, no radius, no chrome. The
   lane keeps a barely-there tint so the drop target has a shape — the column
   is what `onDrop` is bound to, and an invisible drop target is a drag that
   fails silently — and a TRANSPARENT 1px border so `.pk-col.is-won` /
   `.is-lost` above, which set only `border-color`, still have a border to
   colour. Deleting the border outright would have deleted those two states
   without anything reporting it.

   Columns stretch to the tallest (the flex default, restored by not saying
   otherwise): a two-card stage still offers its full height to a dropped
   card. */
.pk-col {
  scroll-snap-align: start;
  border: 1px solid transparent;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.013);
  overflow: visible;
  padding-bottom: 10px;
}
.pk-col-rule { height: 3px; border-radius: 2px; }
.pk-col-head {
  padding: 10px 10px 8px;
  background: none;
  border-bottom: 1px solid var(--pk-line);
}
/* Caps at 12.5px is the reference's heading treatment, and it survives the
   `@media (max-width: 1500px) { .pk-col-name { font-size: 16px } }` above by
   source order alone — same specificity, later rule, no counting required. */
.pk-col-name {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.2;
}
.pk-col-meta { margin-top: 4px; font-size: 12px; gap: 8px; line-height: 1.2; }
.pk-col-fold { width: 21px; height: 21px; }
/* THE COLUMN NO LONGER SCROLLS. `flex: 0 0 auto` matters as much as the
   overflow: with `1 1 auto` the body would still be asked to absorb whatever
   height the lane was given. */
.pk-col-body {
  flex: 0 0 auto;
  overflow: visible;
  padding: 10px 8px 0;
  gap: 8px;
}
.pk-col-add { margin: 8px 8px 0; height: 32px; font-size: 12.5px; }
.pk-col-empty { margin: 0 8px; padding: 12px 13px; }

/* --- 10 - the card, at the reference's density ---------------------------
   151px per deal for four short facts. Measured after: 112px, and the same
   four facts — the air came out of the padding and the leading, not out of
   the content. Nothing is hidden and nothing is truncated that was not
   truncated before.
   2026-08-21: shrunk again — «карточки по верхним двум блокам… сократить» —
   the same pass that tightened the toolbar above the board, applied to the
   cards inside it. Text sizes untouched; only the air between facts moved. */
/* «в карточке… чуть ещё уже» — 2026-08-21: left/right nudged from 10 to 8.
   The column width itself (--pk-col) stays put — that one is a documented
   floor other rules already depend on — this only tightens the card's own
   inset a touch further. */
.pk-lead { padding: 8px 8px 7px; border-radius: 8px; }
.pk-lead-name { font-size: 13px; line-height: 1.2; }
.pk-lead-person { margin-top: 2px; font-size: 12px; line-height: 1.2; }
.pk-lead-when { margin-top: 4px; font-size: 11.5px; line-height: 1.15; }
.pk-lead-next { margin-top: 5px; font-size: 12px; }
.pk-lead-foot { margin-top: 6px; padding-top: 6px; gap: 7px; }
.pk-lead-ava { width: 20px; height: 20px; font-size: 9px; }
.pk-lead-owner { font-size: 12px; }
.pk-lead-go { width: 22px; height: 22px; }

/* --- 11 - and the same rule for the list ---------------------------------
   The list was fixed for width last commit and still carried its own vertical
   rail: measured at 1536, `.crm-list-wrap` held 2847px of rows in 388, inside
   a page that scrolled 586 in 510. Two rails on one screen is the complaint,
   whichever view is showing.

   The head is what a scrolling table cannot lose, and it had no stickiness of
   its own before because the rail it lived in was only 388px tall. Sticky on
   the `th` (not the `thead` — Chrome does not honour it on the section) at the
   toolbar's height, and `overflow: visible` on the wrap, without which the wrap
   is still a scrollport and the head sticks to a box that scrolls away with it.
   Verified: page scrolled 900px, `.pk-bar` at y=158, `thead th` at y=206. */
.crm-listv { flex: 0 0 auto; }
.crm-listv > .crm-list-wrap {
  flex: 0 0 auto;
  max-height: none;
  overflow: visible;
}
.crm-listv .crm-list thead th {
  position: sticky;
  top: var(--pk-bar-h, 48px);
  z-index: 3;
  background: var(--t68);
}

/* --- 12 - and the same rule for the LEAD CARD ----------------------------
   The third time this has been raised, and the first time it was measured on
   the state he is actually looking at. «рельса», «не как у нас… общий справа
   вниз вверх» — one rail, on the right of the frame, and nothing else.

   Measured at 1536x730, in the real shell, on three states of
   /crm/leads/:id/workspace:

     lead WITH a dialogue (`has-card`)   `aside.lw-card` — 1477px of card
        inside 564, and its rail at x=696. That is not on the right of
        anything: it is a scrollbar down the MIDDLE of the screen, drawn
        against the card's own border. This is the рельса.
     lead with no dialogue (`lw-solo`)   `.lw-page.lw-solo` — 1080 inside 572,
        rail at x=1492. One rail, but 44px in from the window edge and 13px
        off the card's border, so it still reads as the card's own.
     the board, for comparison           `.page-stack.crm-page` — 1848 inside
        510, rail at x=1524, i.e. 12px from the window edge.

   TWO CORRECTIONS TO THE BRIEF, both from the measurement. First, the board
   does NOT scroll the window: `body` and `html` are `overflow: hidden` on
   every route (`.app-shell` too), so the board's rail belongs to
   `main.workspace > .page-stack`, a box inside the frame that starts at y=158
   under the pinned topbar and header. "The page scrolls" in this shell MEANS
   that box. So the target is not a window scrollbar — it is the same box, at
   the same x, behaving the same way. Second, the complaint is mostly not about
   `lw-solo` at all; solo is one rail already. It is `has-card`, which is what
   almost every real lead renders as, and which had its rail mid-screen.

   WHAT CHANGES. Two things, both the board's rule verbatim — the page scrolls,
   the panels grow to their content:

   (a) the scrollport reaches the frame. `.workspace` still carries
       `padding-right: 44px !important` and a legacy `padding-left: 56` from
       styles.css, so the `padding: 0` in redesign.css's flex-column rule has
       never actually applied here. The CRM route already answers those two
       with the same pair of !importants (section 6 above); this is the same
       answer for the same reason, and it puts the lead workspace's rail at
       exactly the board's x. The topbar's margins are already zeroed for this
       route in redesign.css, so it moves with the column and stays aligned.

   (b) the card stops being a scrollport. `overflow: visible` + `align-self:
       start` is `.pk-col-body`'s fix applied to `.lw-card`: the panel is as
       tall as its facts, and the page absorbs the height.

   WHAT DELIBERATELY DOES NOT CHANGE: `.lw-scroll`, the transcript. A chat is
   the one place a scrollport is right — the composer belongs to the fold, and
   `.lw-thread { margin-top: auto }` is what puts the newest message on screen
   the moment the lead opens. Growing the transcript into the page would land
   an operator at the OLDEST message of a 300-turn thread with the composer
   somewhere below the fold, and there is no scroll-to-bottom anywhere in this
   page to rescue it. So the conversation column pins itself to the fold with
   `position: sticky` while the card scrolls past it. One rail on the right for
   the page, and the transcript's own, which every messenger on earth has.

   `grid-template-rows: 100%` is what makes the sticky column exact without a
   magic number: the row is the fold, so `height: 100%` on the conversation is
   the fold, and the card — `align-self: start` — is free to overflow that row
   into the page's scrollable overflow.

   The `:not(.lw-solo)` these four rules carried is gone with the class: §2
   above is withdrawn and no markup emits `lw-solo` any more, so the exception
   was selecting nothing and reading as though a second layout still existed. */
/* Was its own `padding-left: 24px !important; padding-inline-end: 12px !important;`
   override — redundant since 2026-08-21, .workspace carries the same 24/12
   unconditionally now (styles.css). Removed rather than left as a duplicate
   that would read as this route needing something the others don't. */

/* The page is the one scroller on this screen. */
.lw-page { overflow-y: auto; overflow-x: hidden; grid-template-rows: 100%; }
.lw-page > .lw-card {
  align-self: start;
  height: auto;
  overflow: visible;
}
/* The conversation and the call drawer keep the fold; the card scrolls past
   them. `top: 0` is against `.lw-page` itself, which is the scrollport. */
.lw-page > .lw-main,
.lw-page > .lw-drawer {
  position: sticky;
  top: 0;
  height: 100%;
}

/* --- 16 - the card is ~530px, everywhere, because that is what he measured -
   «вот так можешь сжать везде в карточках, вот норм». Read off his screenshot
   at 1913px: card column ~530, conversation the rest. §3 above had set 420 at
   ≥1440 against a three-column page; the reference is wider than that and the
   token behind `--pk-client-w` is 360, which is the strip the whole argument
   started over.

   480px with the call drawer open, because three columns at 1536 leave the
   conversation 1270 − 480 − 380 − 28 = 382px otherwise, and 382 is not a
   conversation — the layout contract's own rule that the sides give way before
   the centre does. The drawer already drops the card below 1600; this keeps the
   two-column case honest at every width above it. */
@media (min-width: 1440px) {
  .lw-page.has-card:not(.has-drawer) { grid-template-columns: 520px minmax(0, 1fr); }
}

/* --- «ВЕЗДЕ» HAS TO BE TRUE BELOW 1440 TOO. Owner's decision, 2026-08-17.
   His word was «везде» and the fallback made it false on any screen under
   1440: `--pk-client-w` is 360, the exact strip four rounds of argument were
   about, and a 1280 laptop got it.

   440, and the number was measured rather than picked. At 1280:

     card 360  →  conversation 638   (shipped, and the strip he objected to)
     card 440  →  conversation 558   ← this
     card 520  →  conversation 478

   520 loses the argument it was meant to win: 478 is NARROWER THAN THE CARD,
   and the whole point of the two-column shape is that the conversation is what
   deserves the width. 440 clears the 440–520 band the spec asks for, so «везде»
   becomes true, and still leaves the conversation 118px more than the card.

   Scoped below 1440 so the ≥1440 rule above is untouched — his own screen is
   1536 and must not move. */
@media (min-width: 1024px) and (max-width: 1439px) {
  .lw-page.has-card:not(.has-drawer) { grid-template-columns: 440px minmax(0, 1fr); }
}
/* 1600, NOT 1440 — CAUGHT BY MEASURING, AND IT IS THE EXACT TRAP THIS FILE'S
   HEADER WARNS ABOUT. The three-column rule first went in under the same
   `min-width: 1440px` as the two-column one. At 1536 that matched, and because
   this block is LAST it also beat `@media (max-width: 1599px)` above, which
   drops the card for the drawer. So the grid was handed three tracks while
   `.lw-card` was still `display: none`: measured `480px 384px 380px`, with the
   conversation on 384 — below the 382 my own comment had just called "not a
   conversation". Scoped to the width where the card is genuinely on screen
   beside the drawer, the two rules stop overlapping at all. */
@media (min-width: 1600px) {
  .lw-page.has-card.has-drawer { grid-template-columns: 480px minmax(0, 1fr) var(--pk-drawer-w); }
}

/* --- 13 - A LANE IS AS TALL AS ITS OWN CARDS -----------------------------
   P0, reported from production: `/crm` in «Вид: Воронка» at 1536 showing four
   tall grey rectangles — no stage names, no counts, no cards, no «+ Добавить
   лид» — over a toolbar that read «61 сделка».

   It is not a collapse. It is the opposite, and section 5 above caused it.

   Reproduced in the shell at 1536x730 with the owner's shape — twelve stages,
   sixty-one deals, thirty of them in one:

     board height          4451px
     EVERY column          4437px, whether it holds thirty cards or one
     the one-card stage    body 217px, «+ Добавить лид» ends there, and then
                           4090px OF EMPTY PAINTED LANE below it
     scrolled to the end   stage headers on screen 0, cards on screen 3,
                           lanes on screen 5

   Two rules that were each fine apart. Columns stretch to the tallest — the
   flex default, which section 9 deliberately kept so a two-card stage still
   offers its full height to a dropped card. And section 5 removed the fold cap,
   so "the tallest" stopped being 268px of body and became the whole content.
   Before, the stretch could waste at most a screen; after, one busy stage makes
   every quiet stage a four-thousand-pixel rectangle of nothing.

   And the bottom of the board is exactly where the owner has to go, because
   that is where the horizontal rail now lives — «мне чтобы передвинуть воронку
   вправо надо в самый низ идти и там дергать тянуть вправо бегунок». So the
   screenshot is the bottom of a board whose lanes ran out of cards two thousand
   pixels earlier. Nothing failed to render. Everything that was there was above
   the fold.

   A lane is now its own height. The drop target is unaffected in kind — `onDrop`
   is bound to `.pk-col`, the whole section, not to the body — and `min-height`
   keeps an empty or one-card stage a target big enough to aim at, which is the
   thing section 9 was actually protecting. 96px is one card's height plus its
   gap, so the smallest lane is never smaller than the thing being dropped on it.

   Ragged column bottoms are what a kanban that does not scroll its columns looks
   like; the alternative is the rectangle above. */
.pk-board { align-items: flex-start; }
.pk-col-body { min-height: 96px; }

/* --- 14 - and a way to move sideways without going to the bottom ----------
   The trade section 5 wrote down as its cost — "the board's horizontal rail now
   sits at the bottom of the board rather than at the bottom of the fold, so with
   a tall stage on screen it is a page-scroll away… if that trade turns out wrong
   in use, the honest fix is a pair of steppers in the pinned toolbar, not a
   second vertical rail" — turned out wrong in use, in the way it predicted. The
   steppers are in the toolbar, which is sticky, so lateral movement no longer
   depends on reaching a rail 4451px down. Shift+wheel and the column scroll-snap
   are untouched. */
/* «стрелки вперед назад я бы и везде где такие стрелки как то подсветил, типа
   Select если надо переключить, типа дропдаун или как-то по-другому понятнее
   где это надо».

   Two loose 34px boxes read as decoration next to «Воронка / Список», which is
   the row's reference for "this is something you press": a bordered TRAY with
   two seated buttons inside it. The steppers now borrow that shell.

   AND THE SHELL IS `.pk-ctl`'s, NOT `.pk-seg`'s — CAUGHT BY MEASURING, WHICH IS
   THE ONLY WAY IT COULD HAVE BEEN. The View control is
   `class="pk-ctl pk-ctl-view pk-seg"`, and `.pk-seg` in redesign.css declares a
   tray of its own: 1px #23293a, radius 10, #141926, 3px inset. None of that is
   what paints. `.pk-ctl` here is the same specificity (0,1,0) in a file that
   loads LATER, so it wins every property they share, and `.pk-ctl-view` has no
   rules anywhere. Copying the numbers out of `.pk-seg` produced a tray that
   matched the stylesheet and not the screen — border 0.10 against 0.18, radius
   10 against 11, #141926 against #121821, height 40 against 44. Measured in
   dev/crm-board-strip-harness.html, which is why the second attempt is right.

   So: 44px, radius 11, `--pk-line-2`, `--pk-panel` — `.pk-ctl`'s own four — with
   the 32px seated buttons the segmented control puts inside them. The inset is
   5px rather than 15 because 15 is a text control's side padding and there is
   no text here; the identity is carried by the other four.

   The glyph is bigger than the segmented control's text (16px against 13px)
   because a chevron at label size is a speck. */
.pk-nav {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  /* Едет вместе со всей строкой — см. --pk-row-h. */
  height: var(--pk-row-h);
  padding: 0 4px;
  flex: 0 0 auto;
  border: 1px solid var(--pk-line-2);
  border-radius: 11px;
  background: var(--pk-panel);
}
.pk-nav-btn {
  appearance: none;
  min-height: 0;
  width: 28px; height: 28px;
  display: grid; place-items: center;
  border: 0; border-radius: 7px;
  background: transparent;
  color: var(--pk-text-dim, #8a93a6);
  font: inherit; font-size: 16px; line-height: 1;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}
.pk-nav-btn:hover:not(:disabled) {
  background: var(--pk-accent-soft, #1d2942);
  color: var(--pk-text, #e6ebf5);
}
/* ЧТО ИМЕННО ДВИГАЮТ ЭТИ ДВЕ СТРЕЛКИ.
   Владелец 30 августа: «стрелочки как-то обозначить, чтобы было понятно, что
   это вправо передвигается воронка». Серая галочка в рамке неотличима от
   «назад» в браузере, а делает совсем другое.

   Три полоски между стрелками — доска в миниатюре: средняя ярче, как колонка,
   на которую сейчас смотрят. Нарисованы полосками, а не символом Юникода:
   подходящий глиф есть не в каждом шрифте, а где его нет — встаёт пустой
   прямоугольник, то есть ровно та неясность, которую убираем. */
/* 12 сентября 2026 — ЖИВАЯ КАРТА вместо трёх полосок (владелец: «эту
   маленькую чуть больше и так же крутить, как в конструкторе»). Плашка на
   этап, окно — видимая часть; нажатие и протяжка катят доску. */
.pk-nav-map {
  position: relative;
  display: inline-flex; align-items: stretch; gap: 2px;
  inline-size: 104px; block-size: 20px;
  margin: 0 3px; padding: 2px;
  border-radius: 6px;
  background: rgba(255, 255, 255, .03);
  cursor: pointer; touch-action: none; user-select: none;
}
.pk-nav-map-cell {
  display: block; flex: 1 1 0; min-inline-size: 0;
  border-radius: 2px;
  background: var(--pk-text-dim, #8a93a6);
  opacity: .28;
}
.pk-nav-map-view {
  position: absolute; inset-block: 0;
  border: 1.5px solid var(--pk-blue, #3f7dfb);
  border-radius: 5px;
  background: color-mix(in srgb, var(--pk-blue, #3f7dfb) 22%, transparent);
  pointer-events: none;
  transition: inset-inline-start 60ms linear;
}
.pk-nav:hover .pk-nav-map-cell { opacity: .42; }
/* Сами стрелки — не приглушённые. Управляющий элемент, который человек ищет
   глазами, не должен быть тише подписи рядом. */
.pk-nav-btn { color: var(--pk-text, #e6ebf5); font-weight: 700; }
.pk-nav-btn:focus-visible {
  outline: 2px solid var(--pk-accent, #3f7dfb);
  outline-offset: -2px;
}
/* DEAD AT THE END, AND VISIBLY SO. syncBoardNav() in CrmPipelinePage.js sets
   `disabled` straight on the element when there is nothing further that way.
   `cursor: default` matters as much as the opacity: a pointer cursor over a
   control that will not respond is the same false promise in miniature. */
.pk-nav-btn:disabled {
  opacity: 0.32;
  cursor: default;
  background: transparent;
  color: var(--pk-text-dim, #8a93a6);
}

/* THE OTHER BARE CHEVRON ON THIS SCREEN, brought to the same rule.
   `.pk-col-fold` is the collapse control in every stage header — a naked «⌃» on
   no surface at all, which is the same "is this even a button?" the steppers
   were. It is a disclosure rather than a switcher, so it stays quiet by default
   and takes the tray's own seated-button treatment on hover instead of a
   permanent border: twelve bordered boxes across a twelve-stage header row
   would compete with the stage names they belong to. It already carries a title
   and `aria-expanded`; what it lacked was any sign of being pressable. */
.pk-col-fold, .pk-col-unfold {
  border-radius: 7px;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease;
}
.pk-col-fold:hover, .pk-col-unfold:hover {
  background: var(--pk-accent-soft, #1d2942);
  color: var(--pk-text, #e6ebf5);
}
.pk-col-fold:focus-visible, .pk-col-unfold:focus-visible {
  outline: 2px solid var(--pk-accent, #3f7dfb);
  outline-offset: -2px;
}

/* --- 15 - and the funnel's name stops being wedged into the corner --------
   «ВОРОНКА / Продажи» measured 79x44 starting at x=244 — the frame's own left
   edge, zero padding on that side, 15px on the other, and the segmented View
   control 12px away with nothing between them. Two stacked lines of type jammed
   against a wall and then immediately against a control is the "cramped" he
   reported.

   No new element and no new width: 2px of left inset so the caps line is not
   touching the frame, the line spacing opened from 1px to 3px, and a hairline
   rule taking over the job the bare 12px gap was doing badly — this is a label,
   the thing beside it is a control, and the divider says which is which. */
.pk-pipename {
  gap: 3px;
  padding-block: 0 0; padding-inline: 2px 16px;
  margin-inline-end: 2px;
  border-inline-end: 1px solid var(--pk-line);
}

/* --- 16 - the name is the switch (12 Sep 2026) ------------------------------
   «слово воронка убери продажи оставь … когда будет две и три воронки как
   там через дроп даун переключать». The eyebrow is gone from both shapes; with
   two or more funnels the name itself carries a caret and opens a menu of
   funnels — ours, not the OS's white <select> popup. Same heading type as the
   single-funnel name so the two shapes read as one thing, plus a hover wash so
   the one that opens reads as pressable. */
.pk-pipe { position: relative; flex: 0 0 auto; margin-inline-end: 2px; padding-inline-end: 8px; border-inline-end: 1px solid var(--pk-line); }
.pk-pipe-trigger {
  appearance: none;
  display: inline-flex; align-items: center; gap: 6px;
  height: var(--pk-row-h); min-height: 0;
  max-width: 220px;
  padding: 0 8px;
  border: 0; border-radius: 8px;
  background: transparent;
  color: var(--pk-text);
  font: inherit; cursor: pointer;
}
.pk-pipe-trigger > strong {
  font-size: 14.5px; font-weight: 600; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pk-pipe-trigger:hover, .pk-pipe-trigger.is-on { background: var(--pk-blue-soft); }
.pk-pipe-trigger:focus-visible { outline: 2px solid var(--pk-accent, #3f7dfb); outline-offset: 1px; }
.pk-pipe-menu {
  position: absolute; top: calc(100% + 8px); inset-inline-start: 0; z-index: 60;
  min-width: 240px; max-width: min(320px, calc(100vw - 32px));
  max-height: 360px; overflow-y: auto;
  padding: 6px;
  border: 1px solid var(--pk-line-2);
  border-radius: 12px;
  background: var(--t79);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
  display: grid; gap: 2px;
}
.pk-pipe-opt {
  appearance: none;
  display: flex; align-items: center; gap: 8px;
  width: 100%; height: 34px; min-height: 0;
  padding: 0 10px;
  border: 0; border-radius: 8px;
  background: none; color: var(--pk-muted);
  font: inherit; font-size: 13.5px; text-align: start;
  cursor: pointer;
}
.pk-pipe-opt:hover { background: var(--pk-blue-soft); color: var(--t349); }
.pk-pipe-opt.is-on { color: var(--pk-text); font-weight: 600; }
.pk-pipe-tick { flex: 0 0 14px; color: var(--pk-blue, #3f7dfb); font-size: 12px; text-align: center; }
.pk-pipe-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pk-pipe-build { color: var(--pk-dim); font-size: 13px; }

/* --- 17 - «Воронка / Список» and «Фильтры» one size smaller (12 Sep 2026) ---
   «Сделай канбан и список чуть меньше и фильтр тоже такой же». The row height
   stays --pk-row-h (every control in the row shares it); what shrinks is the
   type and the side padding, so both controls give their width back to the
   search. The seated buttons drop from 28px to 24px inside the same tray, which
   is what makes the toggle read smaller rather than merely narrower. */
.pk-bar .pk-ctl-view { padding: 0 3px; gap: 2px; }
.pk-bar .pk-ctl-view .pk-seg-btn { height: 24px; padding: 0 9px; font-size: 12px; border-radius: 6px; }
.pk-bar .pk-filter { padding: 0 8px; gap: 5px; font-size: 12px; }
.pk-bar .pk-filter .pk-filter-badge { min-width: 18px; height: 18px; font-size: 10.5px; }

/* --- 18 - three overlaps the owner circled on the live screen (12 Sep 2026) --

   1. Search text ran under the magnifier. `.workspace input[type="search"]`
      (0,2,1) out-ranked `.crm-search input` (0,1,1) and reset the right
      padding to 13px — measured on the preview. Room for the lens, and for
      the lens plus «×» once something is typed.
   2. «Ещё» opened IN the toolbar row: `.crm-more-menu` had only a width, so its
      four buttons stacked as separate boxes in flow and pushed the trigger up.
      It is a dropdown, drawn like the funnel menu.
   3. With «Фильтры» open the row kept its full width and «+ Новый лид» sat on
      top of the drawer's header. The row now wraps instead of overflowing
      into its neighbour; on a wide screen nothing changes. */
.workspace .pk-bar .crm-search input { padding-inline-end: 38px; }
.workspace .pk-bar .crm-search:has(.crm-search-x) input { padding-inline-end: 64px; }
.pk-bar .crm-search { min-width: 190px; }

.pk-bar .crm-more { position: relative; flex: 0 0 auto; }
.pk-bar .crm-more-menu {
  position: absolute; top: calc(100% + 8px); inset-inline-end: 0; z-index: 60;
  width: max-content; min-width: 240px; max-width: min(320px, calc(100vw - 32px));
  padding: 6px;
  border: 1px solid var(--pk-line-2); border-radius: 12px;
  background: var(--t79);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
  display: grid; gap: 2px;
}
.pk-bar .crm-more-menu > button {
  appearance: none; display: block; width: 100%; height: 34px; min-height: 0;
  padding: 0 10px; text-align: start;
  border: 0; border-radius: 8px; background: none; box-shadow: none;
  color: var(--pk-muted); font: inherit; font-size: 13.5px; cursor: pointer; white-space: nowrap;
}
.pk-bar .crm-more-menu > button:hover { background: var(--pk-blue-soft); color: var(--t349); }
.pk-bar .crm-more-menu .crm-more-sep { height: 1px; margin: 4px 4px; background: var(--pk-line); }

.pk-bar { flex-wrap: wrap; row-gap: 8px; }

/* ── Security and activity ──────────────────────────────────────────────────
   The client's own view of what authenticates their workspace, who changed
   what in it, and how much of the plan they have used. Same tokens as every
   other panel here; the only new idea is the state rule down the left of a row,
   which carries "this channel is separated / still shared / in a grace window"
   before a word is read. */
.ws-sec-page { display: flex; flex-direction: column; gap: var(--rp-4); max-width: 1180px; }
.ws-sec-lede { margin: 0; color: var(--pk-muted); font-size: 14px; max-width: 82ch; line-height: 1.6; }
.ws-sec-note { color: var(--pk-muted); font-size: 14px; padding: var(--pk-pad) 0; }
.ws-sec-note-bad { color: var(--pk-high); }
.ws-sec-gap {
  margin: 14px 0 0; padding: 14px 16px;
  border: 1px solid var(--pk-line); border-radius: 12px;
  background: rgba(148, 178, 255, 0.04);
  color: var(--pk-dim); font-size: 12.5px; line-height: 1.6; max-width: 82ch;
}

/* Evidence Log (/workspace/evidence-log) — the admin journal and CRM
   activity, side by side, each still tagged with its own source. */
.ws-journal-filters { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 14px 0 0; }
.ws-journal-chips { display: inline-flex; gap: 6px; }
.ws-journal-chip {
  padding: 5px 12px; border-radius: 999px; border: 1px solid var(--pk-line);
  background: transparent; color: var(--pk-muted); font-size: 12.5px; cursor: pointer;
}
.ws-journal-chip.is-on { border-color: var(--pk-accent, #4c7dff); color: var(--pk-ink, #eaf0ff); background: rgba(148, 178, 255, 0.1); }
.ws-journal-actor {
  padding: 5px 10px; border-radius: 8px; border: 1px solid var(--pk-line);
  background: var(--pk-panel); color: var(--pk-muted); font-size: 12.5px;
}
.ws-journal-list { margin-top: 14px; }
.ws-journal-row { align-items: center; }
.ws-journal-source {
  flex: 0 0 auto; font-size: 10px; text-transform: uppercase; letter-spacing: .05em;
  padding: 2px 7px; border-radius: 999px; border: 1px solid var(--pk-line);
}
.ws-journal-source-admin { color: var(--pk-muted); }
.ws-journal-source-crm { color: var(--pk-accent, #4c7dff); border-color: rgba(76, 125, 255, .4); }

.ws-sec-group {
  border: 1px solid var(--pk-line);
  border-radius: 14px;
  background: var(--pk-panel);
  padding: 18px 20px 20px;
}
.ws-sec-group-head { display: flex; align-items: center; gap: 10px; }
.ws-sec-group-head h3 { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.ws-sec-group-count {
  height: 22px; min-width: 22px; padding: 0 8px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; border: 1px solid var(--pk-line-2);
  font-size: 12px; color: var(--pk-muted);
}

.ws-sec-grace { margin-top: 14px; }
.ws-sec-grace-label { display: block; color: var(--pk-dim); font-size: 12.5px; margin-bottom: 8px; }
.ws-sec-grace-choices { display: inline-flex; flex-wrap: wrap; }
.ws-sec-grace-hint { margin: 8px 0 0; color: var(--pk-dim); font-size: 12.5px; line-height: 1.55; max-width: 78ch; }

.ws-sec-rows { display: flex; flex-direction: column; margin-top: 8px; }
.ws-sec-row {
  display: flex; align-items: center; gap: 14px;
  padding-block: 14px 14px; padding-inline: 14px 0;
  border-top: 1px solid var(--pk-line);
  border-inline-start: 3px solid transparent;
  margin-top: 14px;
}
.ws-sec-rows > .ws-sec-row:first-child { border-top: 0; margin-top: 8px; }
.ws-sec-row-live { border-inline-start-color: var(--pk-green); }
.ws-sec-row-grace { border-inline-start-color: var(--pk-amber); }
.ws-sec-row-shared { border-inline-start-color: var(--pk-amber); }
.ws-sec-row-unavailable { border-inline-start-color: var(--pk-line-2); }
.ws-sec-row-main { flex: 1 1 auto; min-width: 0; }
.ws-sec-row-title { display: block; font-size: 14.5px; font-weight: 600; color: var(--pk-text); }
.ws-sec-row-detail { margin: 4px 0 0; color: var(--pk-muted); font-size: 13px; line-height: 1.55; max-width: 72ch; }
/* The way out of a ceiling, shown from 80% — deliberately warmer than the
   detail line above it, because it is the one part of the row the client can
   act on. Amber rather than red: at 80% nothing has failed yet. */
.ws-sec-row-exit {
  margin: 6px 0 0; padding-inline-start: 10px;
  border-inline-start: 2px solid var(--pk-amber);
  color: var(--pk-text); font-size: 12.5px; line-height: 1.5; max-width: 72ch;
}
.ws-sec-row-meta {
  flex: 0 0 auto; color: var(--pk-dim); font-size: 12.5px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  white-space: nowrap; text-align: end;
}
.ws-sec-row-sub { display: block; font-family: inherit; font-size: 11.5px; opacity: 0.8; }
.ws-sec-go {
  flex: 0 0 auto; height: 34px; padding: 0 14px;
  border: 1px solid var(--pk-line-2); border-radius: 9px;
  background: var(--rp-plate); color: var(--pk-muted);
  font-size: 13px; cursor: pointer; white-space: nowrap;
}
.ws-sec-go:hover:not(:disabled) { color: var(--pk-text); border-color: var(--pk-blue-line); }
.ws-sec-go:disabled { opacity: 0.5; cursor: default; }

/* The one-time reveal. Deliberately loud: this is the only moment the value
   exists on screen, and a client who scrolls past it has to rotate again. */
.ws-sec-reveal {
  margin-top: 16px; padding: 14px 16px;
  border: 1px solid var(--pk-amber); border-radius: 12px;
  background: rgba(255, 189, 89, 0.06);
}
.ws-sec-reveal h4 { margin: 0 0 6px; font-size: 14px; font-weight: 600; color: var(--pk-text); }
.ws-sec-reveal-note { margin: 6px 0 0; color: var(--pk-dim); font-size: 12.5px; line-height: 1.55; max-width: 78ch; }
.ws-sec-reveal-row { display: flex; align-items: baseline; gap: 10px; margin-top: 10px; flex-wrap: wrap; }
.ws-sec-reveal-channel { color: var(--pk-muted); font-size: 12.5px; min-width: 96px; }
.ws-sec-reveal-key {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; color: var(--pk-text); word-break: break-all;
  background: var(--rp-plate); border: 1px solid var(--pk-line); border-radius: 8px;
  padding: 6px 10px;
}

/* The journal rows read as a log rather than as a control surface: no state
   colour down the left, because nothing here is a state — it is a record of
   something that already happened. */
.ws-sec-row-log { border-inline-start-color: var(--pk-line); }
.ws-sec-group-blurb { margin: 6px 0 0; color: var(--pk-dim); font-size: 13px; max-width: 78ch; line-height: 1.55; }
.ws-sec-gap-list { margin: 8px 0 0; padding-inline-start: 18px; display: flex; flex-direction: column; gap: 4px; }
.ws-sec-gap-covered { margin: 10px 0 0; opacity: 0.75; word-break: break-word; }

/* Consumption. `over` is the only alarming state here and it is earned: the
   allowance is genuinely used up and the next request will be refused with a
   number. `unmetered` is deliberately quiet — no ceiling is not a warning. */
.ws-sec-row-over { border-inline-start-color: var(--pk-high); }
.ws-sec-row-unmetered { border-inline-start-color: var(--pk-line-2); }

/* --- 17 - THE AMBER STRIP LIES ACROSS THE BOARD, AND THE HEIGHT CHAIN IS WHY -
   P0 from production: «Нужна настройка · 315 сделок в подключённой CRM» painted
   over the card bodies of the third and fourth columns, «Импортировать сделки»
   and «Подключения» floating on top of lead cards.

   Nothing is positioned and nothing has a z-index. `.crm-ext-strip` is
   `position: static` and always has been — the same false lead the LIST view
   produced, and the same real cause one view over (see "THE AMBER STRIP WAS NOT
   FLOATING — THE TABLE WAS OVERFLOWING UNDER IT" above).

   Measured in dev/crm-board-strip-harness.html at 1536x830, the owner's shape —
   twelve stages, sixty-one deals, thirty in one, silence panel showing:

     .page-stack.crm-page   736 tall, scrollHeight 3920
     .pk-page               581 tall   (computed flex: 1 0 0, min-height 0)
     .pk-board              3781 tall, bottom at y=4014
     .crm-ext-strip         top y=762, bottom y=824

     board bottom - page bottom        3266px
     lead cards intersecting the strip 7 of 61
     elementsFromPoint under the strip pk-lead, pk-col-body, pk-col

   That last line is the evidence, not the arithmetic: real cards are painted
   under the strip's own pixels. The strip is laid out immediately after
   `.pk-page`'s 581px box, three thousand pixels above where the board actually
   ends, and being LATER in the document it paints its background over whatever
   the board left there.

   WHO SHRANK `.pk-page`. Section 7 above set `height: auto` precisely so the
   page would grow to its board — "the page grows; nothing inside it does". That
   was then overridden by `.page-stack.crm-page > .pk-page { flex: 1 0 0 }`,
   added for the filter drawer so «Применить» stopped landing 569px below the
   fold. `flex-basis: 0` is a DEFINITE main size and it beats `height: auto`
   outright, so the page went back to being exactly the fold while its content
   went on being 3781px. Both rules are right about their own case; they were
   simply never true at the same time.

   So they are separated by the case they were each written for, and neither is
   weakened. `flex: 1 0 auto` resolves its basis from `height: auto` — the
   content — so the page is as tall as its board and every sibling the route
   carries (this strip, and the admin audit stack) lands BELOW the cards where
   it was always written to be. `flex-grow: 1` still fills the fold on a clean
   day, which is what `min-height: 100%` was protecting: with a short board there
   IS free space and grow hands it over, so a two-card funnel does not float in
   the top third. No minimum height and no viewport number.

   `:not(.has-drawer)` is the whole safety of it. With the drawer OPEN the page
   keeps `flex: 1 0 0` and the 2026-08-16 fix is untouched: the drawer's chip
   list is the tallest intrinsic column on this page, and letting it drive an
   `auto` basis is exactly what pushed «Применить» off the screen. Verified in
   the harness in both states at 1280, 1536 and 1920 — with the drawer open,
   «Применить» stays in the fold and `.pk-drawer-body` keeps its own rail.

   Known and deliberate: with the drawer open the board still overflows behind
   the strip, because that state genuinely wants a fold-height page. It is a
   transient, deliberate state entered by pressing Фильтры, and it is a strictly
   smaller problem than the default screen every client opens. Stated here rather
   than left to be rediscovered.

   THE LIST VIEW HAS THE IDENTICAL DEPENDENCY AND WAS LEFT OUT. Reported live
   again 2026-08-23 on «Список», same shape: the strip's text and buttons
   painted over «Alesea»/«Ulia»'s rows. Section 11 above gives `.crm-listv`
   the same contract the board has — `flex: 0 0 auto`, its wrap `overflow:
   visible; max-height: none` — because this page was built to be ONE rail,
   the page's own, not a second scrollport inside it (the owner's own words,
   quoted at section 11). That contract needs exactly the same `.pk-page`
   height this rule restores for the board; only the selector never named
   `.crm-listv`, so `.page-stack.crm-page > .pk-page { flex: 1 0 0 }` kept
   capping the list's page to the fold while its table went on being however
   tall 48+ rows actually are — the same overflow-under-a-later-sibling
   mechanics as above, one view over. */
.page-stack.crm-page > .pk-page:has(.pk-board):not(.has-drawer),
.page-stack.crm-page > .pk-page:has(.crm-listv):not(.has-drawer) { flex: 1 0 auto; }

/* ФИЛЬТРЫ ОТКРЫТЫ — ДОСКА ПРОКРУЧИВАЕТСЯ САМА, А НЕ ПОД ПОЛОСОЙ (11 Sep 2026).
   «Known and deliberate» выше перестало быть приемлемым: владелец, живьём —
   «артефакты появляются, когда выбираешь фильтры… глючит, даже не могу выйти
   со страницы, нажать что-то». Два механизма, оба измерены на превью:
     1. с открытыми фильтрами страница — высотой в экран, а доска — 2112px;
        карточки рисовались ПОД полупрозрачной «Сверкой источника CRM» и
        полосой внешней CRM (их текст просвечивал сквозь карточки и наоборот);
     2. колесо, докрутив список фильтров до конца, переходило на весь экран:
        шапка наезжала на колонки, «Закрыть» уезжала вверх — выглядело как
        зависание.
   Теперь с открытыми фильтрами страница обрезает доску по своей высоте —
   карточки не рисуются под полосами (у .pk-board вертикаль остаётся hidden,
   см. test-crm-scroll-discipline: своя вертикальная прокрутка у доски вернула
   бы второй рельс), — а прокрутка списка фильтров экрану не передаётся.
   После «Применить» фильтры закрываются, и доска снова во всю высоту. */
.page-stack.crm-page > .pk-page.has-drawer { overflow: hidden; }
.pk-drawer-body { overscroll-behavior: contain; }

/* ═══ THE LEAD CARD, THE SHAPE THE OWNER APPROVED — `lc-` ═══════════════════
   docs/LEAD_CARD_TARGET_KOMMO.md is the spec. This section builds the four
   pieces that spec asks for and the current card does not have:

     a stage strip that reads as changeable   .lc-stage
     tabs instead of a stacked page           .lc-tabs
     one column of label -> value rows        .lc-rows, at a 44px rhythm
     a contact block behind a rule            .lc-contact

   WHY `lc-` AND NOT `lw-`. `src/lead-workspace.css` is the card's own
   stylesheet and is being edited in another session as this lands. A second
   author adding `.lw-*` rules to a third file is how two stylesheets come to
   disagree about one control. `lc-` is a new, disjoint namespace: it collides
   with nothing today, and it can be folded into `lead-workspace.css` later by
   whoever owns that file, in one move, with nothing to untangle.

   WHY THIS FILE AND NOT A NEW ONE. A new stylesheet needs a <link> in
   index.html, which this session does not own. pack-design.css is last in the
   cascade (styles -> cabinet-system -> redesign -> composer-kit ->
   lead-workspace -> dialogue-workspace -> pack-design), so rules written here
   win without a single `!important`, and that is the whole reason the layout
   above already lives here rather than beside the markup.

   MEASURED, NOT REASONED. Every number below was read out of
   getComputedStyle/getBoundingClientRect in a real browser at 1536, 1280 and
   1920 CSS px through dev/lead-card-shape-harness.html, inside the real shell
   (.app-shell > main.workspace > .lw-page.has-card) with all seven stylesheets
   in their real order. Static reading of this repo's CSS is unreliable — see
   the counterexamples in the next comment. */

/* THE LEGACY `button` RULE IS THE ADVERSARY IN THIS SECTION, TWICE OVER.
   `styles.css:62` declares, for every bare <button> in the product:

       button { min-height: 40px; white-space: nowrap;
                overflow: hidden; text-overflow: ellipsis; }

   Both halves bite here.

   (a) `min-height: 40px` inflates anything short. A 32px tab renders at 40 and
       a 44px row rhythm becomes whatever the tallest control in it happens to
       be. Every control below therefore declares its own `min-height`, and the
       row declares its own height rather than inheriting one.

   (b) `overflow: hidden; text-overflow: ellipsis` is why «Вернуть Марию
       сейчас» renders as «Вернуть Мари…» in the ••• menu. It is NOT a width
       bug, and widening `.lw-menu` alone does not fix it —
       `lead-workspace.css`'s `.lw-menu button` never resets the three
       properties, so the label clips at whatever the flex item resolves to.
       Section 6 below is the reset, stated as a rule rather than as a wider
       box. */

.lc-card, .lc-card *, .lc-card *::before, .lc-card *::after { box-sizing: border-box; }

/* ── 1 · the title row ──────────────────────────────────────────────────────
   `‹ Lead #78860034`, and the deal's own identifier IS the title. The card is
   currently titled with the customer's opening sentence, which is why two
   different leads read as the same card. */
.lc-head { display: flex; align-items: center; gap: 8px; padding: 12px 0 6px; }
.lc-back {
  min-height: 26px; height: 26px; padding-block: 0 0; padding-inline: 2px 6px;
  border: 0; border-radius: 8px; background: none;
  color: var(--pk-muted); font: inherit; font-size: 13px; cursor: pointer;
}
.lc-back:hover { color: var(--pk-text); background: rgba(255, 255, 255, 0.05); }
.lc-title {
  min-width: 0; flex: 1;
  color: var(--pk-text); font-size: 16px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* A CONTROL, not a caption — the reference puts it immediately under the title
   and it adds a tag. Uppercase and quiet, so it does not compete with the
   identifier above it. */
.lc-tagadd {
  min-height: 24px; height: 24px; padding: 0 9px;
  border: 1px dashed var(--pk-line-2); border-radius: 999px; background: none;
  color: var(--pk-dim); font: inherit; font-size: 11px; letter-spacing: 0.06em;
  text-transform: uppercase; cursor: pointer;
}
.lc-tagadd:hover { color: var(--pk-text); border-color: var(--pk-blue-line); border-style: solid; }

/* ── 2 · the stage strip ────────────────────────────────────────────────────
   «Стадия · Связались» in a grey band is the thing the owner keeps pointing
   at: a stage you cannot change from the card. This reads as changeable — it
   is a <button>, it carries a chevron, it hovers, and the segmented bar under
   it shows where in the pipeline the deal actually is.

   The segments are `flex: 1 1 0` over a shared gap, so twelve stages and four
   stages both fill the strip exactly. No per-stage width in the markup. */
.lc-stage {
  display: block; width: 100%; text-align: start;
  min-height: 0; padding: 9px 11px; margin: 2px 0 12px;
  border: 1px solid var(--pk-line-2); border-radius: 12px;
  background: var(--pk-card); color: inherit; font: inherit; cursor: pointer;
  overflow: visible; white-space: normal;
}
.lc-stage:hover { border-color: var(--pk-blue-line); background: var(--pk-card-hi); }
.lc-stage:focus-visible { outline: 2px solid var(--pk-blue); outline-offset: 2px; }
.lc-stage-top { display: flex; align-items: baseline; gap: 8px; }
.lc-stage-name {
  min-width: 0; color: var(--pk-text); font-size: 14px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* «(8 days)» — how long it has been stuck is half the information in the
   reference, and it is the half our card never showed. */
.lc-stage-age { color: var(--pk-dim); font-size: 12px; white-space: nowrap; }
.lc-stage-chev { margin-inline-start: auto; color: var(--pk-muted); font-size: 11px; }
.lc-stage:hover .lc-stage-chev { color: var(--pk-text); }
.lc-stage-bar { display: flex; gap: 3px; margin-top: 8px; }
.lc-stage-seg {
  flex: 1 1 0; min-width: 0; height: 4px; border-radius: 2px;
  background: rgba(148, 178, 255, 0.14);
}
.lc-stage-seg.is-done { background: var(--pk-blue-line); }
.lc-stage-seg.is-now { background: var(--pk-blue); }

/* ── 3 · tabs ───────────────────────────────────────────────────────────────
   `Main · Statistics · Media · Products · Setup` in the reference. Ours stacks
   every section, which is what produces the empty half-screen below the fold
   on a lead with no data.

   The row scrolls sideways rather than wrapping: a second line of tabs inside
   a 520px column costs the card 32 more pixels on every lead, for a state that
   only occurs when somebody adds a sixth tab. `scrollbar-width: none` because
   a 6px rail under five tabs reads as a defect, and every tab stays reachable
   by keyboard regardless. */
.lc-tabs {
  display: flex; gap: 2px; margin: 0 0 10px;
  border-bottom: 1px solid var(--pk-line);
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
}
.lc-tabs::-webkit-scrollbar { display: none; }
.lc-tab {
  flex: 0 0 auto;
  min-height: 32px; height: 32px; padding: 0 10px;
  border: 0; border-bottom: 2px solid transparent; border-radius: 0;
  background: none; color: var(--pk-muted);
  font: inherit; font-size: 13px; line-height: 30px; cursor: pointer;
  /* The bare `button` rule's ellipsis is RIGHT here — a tab label that does
     not fit is a tab label that is too long — but its 40px floor is not. */
}
.lc-tab:hover { color: var(--pk-text); }
.lc-tab.is-on { color: var(--pk-text); border-bottom-color: var(--pk-blue); }
.lc-tab:focus-visible { outline: 2px solid var(--pk-blue); outline-offset: -2px; }
/* ONE SCROLL CONTAINER PER PAGE, AND THIS IS NOT IT.
   No `overflow` and no `height` on the panel. `.lw-page > .lw-card` is
   `align-self: start; height: auto; overflow: visible` (section 12 above), so
   the card grows and the PAGE absorbs it; a scrollport here would put a second
   vertical rail inside the first. `min-height: 0` is likewise deliberately
   absent — on a grid/flex item it cancels the automatic minimum size, which is
   what collapsed the CRM board to 6px once. */
.lc-tabpanel { display: block; }

/* ── 4 · the field rows ─────────────────────────────────────────────────────
   ONE column, label left, value right, ~44px rhythm, a full-bleed hairline
   between rows. The reference's nine fields — Responsible us, Sale, Upcoming
   appointment, Business Type, Requested Service, Lead Priority, Demo Status,
   Language, Next Step — are nine controls, not nine printed strings.

   FULL-BLEED means the hairline reaches the card's edges, so `.lc-rows`
   cancels the card's 16px side padding with negative margins and each row puts
   it back. The rule is the row's own border-bottom, removed from the last one,
   so a section never ends on a rule that separates it from nothing. */
.lc-rows { margin: 0 -16px; padding: 0; list-style: none; }
.lc-row {
  display: flex; align-items: center; gap: 12px;
  min-height: 44px; padding: 4px 16px;
  border-bottom: 1px solid var(--pk-line);
}
.lc-row:last-child { border-bottom: 0; }
/* The label never shrinks below the point it stops being readable, and never
   grows past 45% of the column — past that the value has nowhere to go. */
.lc-row-label {
  flex: 0 1 auto; min-width: 0; max-width: 45%;
  color: var(--pk-muted); font-size: 12.5px; line-height: 1.35;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lc-row-value { flex: 1 1 auto; min-width: 0; display: flex; justify-content: flex-end; }

/* THE VALUE IS A CONTROL. This is the whole point of the row: today the card
   prints «Не заполнено» as dead text, which is nine fields nobody can fill
   from the card.

   It is a <button> and not a <select> ON PURPOSE, and the reason is already
   settled in this repo: a native select's option list is drawn by the
   operating system and cannot be styled at all, which is how the owner got a
   white popup on a dark screen («дизайн всплывашки ужасен») — see `.pk-seg` in
   redesign.css. The chevron here opens our own popup, through popupLayer,
   exactly as the pipeline picker does.

   Transparent border, not none: an empty value and a filled one must not shift
   the row by a pixel when one gains a hover outline. */
.lc-val {
  max-width: 100%; min-height: 30px; height: 30px; padding: 0 8px;
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid transparent; border-radius: 8px; background: none;
  color: var(--pk-text); font: inherit; font-size: 13px; text-align: end;
  cursor: pointer;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lc-val:hover { border-color: var(--pk-line-2); background: rgba(255, 255, 255, 0.04); }
.lc-val:focus-visible { outline: 2px solid var(--pk-blue); outline-offset: 1px; }
.lc-val-chev { flex: 0 0 auto; color: var(--pk-dim); font-size: 10px; }
.lc-val:hover .lc-val-chev { color: var(--pk-muted); }
/* Empty is dim but still a CONTROL — the row must read as fillable, which is
   the difference between this and «Не заполнено» printed in grey. */
.lc-val.is-empty { color: var(--pk-faint); }
.lc-val.is-empty:hover { color: var(--pk-muted); }
/* A value that is genuinely read-only says so by not being a button at all. */
.lc-row-static {
  color: var(--pk-text); font-size: 13px; text-align: end;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── 5 · the contact block, behind a rule ───────────────────────────────────
   The reference separates it: avatar, name, a channel badge, then Company /
   Work phone / Work email / Position on the same row rhythm, then
   `+ Add contact` and `+ Add company`. The rule is the section's own top
   border, full-bleed for the same reason the row hairlines are. */
.lc-contact { margin: 14px -16px 0; padding: 14px 16px 0; border-top: 1px solid var(--pk-line-2); }
.lc-contact-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.lc-contact-avatar {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--pk-blue-soft); color: var(--t349); font-size: 14px; font-weight: 600;
}
.lc-contact-id { min-width: 0; }
.lc-contact-name {
  display: block; color: var(--pk-text); font-size: 14px; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* `● Boardroom AI` — which channel this person is reachable on. The dot is a
   ::before, so the badge carries no glyph in its text content and a screen
   reader reads the channel rather than a bullet. */
.lc-contact-badge {
  display: inline-flex; align-items: center; gap: 5px; margin-top: 3px;
  color: var(--pk-muted); font-size: 12px;
}
.lc-contact-badge::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--pk-green); flex: 0 0 auto;
}
.lc-contact-adds { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.lc-add {
  min-height: 28px; height: 28px; padding: 0 11px;
  border: 1px dashed var(--pk-line-2); border-radius: 999px; background: none;
  color: var(--pk-muted); font: inherit; font-size: 12px; cursor: pointer;
}
.lc-add:hover { color: var(--pk-text); border-color: var(--pk-blue-line); border-style: solid; }

/* ── 6 · the ••• menu label, which must never ellipsise ─────────────────────
   See the adversary note at the top of this section. This is the reset for
   `styles.css:62`, and it is what makes «Вернуть Марию сейчас» readable. A
   menu item is not a table cell: it wraps to a second line rather than losing
   its last word, and the menu is wide enough that it rarely has to.

   Written against `.lw-menu button` as well as `.lc-menu-label`, because the
   menu that carries the defect today is `.lw-menu`, and this file is the only
   one in the cascade that can fix it without editing lead-workspace.css. */
.lw-menu button, .lc-menu-label {
  white-space: normal; overflow: visible; text-overflow: clip;
  min-height: 34px; height: auto; line-height: 1.35;
}
/* AND THE `?` IS TAKING HALF THE ROW. THIS is the truncation, measured.
   `lead-workspace.css` declares `.lw-menu li { display: flex }` and
   `.lw-menu button { flex: 1 }` — and `.ck-hint` IS a <button>, so it matches
   that same rule and claims an equal share of the row. Measured at 1536 on the
   shipped stylesheets: the two items with no hint give their label 246px; the
   one item that has a hint gives its label 120px, against a natural width of
   155. That is «Вернуть Мари…», exactly as reported.

   So the doc's reading — "`.lw-menu` is too narrow" — is not quite it. The
   menu is wide enough; one row was being split in half by a 16px glyph. A
   wider menu alone would have moved the truncation point without removing it,
   which is the kind of fix that comes back. The hint takes its own 16px, and
   the label takes the rest. */
.lw-menu .ck-hint { flex: 0 0 16px; }
/* Room for the longest item this menu carries, once the label actually gets
   the row. */
.lw-menu { width: 300px; }

/* ── 7 · and the hint bubble, which is clipped by something else entirely ───
   «проверить вопросики — нигде не показывает ничего». Measured at 1920 in the
   real shell, walking every clipping ancestor between the `?` and the
   document, the bubble is 260x55 at x 1738–1998, y 153:

     .lw-main        overflow hidden   cuts 100px off its RIGHT, 5px off its TOP
     .lw-page        overflow-x hidden cuts  90px off its right, 5px off its top
     main.workspace  overflow hidden   cuts  78px off its right
     .lw-menu        no overflow declared at all — CLIPS NOTHING

   So the spec's reading is wrong in its cause and right in its conclusion. The
   bubble is NOT "cut off by the menu's own bounds": `.lw-menu` has no overflow
   property, and widening it would have changed nothing. The clipper is
   `.lw-main`'s `overflow: hidden` — which this file added, a few hundred lines
   above, so each zone would read as its own rounded surface. A rule for the
   panel's corners quietly amputated every tooltip inside it.

   Two geometry fixes, both here, because the bubble is only ever clipped when
   it opens off the top-right of a panel:

     right-anchored, not centred — the `?` sits at the right edge of a menu
       that sits at the right edge of `.lw-main`, so a bubble centred on it
       always hangs 100px into the panel border. Anchored to the hint's right
       edge it grows leftward, into 300px of menu and then into the whole
       conversation column.
     downward, not upward — the menu opens 49px below the panel's top, and a
       55px bubble above a control that close to the edge cannot fit. Below it
       there are three menu rows and the entire thread.

   THIS DOES NOT PRE-EMPT THE SPEC'S PREFERRED FIX. docs/LEAD_CARD_TARGET_KOMMO.md
   asks for the `?` to be dropped from menu rows and its text moved to the row's
   own `title`, which is a component change and still the better answer — a menu
   item that needs a footnote is a menu item whose wording is wrong. These rules
   are simply what makes the control honest until that lands, and they go inert
   the moment the `?` leaves the menu. */
.lw-menu .ck-hint::after {
  inset-inline-start: auto; inset-inline-end: 0; transform: none;
  bottom: auto; top: calc(100% + 8px);
}

/* ═══════════════════════════════════════════════════════════════════════════
   LIGHT THEME — the second palette
   ═══════════════════════════════════════════════════════════════════════════

   WHY HERE. This file is already the token authority: the block at the top of
   it re-points --pk-* and --rp-*, which is why moving those moves every screen
   at once. A light theme is that same operation with a second set of values,
   so it belongs beside the dark one rather than in a ninth stylesheet that
   would have to win a load-order argument with this one.

   WHY light-dark() AND NOT A SECOND :root BLOCK. The obvious shape — repeat
   every token under [data-theme="light"] — writes the palette out twice, and
   two copies of a palette in this repository is how four stale pricing files
   happened. light-dark(LIGHT, DARK) states both values in ONE declaration, so
   a token cannot be updated in one theme and forgotten in the other. Verified
   available in the target browser before adopting it (Chrome 148; CSS baseline
   since 2024).

   HOW THE THREE STATES WORK. The attribute only ever moves `color-scheme`;
   every colour below follows from that automatically:

     :root                       → color-scheme: dark        (today's product)
     [data-theme="light"]        → color-scheme: light
     [data-theme="dark"]         → color-scheme: dark
     [data-theme="system"]       → color-scheme: light dark   (follows the OS)

   Because this resolves during the first CSS parse, there is NO dark flash on
   a light theme and no blocking script in <head> is required. Setting
   `color-scheme` also hands native scrollbars, form controls and caret colours
   to the browser, which is why those do not need rules of their own.

   THE DEFAULT IS STILL DARK, deliberately. Nothing changes for anyone who does
   not open the switch — an existing operator's next login looks exactly as it
   did. Light is opted into, not applied to everybody because a partner asked.

   WHAT WAS RE-DERIVED RATHER THAN INVERTED. Three families would be unreadable
   if flipped, so each got a decision:

     - The ten stage colours were picked for contrast against a #121821 panel.
       On white every one of them fails. They are re-chosen at the SAME HUE and
       ~4.5:1 on white, so a client who colours a stage keeps the colour they
       named while staying legible.
     - The semantic set. #4ade80 on white is 1.6:1 — a status nobody can read.
       Darkened to carry the same meaning at a legible weight.
     - The white-alpha "lift" overlays. rgba(255,255,255,.03) raises a dark
       panel; on white it does nothing at all. They become dark washes of
       equivalent strength through the --rp-lift-* scale below.
   ═══════════════════════════════════════════════════════════════════════════ */

:root                      { color-scheme: dark; }
:root[data-theme="light"]  { color-scheme: light; }
:root[data-theme="dark"]   { color-scheme: dark; }
:root[data-theme="system"] { color-scheme: light dark; }

:root {
  /* ── the lift scale ─────────────────────────────────────────────────────
     One concept that was written out 23 times as a literal across four
     stylesheets: "raise this surface slightly off the one behind it". On dark
     that is a white wash; on light a dark one. Naming it once is what lets a
     single declaration serve both themes. */
  --rp-lift-1: light-dark(rgba(15, 32, 74, 0.030), rgba(255, 255, 255, 0.020));
  --rp-lift-2: light-dark(rgba(15, 32, 74, 0.045), rgba(255, 255, 255, 0.030));
  --rp-lift-3: light-dark(rgba(15, 32, 74, 0.060), rgba(255, 255, 255, 0.040));
  --rp-lift-4: light-dark(rgba(15, 32, 74, 0.080), rgba(255, 255, 255, 0.055));

  /* Ink and accent steps the older sheets spelled out by hand. */
  --rp-ink-bright: light-dark(#1a3766, #cfe0ff);
  --rp-ink-soft:   light-dark(#566276, #8fa3c8);
  --rp-on-accent:  #ffffff;
  --rp-avatar-bg:  light-dark(rgba(26, 95, 217, 0.12), rgba(120, 190, 255, 0.16));
  --rp-scrim:      light-dark(rgba(255, 255, 255, 0.94), rgba(10, 13, 20, 0.92));
  --rp-field:      light-dark(#e9eef6, rgba(8, 13, 22, 0.72));

  /* ── the approved palette, both themes ──────────────────────────────── */
  --pk-bg:        light-dark(#c3cddc, #0b0f16);
  --pk-panel:     light-dark(#fbfcfe, #121821);
  --pk-card:      light-dark(#f1f5fa, #182029);
  --pk-card-hi:   light-dark(#e9eef6, #1c2532);
  --pk-line:      light-dark(rgba(15, 32, 74, 0.20), rgba(148, 178, 255, 0.10));
  --pk-line-2:    light-dark(rgba(15, 32, 74, 0.26), rgba(148, 178, 255, 0.18));
  --pk-text:      light-dark(#0f1724, #e9eef7);
  /* «на светлой теме поработать над цветом букв и заголовков, чуть темнее»,
     2026-08-21: secondary/tertiary ink already cleared WCAG (~6:1 / ~5.4:1 on
     --pk-panel) but read as flat next to the near-black primary text —
     darkened a step so labels and card sub-text carry more weight, dark
     theme untouched (light-dark()'s second argument). */
  --pk-muted:     light-dark(#37415a, #94a3b8);
  --pk-dim:       light-dark(#3c4658, #6b7a90);
  --pk-faint:     light-dark(#4c5566, #55637a);
  --pk-blue:      light-dark(#1a5fd9, #2f7bff);
  --pk-blue-soft: light-dark(rgba(26, 95, 217, 0.10), rgba(47, 123, 255, 0.13));
  --pk-blue-line: light-dark(rgba(26, 95, 217, 0.40), rgba(47, 123, 255, 0.40));
  --pk-high:      light-dark(#a81e18, #f87171);
  --pk-med:       light-dark(#1a5fd9, #60a5fa);
  --pk-low:       light-dark(#116632, #4ade80);
  --pk-green:     light-dark(#116632, #4ade80);
  --pk-amber:     light-dark(#8a5407, #fbbf24);

  /* ── the ten stage colours ──────────────────────────────────────────────
     Same hue, re-derived for the ground they sit on. See the note above. */
  --pk-stage-blue:    light-dark(#1D63D2, #7FB3FF);
  --pk-stage-indigo:  light-dark(#4F51D6, #A5A8FF);
  --pk-stage-violet:  light-dark(#7B3FD4, #C39BFF);
  --pk-stage-magenta: light-dark(#B03795, #F09BE0);
  --pk-stage-rose:    light-dark(#C43258, #FF9BB5);
  --pk-stage-coral:   light-dark(#C0512A, #FFA98A);
  --pk-stage-sand:    light-dark(#8A6410, #E8C46A);
  --pk-stage-lime:    light-dark(#5F7514, #C3DB6A);
  --pk-stage-mint:    light-dark(#147A53, #6FE3B4);
  --pk-stage-teal:    light-dark(#10707A, #6FDCE3);

  /* ── the rp set (the shell: rail, topbar, cards, footer) ─────────────── */
  /*
     THE LIGHT ARM WAS TOO WASHED OUT, AND THE CAUSE WAS THAT FOUR SURFACES
     WERE ALL BASICALLY WHITE.
     Ground #eef1f7, rail #ffffff, panel #ffffff, panel-2 #f7f9fc, and lines at
     10% alpha: a card on the ground differed by three per cent of lightness and
     its border was almost invisible, so the whole screen read as one sheet of
     milk with text floating on it. The owner's word for it was "очень светлый
     тон", and the fix is NOT to darken the theme — it is to spread the surfaces
     apart so the hierarchy is visible.
     The ground drops and the panel stays white, because separation should come
     from the surface BEHIND the content rather than from tinting the content
     itself: white cards on a deeper ground read as raised, tinted cards on a
     white ground read as dirty. The two line weights roughly double, which is
     what makes a card edge a real edge.
     The dark arm is untouched — it was never the complaint, and changing it
     would put the product's everyday appearance at risk to fix its rarer one.
  */
  /*
     SECOND PASS. Deepening the ground alone was not enough — "всё равно очень
     бело и многое не читается". Two separate causes, and the first pass only
     touched one of them.
     WHITENESS came from the fact that the rail and every panel were pure
     #ffffff. On a screen that is mostly chrome — a full-height rail, a topbar,
     four cards — pure white is most of the pixels, and no ground colour behind
     it can offset that. So the rail and the panels come off pure white by a
     hair. It is not enough to read as a tint on its own; it is enough that the
     screen stops being a lightbox.
     READABILITY was the secondary inks. #566276 and #5b6575 clear the
     4.5:1 minimum on white and still read as faint at 12–13px, which is the
     size most of this product's secondary text actually is. A standard met is
     not the same as a label somebody can read across a desk, and the owner
     reading it is the measurement that counts.
     Checked, not guessed: the text token families were the first suspects and
     were cleared — all 514 --u*/--t* tokens already carry a light arm, and the
     whole product hard-codes only three light greys.
  */
  /*
     THIRD PASS, AND THE LAST ONE THAT MOVES THE GROUND. Two more steps down,
     asked for directly: #eef1f7 → #e2e7f0 → #d7deea → #c1cbdc.
     THE RAIL COMES DOWN WITH IT, and that is the part that is easy to get
     wrong. Dropping only the ground makes a #f6f8fc rail the brightest object
     on the screen — the eye is pulled to the navigation instead of to the work,
     which is the opposite of what a deeper ground is for. The rail stays
     LIGHTER than the ground so it still reads as chrome, just not as a lamp.
     The panel stays nearly white on purpose. With the ground this deep, white
     cards are what carries the hierarchy: the content is the brightest thing on
     the screen and everything else recedes behind it. That is the whole point
     of lowering the ground rather than tinting the cards.
  */
  /*
     THE GROUND WAS NEVER THE PROBLEM, AND FOUR PASSES SPENT ON IT WERE MY
     MISTAKE.
     I held the panels at #fbfcfe on the argument that "tinted cards on a light
     ground read as dirty". That is true of a page with a lot of visible ground.
     It is false here: look at any screen in this product and the cards fill the
     content area, leaving the ground visible only as 12px gutters. The panels
     ARE the screen — nine pixels in ten — so the panels are what "светло"
     was describing, and darkening a ground nobody can see could never have
     answered it.
     So the panel comes off white properly. The ground stays deep underneath it,
     which is what keeps the card edges legible now that the card itself is no
     longer the brightest thing available.
  */
  /*
     FIFTH PASS — HIERARCHY, NOT BRIGHTNESS. The fourth pass pulled every
     surface into ONE band (rail #dce3ed, panel #d4dbe7, panel-2 #dbe2ed,
     topbar white): tinted, yes, but uniform — the owner's screenshot still
     read as one sheet of milk because nothing on it differed from anything
     else. The dark theme never has this problem, and the reason is not that
     it is dark; it is that its planes are DISTINCT (ground < rail < panel)
     and every card carries an edge. So this pass transposes the hierarchy
     instead of the lightness:

       ground   #ccd5e2   the deepest plane, visible in gutters and margins
       rail     #e7ecf4   chrome — lighter than the ground, quieter than cards
       card     #fbfcfe   near-white, the brightest thing on the screen,
                          carried by a border and (light only) a soft shadow
       card-2   #eef2f8   a raised row INSIDE a card, tinted against white

     Four planes a screenshot can tell apart, which is the whole complaint.
     The dark arms are untouched, as everywhere in this section.
  */
  --rp-bg:        light-dark(#c3cddc, #0b0f16);
  --rp-rail:      light-dark(#dbe3ef, #0d121a);
  --rp-panel:     light-dark(#fbfcfe, #121821);
  --rp-panel-2:   light-dark(#eef2f8, #182029);
  --rp-line:      light-dark(rgba(15, 32, 74, 0.26), rgba(148, 178, 255, 0.10));
  --rp-line-2:    light-dark(rgba(15, 32, 74, 0.34), rgba(148, 178, 255, 0.18));
  --rp-ink:       light-dark(#0a101c, #e9eef7);
  --rp-ink-2:     light-dark(#333d4e, #94a3b8);
  --rp-ink-3:     light-dark(#3d4759, #6b7a90);
  --rp-blue:      light-dark(#1a5fd9, #2f7bff);
  --rp-blue-soft: light-dark(rgba(26, 95, 217, 0.10), rgba(47, 123, 255, 0.13));
  --rp-green:     light-dark(#116632, #4ade80);
  --rp-amber:     light-dark(#8a5407, #fbbf24);
  --rp-red:       light-dark(#a81e18, #ef4444);
  --rp-purple:    light-dark(#7B3FD4, #a855f7);
  --rp-cyan:      light-dark(#10707A, #22d3ee);

  /* ── the bd set ─────────────────────────────────────────────────────── */
  --bd-bg:      light-dark(#ccd5e2, #05070c);
  --bd-bg-2:    light-dark(#c6d0df, #080b13);
  --bd-panel:   light-dark(#fbfcfe, #0b1018);
  --bd-panel-2: light-dark(#f1f5fa, #0e141f);
  --bd-raised:  light-dark(rgba(15, 32, 74, 0.030), rgba(255, 255, 255, 0.022));
  --bd-line:    light-dark(rgba(15, 32, 74, 0.16), rgba(148, 178, 255, 0.14));
  --bd-line-2:  light-dark(rgba(15, 32, 74, 0.22), rgba(148, 178, 255, 0.28));
  --bd-edge:    light-dark(rgba(26, 95, 217, 0.45), rgba(120, 190, 255, 0.45));
  --bd-ink:     light-dark(#0f1724, #eaf0ff);
  --bd-ink-2:   light-dark(#566276, #a7b4cc);
  --bd-ink-3:   light-dark(#414c62, #6f7d97);
  --bd-brand:   light-dark(#1a5fd9, #2f7bff);
  --bd-cyan:    light-dark(#10707A, #37d2ff);
  --bd-ok:      light-dark(#15803d, #38d39f);
  --bd-warn:    light-dark(#a16207, #e8b155);
  --bd-risk:    light-dark(#a81e18, #ff6b6b);
  --bd-off:     light-dark(#5b6575, #6f7d97);

  /* ── the original (styles.css) set ──────────────────────────────────── */
  --bg:            light-dark(#ccd5e2, #080b10);
  --bg-2:          light-dark(#c6d0df, #0c1016);
  --panel:         light-dark(#fbfcfe, #11161d);
  --panel-soft:    light-dark(#f2f5fa, #151b23);
  --panel-strong:  light-dark(#e9eef6, #181f29);
  --primary:       light-dark(#1a5fd9, #3d74c5);
  --primary-hover: light-dark(#1550ba, #4a82d3);
  --live:          light-dark(#116632, #3e9b69);
  --live-bg:       light-dark(rgba(21, 128, 61, 0.10), rgba(34, 197, 94, 0.12));
  --warning:       light-dark(#8a5407, #bd8232);
  --warning-bg:    light-dark(rgba(161, 98, 7, 0.10), rgba(245, 158, 11, 0.12));
  --danger:        light-dark(#a81e18, #b84a4a);
  --danger-bg:     light-dark(rgba(194, 38, 31, 0.10), rgba(239, 68, 68, 0.12));
  --neutral:       light-dark(#667080, #6f7b8b);
  --surface:       light-dark(#fbfcfe, #0b1322);
  --surface-2:     light-dark(#f2f5fa, #111c2e);
  --border:        light-dark(#b9c4d8, #27303c);
  --border-strong: light-dark(#a9bcd8, #38547a);
  --accent-blue:   light-dark(#0e7490, #38bdf8);
  --accent-cyan:   light-dark(#10707A, #67e8f9);
  --accent-orange: light-dark(#a16207, #f59e0b);
  --accent-purple: light-dark(#7B3FD4, #8b7cf6);
  --accent-violet: light-dark(#4F51D6, #7d8cff);
  --slate:         light-dark(#566276, #8ea1ba);
  --success:       light-dark(#15803d, #22c55e);
  --text-main:     light-dark(#0f1724, #f2f5f8);
  --text-muted:    light-dark(#3f4a5f, #9da8b6);
  --text-soft:     light-dark(#3c4759, #c4ccd6);
  --shadow:        light-dark(0 16px 34px rgba(15, 32, 74, 0.10), 0 16px 34px rgba(0, 0, 0, 0.22));
  --shadow-soft:   light-dark(0 8px 20px rgba(15, 32, 74, 0.07), 0 8px 20px rgba(0, 0, 0, 0.16));
  --bg-base:       light-dark(#ccd5e2, #0a0c10);
  --bg-surface:    light-dark(#fbfcfe, #12151c);
  --bg-elevated:   light-dark(#f2f5fa, #1a1e27);
  --border-subtle: light-dark(#c4cddc, #232833);
  --text-primary:  light-dark(#0f1724, #edeff3);
  --text-secondary:light-dark(#566276, #9aa3b2);
  --accent:        light-dark(#1a5fd9, #3b82f6);
  --accent-hover:  light-dark(#1550ba, #2f6fe0);
  --accent-subtle: light-dark(#d0daeb, #12233f);
  --info:          light-dark(#0e7490, #38bdf8);
  --glass-line:    light-dark(rgba(15, 32, 74, 0.10), rgba(255, 255, 255, 0.08));
  --gold:          light-dark(#8A6410, #cdb489);
  --gold-soft:     light-dark(#6d4f0d, #e7d6ad);
  --hair:          light-dark(rgba(15, 32, 74, 0.12), rgba(150, 166, 190, 0.12));
  --hair-hi:       light-dark(rgba(26, 95, 217, 0.32), rgba(120, 160, 255, 0.32));
}

/* ── the page ground ──────────────────────────────────────────────────────
   styles.css paints `html` with a literal #030712 and `body` with nothing, so
   the ground was the one surface no token could reach. Both are pinned to the
   token here; without this the whole app sits on a black sheet in light mode
   however well every panel above it behaves. */
html { background: var(--rp-bg); }
body { background: var(--rp-bg); color: var(--rp-ink); }

/* ── the theme switch ─────────────────────────────────────────────────────
   The "on" state is selected by the attribute on <html>, not by a class the
   renderer maintains. That is what lets the row carry no hook state: tinyReact
   can replace the entire DOM and the correct option is still lit, because the
   thing being read never lived in the tree it replaced. */
.profile-theme button {
  color: var(--rp-ink-2);
  background: transparent;
  box-shadow: none;
}
:root[data-theme="light"]  .profile-theme button[data-choice="light"],
:root[data-theme="dark"]   .profile-theme button[data-choice="dark"],
:root[data-theme="system"] .profile-theme button[data-choice="system"] {
  background: var(--rp-blue-soft);
  color: var(--rp-ink);
  box-shadow: inset 0 -2px 0 var(--rp-blue);
}

/* ── the alpha families, as channels ──────────────────────────────────────
   Four colours in this product are never used at one opacity. The hairline
   between panels appears at eleven different alphas across the stylesheets
   (.08 .1 .12 .14 .16 .2 .22 .24 .28 .34 .38), and the "raise this surface"
   wash at seven. Giving each alpha its own token would mean eighteen tokens
   and a judgement call at every call site; flattening them to a four-step
   scale would change how DARK looks, which nobody asked for.

   So the CHANNELS move and the alpha stays where it was written:

       border-color: rgb(var(--ch-line) / .16);

   Dark keeps every alpha it already had, byte for byte — this pass cannot
   regress the theme the product actually ships — and light gets the same
   structure drawn in the opposite direction.

   light-dark() cannot be used here: it resolves to a COLOUR, and `rgb()` needs
   three NUMBERS, so `rgb(light-dark(…) / .16)` is invalid and silently falls
   back to currentColor. (Confirmed in the browser, not assumed — it renders as
   black text-coloured borders.) Hence the attribute selectors below. The values
   are stated once as a --L- and a --D- pair and only the assignment is
   repeated, so the
   two light selectors cannot drift apart. */
:root {
  --D-ch-line:   148 178 255;   --L-ch-line:   15 32 74;
  --D-ch-lift:   255 255 255;   --L-ch-lift:   15 32 74;
  --D-ch-accent: 120 190 255;   --L-ch-accent: 26 95 217;
  --D-ch-blue:    47 123 255;   --L-ch-blue:   26 95 217;
  --D-ch-warm:   214 154  92;   --L-ch-warm:  161  98  7;

  --ch-line:   var(--D-ch-line);
  --ch-lift:   var(--D-ch-lift);
  --ch-accent: var(--D-ch-accent);
  --ch-blue:   var(--D-ch-blue);
  --ch-warm:   var(--D-ch-warm);
}
:root[data-theme="light"] {
  --ch-line:   var(--L-ch-line);
  --ch-lift:   var(--L-ch-lift);
  --ch-accent: var(--L-ch-accent);
  --ch-blue:   var(--L-ch-blue);
  --ch-warm:   var(--L-ch-warm);
}
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] {
    --ch-line:   var(--L-ch-line);
    --ch-lift:   var(--L-ch-lift);
    --ch-accent: var(--L-ch-accent);
    --ch-blue:   var(--L-ch-blue);
    --ch-warm:   var(--L-ch-warm);
  }
}

/* Exact-match ink tokens for the values the workspace sheets spell out by
   hand. The dark side of each pair is the literal those files already use, so
   converting them cannot shift the dark theme by a single byte. */
:root {
  --lw-ink:        light-dark(#0f1724, #eaf0ff);  /* was #eaf0ff  ×22 */
  --lw-ink-bright: light-dark(#1a3766, #cfe0ff);  /* was #cfe0ff  ×30 */
  --lw-ink-soft:   light-dark(#566276, #8fa3c8);  /* was #8fa3c8  ×19 */
  --lw-ink-dim:    light-dark(#5b6575, #6f7d97);  /* was #6f7d97  ×24 */
  --lw-ink-mid:    light-dark(#5c6880, #7b8db0);  /* was #7b8db0  ×7  */
  --lw-ink-faint:  light-dark(#616b7d, #55637f);  /* was #55637f       */
  --lw-panel:      light-dark(#fbfcfe, #0d1420);  /* was #0d1420  ×5  */
  --lw-warm:       light-dark(#a16207, #d69a5c);  /* was #d69a5c  ×7  */
  --lw-late:       light-dark(#b3401f, #e0785c);  /* was #e0785c      */
  --lw-accent:     light-dark(#1a5fd9, #78beff);  /* was #78beff      */
  --lw-ok:         light-dark(#15803d, #78dcaa);  /* was #78dcaa      */
}

/* The remaining accents from the workspace sheets. Same rule as above: the dark
   side of every pair is the literal that file already used, so dark is
   unchanged and only the light side is a new decision. */
:root {
  --D-ch-amber:  245 158  11;   --L-ch-amber:  161  98   7;
  --D-ch-ok:     120 220 170;   --L-ch-ok:      21 128  61;
  --D-ch-violet: 168 148 255;   --L-ch-violet: 123  63 212;
  --D-ch-late:   224 138 106;   --L-ch-late:   179  64  31;

  --ch-amber:  var(--D-ch-amber);
  --ch-ok:     var(--D-ch-ok);
  --ch-violet: var(--D-ch-violet);
  --ch-late:   var(--D-ch-late);

  --lw-accent-2:    light-dark(#1a5fd9, #9ecbff);
  --lw-violet:      light-dark(#7B3FD4, #d3c2ff);
  --lw-ok-2:        light-dark(#15803d, #86efac);
  --lw-ink-standin: light-dark(#4a566b, #9fb2d4);
  --lw-ink-note:    light-dark(#566276, #9fb0cd);
  --lw-ink-quiet:   light-dark(#667080, #6f819f);
  --lw-late-2:      light-dark(#b3401f, #e08a6a);
}
:root[data-theme="light"] {
  --ch-amber:  var(--L-ch-amber);
  --ch-ok:     var(--L-ch-ok);
  --ch-violet: var(--L-ch-violet);
  --ch-late:   var(--L-ch-late);
}
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] {
    --ch-amber:  var(--L-ch-amber);
    --ch-ok:     var(--L-ch-ok);
    --ch-violet: var(--L-ch-violet);
    --ch-late:   var(--L-ch-late);
  }
}

/* Popover drop shadows. Black at .5 is right over a near-black panel and far
   too heavy over white, where a dropdown ends up looking bruised. Same channel
   trick: the alpha stays at each call site, the strength moves with the theme. */
:root                      { --ch-drop: 0 0 0 / .5; }
:root[data-theme="light"]  { --ch-drop: 15 32 74 / .18; }
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] { --ch-drop: 15 32 74 / .18; }
}

/* ── the shell's own colours (redesign.css) ───────────────────────────────
   Same contract as the block above: the dark side of every pair is the literal
   redesign.css already used, so converting it cannot move the dark theme. */
:root {
  --D-ch-blue2:  47 107 255;   --L-ch-blue2:  26  95 217;
  --D-ch-slate: 148 163 184;   --L-ch-slate:  85  98 116;
  --D-ch-green:  34 197  94;   --L-ch-green:  21 128  61;
  --D-ch-red:   239  68  68;   --L-ch-red:   194  38  31;

  --ch-blue2: var(--D-ch-blue2);
  --ch-slate: var(--D-ch-slate);
  --ch-green: var(--D-ch-green);
  --ch-red:   var(--D-ch-red);

  /* Solid shell inks and accents. */
  --sh-blue-1:  light-dark(#1a5fd9, #8fbaff);  /* link / active text  ×22 */
  --sh-blue-2:  light-dark(#1550ba, #6aa2ff);  /* footer + card links ×13 */
  --sh-blue-3:  light-dark(#164ead, #7fb0ff);  /* nav glyph            ×9 */
  --sh-blue-4:  light-dark(#2b4d8f, #b9d0ff);  /* avatar glyph         ×5 */
  --sh-blue-5:  light-dark(#1550ba, #4f86ff);
  --sh-blue-6:  light-dark(#1a5fd9, #2f6bff);
  --sh-slate-1: light-dark(#556274, #93a2bd);  /* system nav glyph     ×4 */
  --sh-mist:    light-dark(#2b3444, #e6ebf5);  /* near-white headings  ×3 */
  --sh-ok:      light-dark(#15803d, #6ee7a8);
  --sh-ok-2:    light-dark(#15803d, #22c55e);
  --sh-warm:    light-dark(#a16207, #f0b45c);
  --sh-warm-2:  light-dark(#a16207, #f59e0b);
  --sh-violet:  light-dark(#7b3fd4, #a855f7);
}
:root[data-theme="light"] {
  --ch-blue2: var(--L-ch-blue2);
  --ch-slate: var(--L-ch-slate);
  --ch-green: var(--L-ch-green);
  --ch-red:   var(--L-ch-red);
}
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] {
    --ch-blue2: var(--L-ch-blue2);
    --ch-slate: var(--L-ch-slate);
    --ch-green: var(--L-ch-green);
    --ch-red:   var(--L-ch-red);
  }
}

/* ── the legacy sheet's colours (styles.css, cabinet-system.css) ──────────
   The long tail. Each light value was derived by flipping lightness about the
   midpoint at constant hue and then CORRECTED by hand where the arithmetic
   produced something legible-on-paper but not on a screen: a mid-lightness
   accent like #22d3ee flips to roughly L46, which is 2.6:1 on white and fails
   as text. Those were pulled down to the ~4.5:1 band by hand. Surfaces, where
   contrast is not the constraint, kept the derived value. */
:root {
  --D-ch-slate9:  15  23  42;   --L-ch-slate9: 226 232 240;
  --D-ch-cyan:    38 217 255;   --L-ch-cyan:    14 116 144;
  --D-ch-cyan2:   55 210 255;   --L-ch-cyan2:   14 116 144;
  --D-ch-red2:   255 107 107;   --L-ch-red2:   185  28  28;
  --D-ch-red3:   244 114 114;   --L-ch-red3:   185  28  28;
  --D-ch-warm3:  255 201 120;   --L-ch-warm3:  138  90  10;
  --D-ch-warm4:  232 177  85;   --L-ch-warm4:  161  98   7;
  --D-ch-ok3:     74 222 128;   --L-ch-ok3:     21 128  61;
  --D-ch-ok4:     56 211 159;   --L-ch-ok4:     21 128  61;
  --D-ch-ink9:     8  11  19;   --L-ch-ink9:   241 244 248;
  --D-ch-panel9:  13  18  28;   --L-ch-panel9: 240 243 247;
  --D-ch-violet2:125 140 255;   --L-ch-violet2: 79  70 229;

  --ch-slate9:  var(--D-ch-slate9);
  --ch-cyan:    var(--D-ch-cyan);
  --ch-cyan2:   var(--D-ch-cyan2);
  --ch-red2:    var(--D-ch-red2);
  --ch-red3:    var(--D-ch-red3);
  --ch-warm3:   var(--D-ch-warm3);
  --ch-warm4:   var(--D-ch-warm4);
  --ch-ok3:     var(--D-ch-ok3);
  --ch-ok4:     var(--D-ch-ok4);
  --ch-ink9:    var(--D-ch-ink9);
  --ch-panel9:  var(--D-ch-panel9);
  --ch-violet2: var(--D-ch-violet2);

  /* Solid surfaces — derived by ROLE, not by arithmetic. Each dark arm is one
     of three planes, and the light arm takes the matching plane from the
     hierarchy above: deep grounds (#08–#0a) map to the ground family, panels
     (#0b–#14) to the near-white card family, raised chips (#1d–#27) to the
     tinted-on-white family. A raised chip that matched its own panel — which
     is what one shared band produced — is a chip nobody can see. */
  --lg-surf-1: light-dark(#e0e7f1, #223448);
  --lg-surf-2: light-dark(#d5dde9, #0a1120);
  --lg-surf-3: light-dark(#e4eaf3, #273548);
  --lg-surf-4: light-dark(#f2f5fa, #101725);
  --lg-surf-5: light-dark(#f0f4f9, #141926);
  --lg-surf-6: light-dark(#f2f5fa, #101822);
  --lg-surf-7: light-dark(#f4f6fb, #0e1622);
  --lg-surf-8: light-dark(#f6f8fc, #0c1423);
  --lg-surf-9: light-dark(#f8fafd, #0b1322);
  --lg-surf-10: light-dark(#cfd8e4, #0a0d14);
  --lg-surf-11: light-dark(#d0d9e5, #09101a);
  --lg-surf-12: light-dark(#e7ecf4, #080b12);
  --lg-surf-13: light-dark(#f0f4f9, #11161d);
  --lg-surf-14: light-dark(#e6ebf4, #1d2942);
  --lg-surf-15: light-dark(#e8edf5, #23293a);

  /* Solid inks — corrected by hand into the legible band. */
  --lg-ink-1:  light-dark(#0f1923, #f8fafc);
  --lg-ink-2:  light-dark(#132334, #e7eef6);
  --lg-ink-3:  light-dark(#24364a, #cdd9e6);
  --lg-ink-4:  light-dark(#4a5a70, #8ea1b8);
  --lg-cyan:   light-dark(#0e7490, #26d9ff);
  --lg-cyan-2: light-dark(#0e7490, #7fe6ff);
  --lg-cyan-3: light-dark(#0e7490, #22d3ee);
  --lg-red-1:  light-dark(#a1211b, #ff8f8f);
  --lg-red-2:  light-dark(#b91c1c, #ff6b6b);
  --lg-red-3:  light-dark(#b91c1c, #f87171);
  --lg-red-4:  light-dark(#b91c1c, #f98080);
  --lg-warm-1: light-dark(#8a5a0a, #ffc978);
  --lg-warm-2: light-dark(#a16207, #f5a524);
  --lg-ok-1:   light-dark(#15803d, #86efac);
  --lg-ok-2:   light-dark(#15803d, #45d483);
  --lg-ok-3:   light-dark(#15803d, #34d399);
  --lg-ok-4:   light-dark(#15803d, #34d07f);
  --lg-violet: light-dark(#6b21a8, #b57cf7);
  --lg-blue-1: light-dark(#1545bb, #2f6bff);
  --lg-blue-2: light-dark(#1448b0, #3b7cff);
}
:root[data-theme="light"] {
  --ch-slate9:  var(--L-ch-slate9);
  --ch-cyan:    var(--L-ch-cyan);
  --ch-cyan2:   var(--L-ch-cyan2);
  --ch-red2:    var(--L-ch-red2);
  --ch-red3:    var(--L-ch-red3);
  --ch-warm3:   var(--L-ch-warm3);
  --ch-warm4:   var(--L-ch-warm4);
  --ch-ok3:     var(--L-ch-ok3);
  --ch-ok4:     var(--L-ch-ok4);
  --ch-ink9:    var(--L-ch-ink9);
  --ch-panel9:  var(--L-ch-panel9);
  --ch-violet2: var(--L-ch-violet2);
}
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] {
    --ch-slate9:  var(--L-ch-slate9);
    --ch-cyan:    var(--L-ch-cyan);
    --ch-cyan2:   var(--L-ch-cyan2);
    --ch-red2:    var(--L-ch-red2);
    --ch-red3:    var(--L-ch-red3);
    --ch-warm3:   var(--L-ch-warm3);
    --ch-warm4:   var(--L-ch-warm4);
    --ch-ok3:     var(--L-ch-ok3);
    --ch-ok4:     var(--L-ch-ok4);
    --ch-ink9:    var(--L-ch-ink9);
    --ch-panel9:  var(--L-ch-panel9);
    --ch-violet2: var(--L-ch-violet2);
  }
}

/* The product uses PURE white in a handful of places on dark — the lead KPI,
   the brand, the active funnel band — where the off-white --rp-ink would read
   as slightly grey against a black panel. Those keep #fff on dark and take the
   deep ink on light, so converting them costs the dark theme nothing. Measured:
   without this token, 13 elements shifted #ffffff -> #e9eef7. */
:root { --rp-ink-max: light-dark(#0f1724, #ffffff); }

/* Two warm reds sat one hue apart (224,138,106 and 224,120,92) and were briefly
   folded onto one channel; the diff against HEAD caught the 0.5-alpha border on
   the overdue-task field shifting. They are separate channels again. */
:root                      { --D-ch-late2: 224 120 92; --L-ch-late2: 179 64 31; --ch-late2: var(--D-ch-late2); }
:root[data-theme="light"]  { --ch-late2: var(--L-ch-late2); }
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] { --ch-late2: var(--L-ch-late2); }
}

/* The last few surfaces that were still black in light: the sticky topbar, the
   ten `#0f151d` field plates, the two chat/search inputs and the drawer scrim.
   Each was a solid or near-solid literal, so no channel helps — they need a
   pair. Dark side verbatim, as everywhere above. */
:root {
  --rp-topbar-bg: light-dark(rgba(247, 249, 252, 0.94), rgba(10, 13, 20, 0.92));
  --rp-plate:     light-dark(#edf1f8, #0f151d);
  --rp-inset:     light-dark(#edf1f8, rgba(5, 8, 14, 0.66));
  --rp-sunken:    light-dark(#dfe5ee, #16202c);
  --rp-scrim-2:   light-dark(rgba(15, 32, 74, 0.32), rgba(0, 4, 12, 0.76));
}

/* ── THE HARD-CODED NAVY CARDS (found 2026-08-18, round 2) ─────────────────
   The Marketing KPI tiles («Охват», «Лиды», «Выручка от продаж»…) rendered as
   dark navy on the light theme, and the reason is that eleven card families in
   styles.css shared one gradient that ends in a LITERAL — rgba(9, 16, 29, .92)
   — which no token pass could reach. The owner's instruction: «как синяя и
   чуть светлее» — keep the blue character, make it lighter. So the light arms
   below are pale BLUES from the card family, not greys, and every dark arm is
   the exact literal the gradient already used, so dark cannot move.

   Channels (alpha stays at the call site, the file's own convention):
     deep1/deep2  the five tile siblings (integration-card, control-tile,
                  sop-card, revenue-kpi-card, revenue-integration-card)
     deep3        the eleven-card fade (metric/detail/config/source/campaign/
                  meeting/audit/seo-score/report/settings + control-card)
     deep4        crm-connect-card, agent-mode chip.active
     deep5        the truth banner
     xo1/xo2      the Executive Overview accent KPI
     xf1/xf2      the Executive Overview funnel bar track
   Whole-colour pairs for the gradients whose literals carry hex alpha:
     mf-grad-*    media-factory summary tiles, partner card, bar chart
     promo-card-a the behavioural promo popups (their ink is tokens that flip,
                  so a frozen dark card would strand flipped ink on navy)
     bd-flow-*    the Sources→Intelligence→Pipeline→Revenue strip
     bd-header-a  the legacy cabinet workspace header (dead in today's DOM,
                  converted anyway so a revival cannot revive the bug)
     crm-accent-* the CRM open-pipeline accent tile
     bd-surface-2 was only ever a var() FALLBACK (#0e1420) — the token did not
                  exist, so the fallback WAS the value; defining it keeps dark
                  identical and finally gives the popover a light arm. */
:root {
  --D-ch-deep1: 18 30 50;   --L-ch-deep1: 226 234 246;
  --D-ch-deep2:  8 15 28;   --L-ch-deep2: 214 226 242;
  --D-ch-deep3:  9 16 29;   --L-ch-deep3: 228 236 249;
  --D-ch-deep4: 12 20 35;   --L-ch-deep4: 216 228 244;
  --D-ch-deep5:  9 16 30;   --L-ch-deep5: 235 241 250;
  --D-ch-xo1:   22 22 55;   --L-ch-xo1:   228 230 250;
  --D-ch-xo2:   17 17 36;   --L-ch-xo2:   234 236 250;
  --D-ch-xf1:   34 48 90;   --L-ch-xf1:   208 221 243;
  --D-ch-xf2:   27 35 64;   --L-ch-xf2:   199 214 240;
  --D-ch-deep6: 10 18 32;   --L-ch-deep6: 232 239 249;
  --D-ch-deep7:  8 16 30;   --L-ch-deep7: 221 231 245;
  --D-ch-deep8: 17 24 39;   --L-ch-deep8: 244 247 252;
  --D-ch-deep9:  7 12 22;   --L-ch-deep9: 236 241 249;

  --ch-deep1: var(--D-ch-deep1);
  --ch-deep2: var(--D-ch-deep2);
  --ch-deep3: var(--D-ch-deep3);
  --ch-deep4: var(--D-ch-deep4);
  --ch-deep5: var(--D-ch-deep5);
  --ch-xo1:   var(--D-ch-xo1);
  --ch-xo2:   var(--D-ch-xo2);
  --ch-xf1:   var(--D-ch-xf1);
  --ch-xf2:   var(--D-ch-xf2);
  --ch-deep6: var(--D-ch-deep6);
  --ch-deep7: var(--D-ch-deep7);
  --ch-deep8: var(--D-ch-deep8);
  --ch-deep9: var(--D-ch-deep9);

  --mf-grad-a40:  light-dark(#eaf1fa, #12203040);
  --mf-grad-a30:  light-dark(#edf3fb, #12203030);
  --mf-grad-a20:  light-dark(#f0f5fc, #12203020);
  --mf-grad-b:    light-dark(#dfe9f6, #0f1a26);
  --promo-card-a: light-dark(#f4f8fd, #0f1b2e);
  --bd-flow-a:    light-dark(rgba(240, 244, 251, 0.6), rgba(11, 16, 24, 0.6));
  --bd-flow-b:    light-dark(rgba(230, 237, 247, 0.6), rgba(6, 9, 15, 0.6));
  --bd-header-a:  light-dark(rgba(246, 249, 253, 0.72), rgba(14, 20, 31, 0.72));
  --crm-accent-a: light-dark(rgba(221, 232, 247, 0.7), rgba(20, 38, 58, 0.7));
  --crm-accent-b: light-dark(rgba(236, 242, 250, 0.7), rgba(9, 14, 24, 0.7));
  --bd-surface-2: light-dark(#fbfcfe, #0e1420);
}
:root[data-theme="light"] {
  --ch-deep1: var(--L-ch-deep1);
  --ch-deep2: var(--L-ch-deep2);
  --ch-deep3: var(--L-ch-deep3);
  --ch-deep4: var(--L-ch-deep4);
  --ch-deep5: var(--L-ch-deep5);
  --ch-xo1:   var(--L-ch-xo1);
  --ch-xo2:   var(--L-ch-xo2);
  --ch-xf1:   var(--L-ch-xf1);
  --ch-xf2:   var(--L-ch-xf2);
  --ch-deep6: var(--L-ch-deep6);
  --ch-deep7: var(--L-ch-deep7);
  --ch-deep8: var(--L-ch-deep8);
  --ch-deep9: var(--L-ch-deep9);
}
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] {
    --ch-deep1: var(--L-ch-deep1);
    --ch-deep2: var(--L-ch-deep2);
    --ch-deep3: var(--L-ch-deep3);
    --ch-deep4: var(--L-ch-deep4);
    --ch-deep5: var(--L-ch-deep5);
    --ch-xo1:   var(--L-ch-xo1);
    --ch-xo2:   var(--L-ch-xo2);
    --ch-xf1:   var(--L-ch-xf1);
    --ch-xf2:   var(--L-ch-xf2);
    --ch-deep6: var(--L-ch-deep6);
    --ch-deep7: var(--L-ch-deep7);
    --ch-deep8: var(--L-ch-deep8);
    --ch-deep9: var(--L-ch-deep9);
  }
}

/* ── the long tail ───────────────────────────────────────────────────────
   Generated, then reviewed. Every hex below was still a literal after the
   family passes: a one-off ink or plate that appears once or twice. The DARK
   arm of each pair IS the original literal, so this block cannot move the
   dark theme; the light arm is the same hue re-placed at a lightness that
   works on a white ground (text pulled into the ~18-34% band, plates lifted
   above 90%). Names are deliberately anonymous: these are not design
   decisions with meanings, they are the residue of eight years of one-off
   colour picking, and naming them semantically would dignify that. */
:root {
  --t1: light-dark(#e0e4eb, #030712);  /* surface ×1 */
  --t2: light-dark(#dce2e9, #061021);  /* surface ×2 */
  --t3: light-dark(#dce2e9, #07101f);  /* surface ×1 */
  --t4: light-dark(#dfe4eb, #080b10);  /* surface ×3 */
  --t5: light-dark(#dee3eb, #080d13);  /* surface ×1 */
  --t6: light-dark(#dee3eb, #0a0e13);  /* surface ×3 */
  --t7: light-dark(#dee2ea, #0a1017);  /* surface ×3 */
  --t8: light-dark(#dde2ea, #0a111a);  /* surface ×1 */
  --t9: light-dark(#dee3ea, #0b0f14);  /* surface ×1 */
  --t10: light-dark(#dde2ea, #0b1018);  /* surface ×2 */
  --t11: light-dark(#dce2e9, #0b121c);  /* surface ×20 */
  --t12: light-dark(#dce1e9, #0b1220);  /* surface ×5 */
  --t13: light-dark(#dce1e9, #0b131e);  /* surface ×1 */
  --t14: light-dark(#dae0e8, #0b1528);  /* surface ×1 */
  --t15: light-dark(#dce2e9, #0c121a);  /* surface ×1 */
  --t16: light-dark(#dce1e9, #0c131d);  /* surface ×1 */
  --t17: light-dark(#dce2e9, #0c141d);  /* surface ×19 */
  --t18: light-dark(#dce1e9, #0c141f);  /* surface ×1 */
  --t19: light-dark(#dce1e9, #0c1420);  /* surface ×1 */
  --t20: light-dark(#dbe0e9, #0c1424);  /* surface ×2 */
  --t21: light-dark(#dbe1e9, #0c1a22);  /* surface ×1 */
  --t22: light-dark(#dde2ea, #0d1218);  /* surface ×2 */
  --t23: light-dark(#dce1e9, #0d151f);  /* surface ×4 */
  --t24: light-dark(#dae0e8, #0d1526);  /* surface ×1 */
  --t25: light-dark(#dae0e8, #0d1b2a);  /* surface ×1 */
  --t26: light-dark(#dce3e9, #0d1d19);  /* surface ×1 */
  --t27: light-dark(#dce2e9, #0e141b);  /* surface ×1 */
  --t28: light-dark(#dce1e9, #0e141d);  /* surface ×1 */
  --t29: light-dark(#dce1e9, #0e141e);  /* surface ×1 */
  --t30: light-dark(#dbe1e9, #0e1620);  /* surface ×5 */
  --t31: light-dark(#dbe0e9, #0e1722);  /* surface ×2 */
  --t32: light-dark(#dadfe8, #0e1a2b);  /* surface ×1 */
  --t33: light-dark(#d9dee7, #0e1a2e);  /* surface ×1 */
  --t34: light-dark(#dbe2e9, #0e1b20);  /* surface ×2 */
  --t35: light-dark(#dce2e9, #0f141a);  /* surface ×1 */
  --t36: light-dark(#dce1e9, #0f151d);  /* surface ×1 */
  --t37: light-dark(#dbe0e9, #0f151f);  /* surface ×1 */
  --t38: light-dark(#dae0e8, #0f1926);  /* surface ×1 */
  --t39: light-dark(#dae0e8, #0f1a26);  /* surface ×1 */
  --t40: light-dark(#d9dee7, #0f1b2e);  /* surface ×3 */
  --t41: light-dark(#dce1e9, #10161d);  /* surface ×1 */
  --t42: light-dark(#dbe0e9, #10161e);  /* surface ×2 */
  --t43: light-dark(#dbe0e9, #101720);  /* surface ×1 */
  --t44: light-dark(#dae0e8, #101923);  /* surface ×3 */
  --t45: light-dark(#d9dee7, #101a2c);  /* surface ×1 */
  --t46: light-dark(#dadfe8, #101b29);  /* surface ×1 */
  --t47: light-dark(#d9dee7, #101d2d);  /* surface ×2 */
  --t48: light-dark(#dae2e7, #10231a);  /* surface ×1 */
  --t49: light-dark(#d9e1e6, #102d22);  /* surface ×1 */
  --t50: light-dark(#dbe0e9, #111720);  /* surface ×1 */
  --t51: light-dark(#dae0e8, #111722);  /* surface ×3 */
  --t52: light-dark(#dae0e9, #111821);  /* surface ×2 */
  --t53: light-dark(#dae0e8, #111824);  /* surface ×1 */
  --t54: light-dark(#dae0e8, #111923);  /* surface ×1 */
  --t55: light-dark(#dae0e8, #111924);  /* surface ×1 */
  --t56: light-dark(#dadfe8, #111a27);  /* surface ×1 */
  --t57: light-dark(#d9dfe7, #111c2a);  /* surface ×1 */
  --t58: light-dark(#d9dfe7, #111d2a);  /* surface ×2 */
  --t59: light-dark(#d6dce6, #112039);  /* surface ×1 */
  --t60: light-dark(#dbe0e9, #12171e);  /* surface ×1 */
  --t61: light-dark(#dae0e8, #121a24);  /* surface ×1 */
  --t62: light-dark(#dae0e8, #121a25);  /* surface ×1 */
  --t63: light-dark(#dadfe8, #121a26);  /* surface ×1 */
  --t64: light-dark(#d9dee7, #121d2b);  /* surface ×1 */
  --t65: light-dark(#d6dce6, #12203a);  /* surface ×2 */
  --t66: light-dark(#d6dce6, #12233b);  /* surface ×1 */
  --t67: light-dark(#d6e0e3, #123a27);  /* surface ×1 */
  --t68: light-dark(#dadfe8, #131a24);  /* surface ×1 */
  --t69: light-dark(#dadfe8, #131c26);  /* surface ×1 */
  --t70: light-dark(#d9dee7, #141c28);  /* surface ×1 */
  --t71: light-dark(#d9dee7, #141c29);  /* surface ×1 */
  --t72: light-dark(#d8dee7, #141f2c);  /* surface ×1 */
  --t73: light-dark(#d8dde7, #142130);  /* surface ×2 */
  --t74: light-dark(#d6dce5, #14243a);  /* surface ×1 */
  --t75: light-dark(#d6dce5, #14263a);  /* surface ×1 */
  --t76: light-dark(#d5dbe5, #142640);  /* surface ×1 */
  --t77: light-dark(#d9dfe7, #151c25);  /* surface ×1 */
  --t78: light-dark(#d9dfe7, #151d27);  /* surface ×1 */
  --t79: light-dark(#d9dee7, #151d28);  /* surface ×4 */
  --t80: light-dark(#d8dee7, #151e2a);  /* surface ×1 */
  --t81: light-dark(#d7dde6, #152033);  /* surface ×1 */
  --t82: light-dark(#d8dde7, #16202e);  /* surface ×1 */
  --t83: light-dark(#d6dbe5, #162238);  /* surface ×1 */
  --t84: light-dark(#d6dde6, #162334);  /* surface ×1 */
  --t85: light-dark(#d6dbe5, #16233a);  /* surface ×1 */
  --t86: light-dark(#e2e7ee, #16345e);  /* surface ×1 */
  --t87: light-dark(#d6e0e2, #16351f);  /* surface ×1 */
  --t88: light-dark(#e2e7ee, #16365e);  /* surface ×1 */
  --t89: light-dark(#e5edef, #164653);  /* surface ×1 */
  --t90: light-dark(#d9dfe7, #171d25);  /* surface ×2 */
  --t91: light-dark(#d9dee7, #171d26);  /* surface ×1 */
  --t92: light-dark(#d8dde7, #17202c);  /* surface ×1 */
  --t93: light-dark(#d7dde6, #172131);  /* surface ×1 */
  --t94: light-dark(#d6dbe5, #172238);  /* surface ×1 */
  --t95: light-dark(#d6dde6, #172433);  /* surface ×1 */
  --t96: light-dark(#d6dbe5, #17263a);  /* surface ×1 */
  --t97: light-dark(#d4dae4, #172b45);  /* surface ×1 */
  --t98: light-dark(#e3e8ef, #173257);  /* surface ×1 */
  --t99: light-dark(#e2e7ee, #17345d);  /* surface ×1 */
  --t100: light-dark(#e1e6ed, #173662);  /* surface ×1 */
  --t101: light-dark(#e2e8ee, #17375c);  /* surface ×1 */
  --t102: light-dark(#d4dde2, #174534);  /* surface ×1 */
  --t103: light-dark(#d8dde7, #18202c);  /* surface ×1 */
  --t104: light-dark(#d8dde7, #18212b);  /* surface ×1 */
  --t105: light-dark(#d8dde7, #18212d);  /* surface ×1 */
  --t106: light-dark(#d7dde7, #18212e);  /* surface ×3 */
  --t107: light-dark(#d5dbe5, #18263a);  /* surface ×1 */
  --t108: light-dark(#e5eaf0, #18304f);  /* surface ×1 */
  --t109: light-dark(#e4e8ef, #183155);  /* surface ×1 */
  --t110: light-dark(#e2e7ee, #18345a);  /* surface ×1 */
  --t111: light-dark(#d7dde6, #192230);  /* surface ×1 */
  --t112: light-dark(#d7dde6, #1a222d);  /* surface ×1 */
  --t113: light-dark(#d7dde6, #1a222e);  /* surface ×1 */
  --t114: light-dark(#d6dce6, #1a2431);  /* surface ×1 */
  --t115: light-dark(#d6dce5, #1b2633);  /* surface ×1 */
  --t116: light-dark(#e3e8ee, #1b3655);  /* surface ×1 */
  --t117: light-dark(#dfe6ec, #1b4a78);  /* surface ×1 */
  --t118: light-dark(#d8dbe6, #1c1830);  /* surface ×1 */
  --t119: light-dark(#d4d9e4, #1c2740);  /* surface ×1 */
  --t120: light-dark(#d5dbe5, #1c2836);  /* surface ×2 */
  --t121: light-dark(#e3eaef, #1c3a52);  /* surface ×1 */
  --t122: light-dark(#d7dce5, #1d222d);  /* surface ×1 */
  --t123: light-dark(#e5e8ef, #1d2e4c);  /* surface ×1 */
  --t124: light-dark(#dfe4ec, #1f6feb);  /* surface ×2 */
  --t125: light-dark(#d6dae5, #202433);  /* surface ×1 */
  --t126: light-dark(#d4dbe5, #202b39);  /* surface ×1 */
  --t127: light-dark(#d5dbe4, #222a34);  /* surface ×1 */
  --t128: light-dark(#dfece6, #236b4b);  /* surface ×1 */
  --t129: light-dark(#dedde5, #241417);  /* surface ×1 */
  --t130: light-dark(#dadbe6, #241a2e);  /* surface ×1 */
  --t131: light-dark(#dfece6, #246c4a);  /* surface ×1 */
  --t132: light-dark(#dfece5, #247e4c);  /* surface ×1 */
  --t133: light-dark(#dfe5ec, #254d82);  /* surface ×1 */
  --t134: light-dark(#e7ebf0, #26303b);  /* surface ×1 */
  --t135: light-dark(#e7ebef, #27313d);  /* surface ×1 */
  --t136: light-dark(#e6eaef, #27313e);  /* surface ×1 */
  --t137: light-dark(#e0e6ed, #273b54);  /* surface ×1 */
  --t138: light-dark(#e0ede7, #285440);  /* surface ×1 */
  --t139: light-dark(#e0ede7, #285442);  /* surface ×2 */
  --t140: light-dark(#dfe7ec, #296287);  /* surface ×1 */
  --t141: light-dark(#dddce3, #2a1519);  /* surface ×1 */
  --t142: light-dark(#dedfe4, #2a1a0e);  /* surface ×1 */
  --t143: light-dark(#dee0e4, #2a1e0c);  /* surface ×1 */
  --t144: light-dark(#e4e8ee, #2b3644);  /* surface ×1 */
  --t145: light-dark(#e2e7ee, #2b3748);  /* surface ×1 */
  --t146: light-dark(#dfece5, #2c5f45);  /* surface ×2 */
  --t147: light-dark(#dfece5, #2f6b4a);  /* surface ×1 */
  --t148: light-dark(#dfe4ec, #2f6fc7);  /* surface ×1 */
  --t149: light-dark(#dfece6, #2f9d68);  /* surface ×1 */
  --t150: light-dark(#dfece1, #2f9e44);  /* surface ×1 */
  --t151: light-dark(#dcdee2, #302312);  /* surface ×1 */
  --t152: light-dark(#e3e6ec, #303846);  /* surface ×1 */
  --t153: light-dark(#dfe4ec, #314361);  /* surface ×1 */
  --t154: light-dark(#dfe4ec, #315487);  /* surface ×1 */
  --t155: light-dark(#dfe5ec, #315f96);  /* surface ×1 */
  --t156: light-dark(#dfe5ec, #315f98);  /* surface ×1 */
  --t157: light-dark(#dfe5ec, #315f9a);  /* surface ×1 */
  --t158: light-dark(#dcdbe2, #32171d);  /* surface ×1 */
  --t159: light-dark(#e1e5eb, #323d4b);  /* surface ×1 */
  --t160: light-dark(#dfe4ec, #334155);  /* surface ×1 */
  --t161: light-dark(#dfe4ec, #334158);  /* surface ×1 */
  --t162: light-dark(#dcdde1, #342614);  /* surface ×1 */
  --t163: light-dark(#dfe4ec, #3478dc);  /* surface ×1 */
  --t164: light-dark(#dcdee2, #352510);  /* surface ×1 */
  --t165: light-dark(#dfe5ec, #356ca8);  /* surface ×1 */
  --t166: light-dark(#dfe5ec, #356db8);  /* surface ×1 */
  --t167: light-dark(#dfe5ec, #356eaf);  /* surface ×1 */
  --t168: light-dark(#dfe5ec, #38485c);  /* surface ×1 */
  --t169: light-dark(#dfe5ec, #3976c6);  /* surface ×1 */
  --t170: light-dark(#dfe5ec, #397ed9);  /* surface ×1 */
  --t171: light-dark(#dfe5ec, #397fd6);  /* surface ×1 */
  --t172: light-dark(#e2e4e9, #3a3f4a);  /* surface ×1 */
  --t173: light-dark(#f1e7ea, #3b242a);  /* surface ×1 */
  --t174: light-dark(#e5e0ed, #3b2a52);  /* surface ×1 */
  --t175: light-dark(#dfe5ec, #3b5f8a);  /* surface ×1 */
  --t176: light-dark(#dfe5ec, #3b70aa);  /* surface ×1 */
  --t177: light-dark(#dfe4ec, #3b82f6);  /* surface ×3 */
  --t178: light-dark(#dfe5ec, #3c5f86);  /* surface ×1 */
  --t179: light-dark(#dfe5ec, #3c5f8c);  /* surface ×1 */
  --t180: light-dark(#e2dfec, #3d3265);  /* surface ×1 */
  --t181: light-dark(#e1e5ea, #3d4857);  /* surface ×1 */
  --t182: light-dark(#dfe4ec, #3d5170);  /* surface ×1 */
  --t183: light-dark(#dfe5ec, #3d73b1);  /* surface ×1 */
  --t184: light-dark(#dfe5ec, #3e6b9d);  /* surface ×1 */
  --t185: light-dark(#dfe6ec, #3f6f9f);  /* surface ×1 */
  --t186: light-dark(#dfe5ec, #3f89d7);  /* surface ×1 */
  --t187: light-dark(#dfe5ec, #4079b7);  /* surface ×2 */
  --t188: light-dark(#dfe5ec, #4179c3);  /* surface ×1 */
  --t189: light-dark(#dfe4ec, #4388e8);  /* surface ×1 */
  --t190: light-dark(#dfece7, #46a27c);  /* surface ×1 */
  --t191: light-dark(#dfe5ec, #477fc7);  /* surface ×1 */
  --t192: light-dark(#dfe3ec, #4880ff);  /* surface ×2 */
  --t193: light-dark(#dfe5ec, #4a78b5);  /* surface ×1 */
  --t194: light-dark(#dfe5ec, #4a91dc);  /* surface ×1 */
  --t195: light-dark(#1b9346, #4ade80);  /* text ×9 */
  --t196: light-dark(#e7dfec, #4b315e);  /* surface ×1 */
  --t197: light-dark(#dfe5ec, #4b8bd4);  /* surface ×1 */
  --t198: light-dark(#dfe5ec, #4b8fdc);  /* surface ×1 */
  --t199: light-dark(#dfe5ec, #4c8bd2);  /* surface ×1 */
  --t200: light-dark(#dfe5ec, #4c8ed9);  /* surface ×1 */
  --t201: light-dark(#dfe5ec, #4d8bd1);  /* surface ×2 */
  --t202: light-dark(#248957, #4dd08f);  /* text ×11 */
  --t203: light-dark(#dfe5ec, #4e657f);  /* surface ×1 */
  --t204: light-dark(#dfe4ec, #4f8ef7);  /* surface ×5 */
  --t205: light-dark(#ecdfe3, #50313a);  /* surface ×1 */
  --t206: light-dark(#258836, #51cf66);  /* text ×2 */
  --t207: light-dark(#e0e5eb, #52647c);  /* surface ×1 */
  --t208: light-dark(#e1dfec, #554b83);  /* surface ×1 */
  --t209: light-dark(#24894f, #57d38c);  /* text ×12 */
  --t210: light-dark(#eee8e2, #5a3719);  /* surface ×1 */
  --t211: light-dark(#ece8df, #5a4a2a);  /* surface ×1 */
  --t212: light-dark(#27864d, #5fd08c);  /* text ×1 */
  --t213: light-dark(#1c9157, #5fe0a0);  /* text ×2 */
  --t214: light-dark(#e1e5ea, #64748b);  /* surface ×1 */
  --t215: light-dark(#ecdfe1, #65313a);  /* surface ×1 */
  --t216: light-dark(#397555, #67b58c);  /* text ×1 */
  --t217: light-dark(#ecdfdf, #6b2f30);  /* surface ×3 */
  --t218: light-dark(#e2e5e9, #6b7a90);  /* surface ×1 */
  --t219: light-dark(#ecdfe0, #6d3439);  /* surface ×1 */
  --t220: light-dark(#ecdfe1, #6d3b43);  /* surface ×1 */
  --t221: light-dark(#ece6df, #6e4b1d);  /* surface ×1 */
  --t222: light-dark(#163e7b, #6ea8ff);  /* text ×1 */
  --t223: light-dark(#298550, #6fd39a);  /* text ×1 */
  --t224: light-dark(#ecdfe7, #70435f);  /* surface ×1 */
  --t225: light-dark(#e2e5e9, #728198);  /* surface ×1 */
  --t226: light-dark(#ece6df, #76501f);  /* surface ×1 */
  --t227: light-dark(#ecdfe1, #773541);  /* surface ×1 */
  --t228: light-dark(#184988, #77a8e7);  /* text ×1 */
  --t229: light-dark(#205288, #77a9df);  /* text ×1 */
  --nav-accent-media: light-dark(#1f7788, #77cfe0);  /* text ×1 */
  --t231: light-dark(#238755, #78dcaa);  /* text ×1 */
  --t232: light-dark(#16467a, #79b5f5);  /* text ×1 */
  --t233: light-dark(#ece7df, #7a5a1f);  /* surface ×1 */
  --t234: light-dark(#143071, #7aa2ff);  /* text ×1 */
  --t235: light-dark(#143371, #7aa7ff);  /* text ×1 */
  --t236: light-dark(#143a71, #7ab0ff);  /* text ×1 */
  --t237: light-dark(#e1e5ea, #7c8da2);  /* surface ×1 */
  --t238: light-dark(#e2e5e9, #7d8999);  /* surface ×2 */
  --t239: light-dark(#1f8149, #7ee0a8);  /* text ×1 */
  --t240: light-dark(#116632, #7ee2a8);  /* text ×3 */
  --nav-accent-work: light-dark(#13376d, #7fb2ff);  /* text ×1 */
  --t242: light-dark(#13546d, #7fdcff);  /* text ×1 */
  --t243: light-dark(#ecdfdf, #824747);  /* surface ×1 */
  --t244: light-dark(#154478, #82b6ef);  /* text ×1 */
  --t245: light-dark(#ece6df, #8a6536);  /* surface ×1 */
  --t246: light-dark(#3f536e, #8da2be);  /* text ×1 */
  --t247: light-dark(#113361, #8dbdff);  /* text ×1 */
  --t248: light-dark(#115161, #8de9ff);  /* text ×1 */
  --t249: light-dark(#41556c, #8fa2b8);  /* text ×1 */
  --t250: light-dark(#41556c, #8fa2b9);  /* text ×2 */
  --t251: light-dark(#40536d, #8fa2bd);  /* text ×1 */
  --t252: light-dark(#112b5f, #8fb4ff);  /* text ×2 */
  --t253: light-dark(#13396d, #8fb8ef);  /* text ×1 */
  --t254: light-dark(#112f5f, #8fbaff);  /* text ×2 */
  --t255: light-dark(#41546c, #91a2b7);  /* text ×2 */
  --t256: light-dark(#41556c, #91a3b8);  /* text ×1 */
  --t257: light-dark(#41556c, #91a4ba);  /* text ×2 */
  --t258: light-dark(#41546c, #91a4bc);  /* text ×2 */
  --t259: light-dark(#3b526e, #91a8c4);  /* text ×1 */
  --t260: light-dark(#206e4a, #91dfbb);  /* text ×1 */
  --nav-accent-system: light-dark(#41526c, #93a3bd);  /* text ×1 */
  --t262: light-dark(#41556c, #93a5ba);  /* text ×1 */
  --t263: light-dark(#10355d, #93c5fd);  /* text ×1 */
  --t264: light-dark(#41536c, #94a3b8);  /* text ×1 */
  --t265: light-dark(#41536c, #95a3b7);  /* text ×1 */
  --t266: light-dark(#41556c, #95a6ba);  /* text ×1 */
  --t267: light-dark(#41536c, #96a4b7);  /* text ×1 */
  --t268: light-dark(#40546b, #97a8bc);  /* text ×1 */
  --t269: light-dark(#41556c, #98a7b9);  /* text ×1 */
  --t270: light-dark(#40556a, #98aabc);  /* text ×3 */
  --t271: light-dark(#40566a, #9aabba);  /* text ×1 */
  --t272: light-dark(#40536b, #9ba8b8);  /* text ×1 */
  --t273: light-dark(#3e4f68, #9ba9bd);  /* text ×2 */
  --t274: light-dark(#10315c, #9bc3f7);  /* text ×1 */
  --t275: light-dark(#3d5166, #9cacbe);  /* text ×20 */
  --t276: light-dark(#3c4f65, #9cadc1);  /* text ×1 */
  --t277: light-dark(#0f2e54, #9cc8ff);  /* text ×1 */
  --t278: light-dark(#40536b, #9da8b6);  /* text ×1 */
  --t279: light-dark(#3b4d62, #9dafc4);  /* text ×1 */
  --t280: light-dark(#334862, #9db2cc);  /* text ×13 */
  --t281: light-dark(#0f2753, #9dc0ff);  /* text ×1 */
  --t282: light-dark(#3b4e63, #9eafc2);  /* text ×1 */
  --t283: light-dark(#3b4d62, #9eafc3);  /* text ×1 */
  --t284: light-dark(#3b4c62, #9faec2);  /* text ×1 */
  --t285: light-dark(#3a4c61, #9fb0c4);  /* text ×10 */
  --t286: light-dark(#384960, #9fb0c7);  /* text ×1 */
  --t287: light-dark(#334660, #9fb2cc);  /* text ×13 */
  --t288: light-dark(#374b60, #9fb3c8);  /* text ×5 */
  --t289: light-dark(#0e2852, #9fc4ff);  /* text ×1 */
  --t290: light-dark(#0e3152, #9fd0ff);  /* text ×2 */
  --t291: light-dark(#1f6040, #9fe0c0);  /* text ×1 */
  --t292: light-dark(#19603a, #9fe6c0);  /* text ×1 */
  --t293: light-dark(#115e2d, #9ff0bd);  /* text ×2 */
  --t294: light-dark(#364659, #a7b6c8);  /* text ×1 */
  --t295: light-dark(#27573e, #a8d8bf);  /* text ×1 */
  --nav-accent-ai: light-dark(#3b2f8f, #a99cff);  /* text ×1 */
  --t297: light-dark(#303e56, #a9b7cf);  /* text ×1 */
  --t298: light-dark(#2e3e56, #a9b9d1);  /* text ×1 */
  --t299: light-dark(#0e224e, #a9c4ff);  /* text ×2 */
  --t300: light-dark(#0e254e, #a9c8ff);  /* text ×1 */
  --t301: light-dark(#364659, #aab6c5);  /* text ×2 */
  --t302: light-dark(#344357, #aeb8c5);  /* text ×1 */
  --t303: light-dark(#334256, #aeb9c7);  /* text ×1 */
  --t304: light-dark(#334155, #aeb9c8);  /* text ×1 */
  --t305: light-dark(#334054, #aeb9c9);  /* text ×3 */
  --t306: light-dark(#2f3c51, #aebbd0);  /* text ×1 */
  --t307: light-dark(#314051, #aebdce);  /* text ×2 */
  --t308: light-dark(#2f3e51, #aebdd0);  /* text ×1 */
  --t309: light-dark(#2e3d51, #aebdd1);  /* text ×4 */
  --t310: light-dark(#2d3c51, #aebdd2);  /* text ×1 */
  --t311: light-dark(#0e4e36, #afffe1);  /* text ×1 */
  --t312: light-dark(#2e3c4d, #b4c0cf);  /* text ×1 */
  --t313: light-dark(#ece6df, #b58343);  /* surface ×1 */
  --t314: light-dark(#2e3b4c, #b5c0cf);  /* text ×1 */
  --t315: light-dark(#273549, #b6c4d8);  /* text ×1 */
  --t316: light-dark(#2f3c4e, #b7c0cb);  /* text ×1 */
  --t317: light-dark(#273648, #b7c6d8);  /* text ×4 */
  --t318: light-dark(#2b3847, #b8c5d4);  /* text ×1 */
  --t319: light-dark(#2a3747, #b8c5d5);  /* text ×1 */
  --t320: light-dark(#243346, #b9c8db);  /* text ×1 */
  --t321: light-dark(#0e2c4e, #b9d8fb);  /* text ×1 */
  --t322: light-dark(#0e4e28, #b9f3d1);  /* text ×1 */
  --t323: light-dark(#0e4e25, #b9f5cf);  /* text ×1 */
  --t324: light-dark(#ece6df, #ba7a25);  /* surface ×1 */
  --t325: light-dark(#0e4e24, #bbf7d0);  /* text ×1 */
  --t326: light-dark(#122c4a, #bcd4ef);  /* text ×1 */
  --t327: light-dark(#0e2a4e, #bcd8fb);  /* text ×1 */
  --t328: light-dark(#0e2b4e, #bed8f7);  /* text ×1 */
  --t329: light-dark(#0e2a4e, #bfdbfe);  /* text ×2 */
  --t330: light-dark(#222f3e, #c1cedd);  /* text ×1 */
  --t331: light-dark(#142a48, #c4d6ef);  /* text ×1 */
  --t332: light-dark(#212c3b, #c5d0df);  /* text ×1 */
  --t333: light-dark(#212d3b, #c5d1df);  /* text ×1 */
  --t334: light-dark(#0e2d4e, #c6def7);  /* text ×1 */
  --t335: light-dark(#1e2d3e, #c8d5e4);  /* text ×1 */
  --t336: light-dark(#1b2d41, #c8d7e8);  /* text ×1 */
  --t337: light-dark(#0e2c4e, #c8ddf5);  /* text ×1 */
  --t338: light-dark(#270e4e, #c9a6ff);  /* text ×2 */
  --t339: light-dark(#513131, #c9b3b3);  /* text ×1 */
  --t340: light-dark(#222c3a, #c9d2df);  /* text ×1 */
  --t341: light-dark(#0e2a4d, #c9dcf5);  /* text ×1 */
  --t342: light-dark(#222d3a, #cbd5e1);  /* text ×3 */
  --t343: light-dark(#1a2941, #cbd7ea);  /* text ×1 */
  --t344: light-dark(#1c2c40, #cbd8e8);  /* text ×1 */
  --t345: light-dark(#765d32, #cdb489);  /* text ×1 */
  --t346: light-dark(#1f2c3d, #cdd8e6);  /* text ×5 */
  --t347: light-dark(#172c45, #cddcee);  /* text ×1 */
  --t348: light-dark(#102b4c, #cfe0f5);  /* text ×1 */
  --t349: light-dark(#0e254e, #cfe0ff);  /* text ×13 */
  --t350: light-dark(#0e2c4e, #cfe2f7);  /* text ×1 */
  --t351: light-dark(#1f3c2d, #cfe6da);  /* text ×1 */
  --t352: light-dark(#1c2b40, #d1dceb);  /* text ×2 */
  --t353: light-dark(#886126, #d2a35c);  /* text ×1 */
  --t354: light-dark(#1b2a41, #d4deed);  /* text ×1 */
  --t355: light-dark(#876726, #d6b36d);  /* text ×1 */
  --t356: light-dark(#162a46, #d6e2f2);  /* text ×1 */
  --t357: light-dark(#7d6328, #d7bd82);  /* text ×4 */
  --t358: light-dark(#1a2b42, #d7e1ef);  /* text ×1 */
  --t359: light-dark(#0e294e, #d7e8ff);  /* text ×1 */
  --t360: light-dark(#1c2b40, #d8e1ee);  /* text ×1 */
  --t361: light-dark(#1b2a41, #d9e2ef);  /* text ×1 */
  --t362: light-dark(#172b44, #d9e4f2);  /* text ×1 */
  --t363: light-dark(#172d44, #d9e5f2);  /* text ×1 */
  --t364: light-dark(#0e254e, #d9e7ff);  /* text ×1 */
  --t365: light-dark(#0e2c4e, #d9ebff);  /* text ×1 */
  --t366: light-dark(#1d2d3e, #dbe4ee);  /* text ×8 */
  --t367: light-dark(#1c2c40, #dbe4ef);  /* text ×1 */
  --t368: light-dark(#1b2d41, #dbe5f0);  /* text ×10 */
  --t369: light-dark(#182d43, #dbe6f2);  /* text ×1 */
  --t370: light-dark(#112a4b, #dbe7f7);  /* text ×1 */
  --t371: light-dark(#0e234e, #dbe7ff);  /* text ×1 */
  --t372: light-dark(#0e274e, #dbe9ff);  /* text ×3 */
  --t373: light-dark(#0e294e, #dbeafe);  /* text ×5 */
  --t374: light-dark(#1d2d3f, #dce5ef);  /* text ×1 */
  --t375: light-dark(#192a43, #dce5f2);  /* text ×1 */
  --t376: light-dark(#192c43, #dce6f2);  /* text ×1 */
  --t377: light-dark(#11294b, #dce7f7);  /* text ×1 */
  --t378: light-dark(#142d47, #dce8f5);  /* text ×2 */
  --t379: light-dark(#0e2b4e, #dcecff);  /* text ×1 */
  --t380: light-dark(#0e4e24, #dcfce7);  /* text ×4 */
  --t381: light-dark(#0e2c4e, #ddebfb);  /* text ×1 */
  --t382: light-dark(#180e4e, #ded8ff);  /* text ×1 */
  --t383: light-dark(#0e2c4e, #dfeeff);  /* text ×1 */
  --t384: light-dark(#ecdfdf, #e05c5c);  /* surface ×1 */
  --t385: light-dark(#ecdfdf, #e5484d);  /* surface ×1 */
  --t386: light-dark(#132a48, #e5edf8);  /* text ×1 */
  --t387: light-dark(#523f19, #e6d3ad);  /* text ×2 */
  --t388: light-dark(#1a2d42, #e6edf5);  /* text ×1 */
  --t389: light-dark(#182b44, #e6edf6);  /* text ×14 */
  --t390: light-dark(#651818, #e79a9a);  /* text ×1 */
  --t391: light-dark(#1b2b41, #e7edf5);  /* text ×1 */
  --t392: light-dark(#0e264e, #e7f0ff);  /* text ×1 */
  --t393: light-dark(#544117, #e8d5ab);  /* text ×1 */
  --t394: light-dark(#1f2d3c, #e8edf3);  /* text ×1 */
  --t395: light-dark(#182b43, #e9eff7);  /* text ×3 */
  --t396: light-dark(#162c46, #e9f0f8);  /* text ×1 */
  --t397: light-dark(#142c47, #eaf1f9);  /* text ×1 */
  --t398: light-dark(#0f284d, #eaf1fb);  /* text ×2 */
  --t399: light-dark(#0e234e, #eaf1ff);  /* text ×10 */
  --t400: light-dark(#3d1f1f, #ecd9d9);  /* text ×1 */
  --t401: light-dark(#1c2e40, #edf2f7);  /* text ×1 */
  --t402: light-dark(#1a2c42, #edf2f8);  /* text ×2 */
  --t403: light-dark(#0e2c4e, #edf4fc);  /* text ×2 */
  --t404: light-dark(#0e2a4e, #edf4fd);  /* text ×1 */
  --t405: light-dark(#0e2a4e, #edf5ff);  /* text ×1 */
  --t406: light-dark(#182c44, #eef3f9);  /* text ×1 */
  --t407: light-dark(#11274a, #eef3fb);  /* text ×2 */
  --t408: light-dark(#112c4a, #eef4fb);  /* text ×10 */
  --t409: light-dark(#0e2c4e, #eef5fd);  /* text ×1 */
  --t410: light-dark(#0e284e, #eef5ff);  /* text ×1 */
  --t411: light-dark(#0e2c4e, #eef6ff);  /* text ×1 */
  --t412: light-dark(#ecdfdf, #ef4444);  /* surface ×2 */
  --t413: light-dark(#4b1015, #efb5ba);  /* text ×1 */
  --t414: light-dark(#7c5416, #efc27d);  /* text ×1 */
  --t415: light-dark(#0e2a4e, #eff6ff);  /* text ×1 */
  --t416: light-dark(#701414, #f08a8a);  /* text ×1 */
  --t417: light-dark(#93681a, #f0b64d);  /* text ×5 */
  --t418: light-dark(#4b1117, #f0bdc2);  /* text ×1 */
  --t419: light-dark(#835e17, #f0c674);  /* text ×2 */
  --t420: light-dark(#1a2c42, #f0f4f9);  /* text ×8 */
  --t421: light-dark(#7d5616, #f1c47a);  /* text ×1 */
  --t422: light-dark(#102b4c, #f1f6fc);  /* text ×1 */
  --t423: light-dark(#5b101b, #f2a1ad);  /* text ×1 */
  --t424: light-dark(#724f14, #f2ca86);  /* text ×1 */
  --t425: light-dark(#202e3c, #f2f5f8);  /* text ×1 */
  --t426: light-dark(#162b46, #f2f6fb);  /* text ×3 */
  --t427: light-dark(#4e0e11, #f3b8bb);  /* text ×1 */
  --t428: light-dark(#4e0e0e, #f4b0b0);  /* text ×1 */
  --t429: light-dark(#6d4413, #f4c48a);  /* text ×1 */
  --t430: light-dark(#6d4c13, #f4cd8a);  /* text ×1 */
  --t431: light-dark(#182b43, #f4f7fb);  /* text ×1 */
  --t432: light-dark(#142e48, #f4f8fc);  /* text ×3 */
  --t433: light-dark(#0e2a4e, #f4f8fd);  /* text ×2 */
  --t434: light-dark(#93661a, #f59e0b);  /* text ×2 */
  --t435: light-dark(#152a47, #f5f8fc);  /* text ×2 */
  --t436: light-dark(#7c4a06, #f6c76a);  /* text ×1 */
  --t437: light-dark(#0e314e, #f6fbff);  /* text ×1 */
  --t438: light-dark(#520e0e, #f7a7a7);  /* text ×3 */
  --t439: light-dark(#51360e, #f8d8a7);  /* text ×1 */
  --t440: light-dark(#523b0e, #f8dca6);  /* text ×2 */
  --t441: light-dark(#0e294e, #f8fbff);  /* text ×3 */
  --t442: light-dark(#93721a, #fbbf24);  /* text ×7 */
  --t443: light-dark(#4e3c0e, #fde4a6);  /* text ×1 */
  --t444: light-dark(#4e0e16, #fecdd3);  /* text ×1 */
  --t445: light-dark(#4e300e, #fed7aa);  /* text ×2 */
  --t446: light-dark(#4e410e, #fef3c7);  /* text ×4 */
  --t447: light-dark(#560f1d, #ff9aae);  /* text ×3 */
  --t448: light-dark(#631d12, #ff9b8a);  /* text ×3 */
  --t449: light-dark(#93681a, #ffb020);  /* text ×1 */
  --t450: light-dark(#4e170e, #ffb3a7);  /* text ×2 */
  --t451: light-dark(#4e0e0e, #ffb4b4);  /* text ×3 */
  --t452: light-dark(#7e5516, #ffc46b);  /* text ×1 */
  --t453: light-dark(#4e0e1c, #ffccd7);  /* text ×1 */
  --t454: light-dark(#8b6918, #ffcf5c);  /* text ×4 */
  --t455: light-dark(#4e0e0e, #ffd0d0);  /* text ×1 */
  --t456: light-dark(#826217, #ffd166);  /* text ×1 */
  --t457: light-dark(#4e0e1d, #ffd1dc);  /* text ×1 */
  --t458: light-dark(#4e0e1c, #ffd2dc);  /* text ×1 */
  --t459: light-dark(#4e0e1a, #ffd4dc);  /* text ×1 */
  --t460: light-dark(#4e0e0e, #ffd7d7);  /* text ×1 */
  --t461: light-dark(#4e0e0e, #ffd9d9);  /* text ×1 */
  --t462: light-dark(#4e0e1e, #ffe4eb);  /* text ×4 */
  --t463: light-dark(#4e3a0e, #ffe5ad);  /* text ×1 */
  --t464: light-dark(#392222, #ffffff);  /* text ×6 */
}

/* Two values measured marginally short of 4.5:1 on their real grounds and
   pulled down rather than left as "close enough": the rail's section labels
   (4.27 on the white rail) and the critical mark (4.29 on its own pink chip).
   Dark arms unchanged. */
/* Заголовки групп в рейле — 10px прописными на светлом. Замерено 1 сентября:
   контраст 4.39 против плоскости рейла, то есть «стандарт формально пройден, а
   надпись читается как серый шум». Владелец показал именно на них. Сдвиг
   строго в тёмную сторону — единственное направление, разрешённое для этих
   значений (см. scripts/test-theme.mjs). */
:root { --rp-nav-label: light-dark(#3f4a60, #6b7b99); }

/* Two tokens the stylesheets referenced but nobody ever defined, so every use
   fell through to the pale literal in the var() fallback — invisible in dark
   (the fallback WAS the intended colour) and 3.1:1 in light. Defining them is
   what makes the fallback dead code rather than the actual value.
   Between these two and --pk-faint, 64 of the CRM board's contrast failures
   had three causes, not sixty-four. */
:root {
  --pk-text-dim: light-dark(#5b6575, #8a93a6);
  --bd-accent:   light-dark(#1a5fd9, #7aa7ff);
}

/* TEXT ON A COLOUR THAT IS NOT OURS TO THEME.
   The channel marks carry Instagram pink, Facebook blue, TikTok black — brand
   colours set inline from the channel record, identical in both themes because
   Instagram is not lighter in the morning. Their label therefore cannot use the
   themed ink: --rp-ink-max is white on dark and deep ink on light, which turned
   18 of these chips into dark-on-dark the moment the light theme existed. This
   is the third ink, and the only one that does not move. */
:root { --rp-on-brand: #ffffff; }

/* The two blurred bars that float over content (the voice footer and its twin).
   They need to be near-opaque so the page does not read through them, which is
   why they are a solid-ish plate rather than one of the lift washes. */
:root { --rp-veil: light-dark(rgba(255, 255, 255, 0.94), rgba(14, 20, 32, 0.94)); }

/* The mid-tone text literals the first tail pass wrongly judged "already
   dark enough for white". 4.5:1 against white needs a relative luminance of
   0.183 or less; these sat between 0.183 and 0.40 and measured 3.0-4.4 on a
   white panel. Placed by solving for the ratio rather than by eye. Dark arms
   are the original literals, so dark is untouched. */
:root {
  --u1: light-dark(#1f377a, #5c7dd6);  /* text ×1 */
  --u2: light-dark(#2e456b, #6b8bbf);  /* text ×1 */
  --u3: light-dark(#304a69, #6d91bc);  /* text ×1 */
  --u4: light-dark(#3d4a5c, #6f819a);  /* text ×1 */
  --u5: light-dark(#3d4b5c, #6f8299);  /* text ×1 */
  --u6: light-dark(#3d4b5c, #70839a);  /* text ×1 */
  --u7: light-dark(#3d4a5c, #717e90);  /* text ×1 */
  --u8: light-dark(#3d4a5c, #718198);  /* text ×1 */
  --u9: light-dark(#314868, #7292bd);  /* text ×1 */
  --u10: light-dark(#3d495c, #748195);  /* text ×1 */
  --u11: light-dark(#3d4b5c, #74879e);  /* text ×7 */
  --u12: light-dark(#3d4c5c, #77899d);  /* text ×1 */
  --u13: light-dark(#2e1b7e, #7c5cff);  /* text ×1 */
  --u14: light-dark(#3d495c, #7d8da6);  /* text ×1 */
  --u15: light-dark(#3d4b5c, #7d8ea3);  /* text ×2 */
  --u16: light-dark(#3d4a5c, #7d8ea6);  /* text ×5 */
  --u17: light-dark(#3d4b5c, #7e8a99);  /* text ×1 */
  --u18: light-dark(#3d4a5c, #7f8a99);  /* text ×1 */
  --u19: light-dark(#3d4a5c, #7f8b9b);  /* text ×1 */
  --u20: light-dark(#3d4a5c, #7f8b9c);  /* text ×1 */
  --u21: light-dark(#3d485c, #7f8ca3);  /* text ×1 */
  --u22: light-dark(#3d4a5c, #7f8ea3);  /* text ×1 */
  --u23: light-dark(#3d4c5c, #7f90a3);  /* text ×7 */
  --u24: light-dark(#3d4b5c, #7f91a7);  /* text ×1 */
  --u25: light-dark(#3d4b5c, #7f92aa);  /* text ×6 */
  --u26: light-dark(#3d4b5c, #8191a5);  /* text ×1 */
  --u27: light-dark(#3d4a5c, #8290a3);  /* text ×3 */
  --u28: light-dark(#3d4b5c, #8392a5);  /* text ×1 */
  --u29: light-dark(#3d4a5c, #8394ad);  /* text ×1 */
  --u30: light-dark(#3d4b5c, #8491a1);  /* text ×1 */
  --u31: light-dark(#3d4a5c, #8492a6);  /* text ×1 */
  --u32: light-dark(#3d4a5c, #8493a8);  /* text ×1 */
  --u33: light-dark(#3d4b5c, #8494a7);  /* text ×1 */
  --u34: light-dark(#3d4c5c, #8496aa);  /* text ×2 */
  --u35: light-dark(#3d4b5c, #8497ad);  /* text ×1 */
  --u36: light-dark(#3d4b5c, #8793a2);  /* text ×1 */
  --u37: light-dark(#3d4b5c, #8997a8);  /* text ×2 */
  --u38: light-dark(#5c3d3d, #8a7373);  /* text ×1 */
  --u39: light-dark(#3d4c5c, #8a99a8);  /* text ×1 */
  --u40: light-dark(#3d4b5c, #8e9baa);  /* text ×1 */
  --u41: light-dark(#3d495c, #8e9bb0);  /* text ×1 */
  --u42: light-dark(#3d4b5c, #8ea0b5);  /* text ×1 */
  --u43: light-dark(#3c4b5d, #8ea0b6);  /* text ×1 */
  --u44: light-dark(#3d4b5c, #8f9baa);  /* text ×1 */
  --u45: light-dark(#3d4a5c, #8f9caf);  /* text ×1 */
  --u46: light-dark(#3d4a5c, #8f9db1);  /* text ×1 */
  --u47: light-dark(#3d4b5c, #8fa0b5);  /* text ×1 */
  --u48: light-dark(#3c4b5d, #8fa1b6);  /* text ×9 */
  --u49: light-dark(#3d4b5c, #91a0b2);  /* text ×2 */
  --u50: light-dark(#3d4b5c, #91a0b3);  /* text ×1 */
  --u51: light-dark(#3d4a5c, #91a0b4);  /* text ×1 */
  --u52: light-dark(#5c3d3d, #9a8080);  /* text ×3 */
  --u53: light-dark(#5c3d3d, #b58f8f);  /* text ×1 */
  --u54: light-dark(#7e301b, #e0785c);  /* text ×1 */
}

/* ═══════════════════════════════════════════════════════════════════════════
   SCROLLBARS FOLLOW THE THEME, EXPLICITLY.
   Nothing declared a scrollbar colour anywhere, so every scroller was painted
   by the engine from `color-scheme`. That is correct in Chrome and unreliable
   elsewhere, and in light mode it left a dark track running the full height of
   the content column — the strip in the owner's screenshot. Declared from
   tokens it is right on both arms and on every engine that supports either
   property.
   `scrollbar-color` first (the standard, Firefox and Chrome 121+), the WebKit
   pseudo-elements after it for older Chromium and Safari. Both read the same
   two tokens, so they cannot disagree.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  --rp-scroll-thumb: light-dark(rgba(15, 32, 74, 0.26), rgba(148, 178, 255, 0.22));
  --rp-scroll-track: light-dark(rgba(15, 32, 74, 0.06), rgba(148, 178, 255, 0.05));
}

html { scrollbar-color: var(--rp-scroll-thumb) var(--rp-scroll-track); }
*   { scrollbar-color: var(--rp-scroll-thumb) var(--rp-scroll-track); }

*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: var(--rp-scroll-track); }
*::-webkit-scrollbar-thumb {
  background: var(--rp-scroll-thumb);
  border-radius: 8px;
}
*::-webkit-scrollbar-thumb:hover {
  background: light-dark(rgba(15, 32, 74, 0.38), rgba(148, 178, 255, 0.34));
}
/* The rails that deliberately hide their scrollbar keep hiding it — those rules
   set `display: none` on the pseudo-element and are later in their own files,
   but this one is more specific than nothing, so it is restated here rather
   than left to cascade luck. */
.group-subnav::-webkit-scrollbar,
.module-tabs::-webkit-scrollbar,
.lc-tabs::-webkit-scrollbar { display: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   THE SURFACES styles.css HARD-CODED BEFORE THE THEME EXISTED.
   styles.css carries 46 near-black backgrounds and not one light-dark() token;
   it was written when the product had one theme. Most are harmless — modal
   scrims stay dark in BOTH arms, and the status dots are semantic colours that
   read on either. The list below is the remainder: real surfaces that stayed
   black on a white page.
   FIXED HERE RATHER THAN EDITED THERE, on purpose. pack-design.css is last in
   the cascade, so one reviewable block overrides twenty scattered lines, and
   reverting it is one delete instead of twenty. The originals stay as the dark
   arm's values, which is also the record of what they were.
   EVERY RULE SETS BACKGROUND *AND* COLOUR. Moving a background alone is how a
   panel goes white while its text stays near-white — the defect would be worse
   than the one being fixed, and it would only show on the arm nobody is
   looking at.
   ═══════════════════════════════════════════════════════════════════════════ */

.hero-signal-panel {
  background: light-dark(rgba(255, 255, 255, 0.78), rgba(3, 8, 18, 0.46));
  color: var(--rp-ink);
}

.data-status-line {
  background: light-dark(rgba(255, 255, 255, 0.82), rgba(8, 15, 27, 0.62));
  color: var(--rp-ink-2);
}

/* A code block wants to read as inset on both arms, not as a hole in one and a
   panel in the other. */
.raw-json {
  background: light-dark(#dae0ea, rgba(2, 6, 12, 0.72));
  color: var(--rp-ink);
  border-color: var(--rp-line);
}

.toast {
  background: light-dark(#e3e7ed, rgba(7, 13, 24, 0.96));
  color: var(--rp-ink);
  border-color: var(--rp-line-2);
}

.truth-banner {
  background: light-dark(rgba(255, 255, 255, 0.86), rgba(9, 16, 30, 0.84));
  color: var(--rp-ink);
}

.module-tabs {
  background: light-dark(rgba(255, 255, 255, 0.72), rgba(6, 13, 25, 0.76));
}

/* Inputs. A field must look like a field on both arms — the field token already
   exists for exactly this and was simply never reached from here. */
.range-control input[type="date"],
.roi-input input {
  background: var(--rp-field);
  color: var(--rp-ink);
  border-color: var(--rp-line);
}

/* A row hover is a LIFT, not a colour: the lift scale is the one concept that
   already knows a wash is dark on light and light on dark. */
tr:hover td { background: var(--rp-lift-2); }

.language-switcher,
.sidebar-utility .language-switcher {
  background: light-dark(rgba(15, 32, 74, 0.05), rgba(3, 7, 18, 0.54));
  color: var(--rp-ink-2);
}

.control-tile button:hover,
.agent-version-card.active {
  background: light-dark(rgba(15, 32, 74, 0.07), rgba(30, 41, 59, 0.9));
  color: var(--rp-ink);
}

/* Badges that mean "nothing here". Muted on both arms rather than dark on one. */
.data-source-badge.neutral,
.data-source-badge.disabled,
.button-variant.disabled,
.status-pill.local_only {
  background: light-dark(rgba(15, 32, 74, 0.08), rgba(51, 65, 85, 0.42));
  color: var(--rp-ink-3);
}

.ch-group {
  background: light-dark(rgba(255, 255, 255, 0.66), rgba(12, 18, 28, 0.35));
  border-color: var(--rp-line);
}

/* The track a meter fills. It has to be visible as an EMPTY track, which on a
   white card means a wash and not a white block. */
.xo-bar { background: light-dark(rgba(15, 32, 74, 0.10), rgba(20, 27, 34, 0.9)); }

.xo-chip {
  background: light-dark(rgba(15, 32, 74, 0.05), rgba(20, 27, 34, 0.7));
  color: var(--rp-ink-2);
}
/* 4% чернил на белой панели — 1.08:1, плашки практически нет. Серый остаётся
   серым (серый = «неизвестно»), просто становится видимым. */
.xo-chip.off {
  background: light-dark(rgba(15, 32, 74, 0.10), rgba(20, 27, 34, 0.6));
}

/* A credential the client really did save, which nothing in the product reads
   yet. Not green — nothing was verified. Not the grey of "needs setup" either:
   the client did their half and should not be asked again. And it is allowed to
   wrap, because the words are the whole point of this state. */
.idesk-state-saved {
  border-color: rgba(240, 180, 41, 0.3);
  background: rgba(240, 180, 41, 0.1);
  color: var(--pk-amber, #f0b429);
  white-space: normal;
  text-align: end;
  line-height: 1.25;
}

/* Связь есть, доставки нет — и решает это не клиент. Тот же янтарь, что у
   `saved`, по той же причине: человек сделал свою половину, ждать надо
   провайдера. Зелёный здесь был бы обещанием сообщений, которых Meta не
   пришлёт; серый «нужна настройка» отправил бы клиента настраивать то, что уже
   настроено. Переносится по словам — они и есть содержание состояния. */
.idesk-state-awaiting_provider {
  border-color: rgba(240, 180, 41, 0.3);
  background: rgba(240, 180, 41, 0.1);
  color: var(--pk-amber, #f0b429);
  white-space: normal;
  text-align: end;
  line-height: 1.25;
}

/* THE ONE STATE ON THIS DESK THAT IS ALLOWED TO BE RED.
   Unavailable is grey because that is OUR read failing and the client cannot
   act on it. This one is the opposite: the provider itself refused the key, the
   client is the only person who can fix it, and until they do the agent is not
   answering on this channel. Red is not decoration here — it is the difference
   between a card that reports and a card that warns. Wraps for the same reason
   `saved` does: the words carry the meaning. */
.idesk-state-check_failed {
  border-color: rgba(248, 113, 113, 0.38);
  background: rgba(248, 113, 113, 0.12);
  color: var(--pk-red, #f87171);
  white-space: normal;
  text-align: end;
  line-height: 1.25;
}

/* Google Ads / TikTok Ads (14 сентября 2026): доступ сохранён, но кабинет
   ещё не прочитан — ждём выбора кабинета или шага, который назван под
   плашкой. Янтарь, как у `saved`: клиент свою половину сделал. Отказ
   провайдера в чтении — красный, как `check_failed`: чинит только клиент,
   переподключением. */
.idesk-state-choose_account,
.idesk-state-not_read {
  border-color: rgba(240, 180, 41, 0.3);
  background: rgba(240, 180, 41, 0.1);
  color: var(--pk-amber, #f0b429);
  white-space: normal;
  text-align: end;
  line-height: 1.25;
}
.idesk-state-read_refused {
  border-color: rgba(248, 113, 113, 0.38);
  background: rgba(248, 113, 113, 0.12);
  color: var(--pk-red, #f87171);
  white-space: normal;
  text-align: end;
  line-height: 1.25;
}
/* Список кабинетов на карточке: по кнопке на кабинет, переносятся на узком
   экране. Кнопка вместо <select> намеренно: значение select в tinyReact не
   выставляется, а кнопка — одно нажатие и одно действие. */
.idesk-ads-accounts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.idesk-ads-accounts > .idesk-needs {
  flex-basis: 100%;
}

/* The provider's own sentence, under the card. Quiet rather than loud — the
   chip already carries the alarm, and this is the part the client reads to
   know WHICH thing to fix. */
.idesk-check-error {
  margin: 0;
  color: var(--pk-red, #f87171);
  font-size: 11.5px;
  line-height: 1.45;
}
.idesk-check-when { color: var(--pk-faint); font-size: 11px; }

/* ═══════════════════════════════════════════════════════════════════════════
   LIGHT-ONLY COMPONENT RULES — the pieces a token cannot carry
   ═══════════════════════════════════════════════════════════════════════════

   Everything above moves values through light-dark() pairs, which is right for
   colours. Four things on the light theme need a RULE rather than a value, and
   each rule below is scoped to [data-theme="light"] (plus the system state
   under a light OS), so the dark theme cannot be touched by any of them: on
   dark none of these selectors match at all.

   1. CARD SHADOWS. On dark, a card is separated from the ground by being
      LIGHTER than it; a shadow would be invisible anyway. On light the card is
      near-white on a tinted ground and the border does the near work — the
      shadow is what makes the card read as a raised object at a glance, which
      is the hierarchy the dark theme gets for free. The !important is forced
      by redesign.css's own `.control-card { box-shadow: none !important }`
      (which that file documents as a measured necessity against styles.css);
      a normal declaration here would lose to it in both themes.

   2. THE BRAND MARK. media/brand/boardroom-mark.svg is pale steel and cyan —
      drawn for a dark rail, invisible on a light one. No second asset: the
      mark keeps its one file and light mode puts the dark chip it was drawn
      for back underneath it. The chip doubles as the strongest dark note on
      the screen, which anchors the rail the way the mockups' rail is anchored.

   3. BORO. The mascot is a pale-teal robot rendered transparent; on white it
      dissolves. A soft navy halo behind it (not a box — a radial wash that
      fades to nothing) gives the sprite an edge to exist against, and the
      drop-shadow is re-tinted from black to navy so it reads as shadow rather
      than soot.

   4. THE TOPBAR SEARCH. Its fill is `rgb(var(--ch-lift) / 0.03)` — 3% of navy
      over a near-white bar is arithmetic for "invisible". The dark arm keeps
      its 3% of white; light gets enough wash to read as a control. */

:root[data-theme="light"] .control-card,
:root[data-theme="light"] .xo-card,
:root[data-theme="light"] .module-header,
:root[data-theme="light"] .rp-kpi,
:root[data-theme="light"] .crm-kpi-strip,
:root[data-theme="light"] .crm-kpi-tile,
:root[data-theme="light"] .crm-attention,
:root[data-theme="light"] .crm-segrail,
:root[data-theme="light"] .kb-card,
:root[data-theme="light"] .chat-card,
:root[data-theme="light"] .agent-cards-panel,
:root[data-theme="light"] .agent-cabhead,
:root[data-theme="light"] .agent-integrations,
:root[data-theme="light"] .ac-nav,
:root[data-theme="light"] .ac-section,
:root[data-theme="light"] .ac-soon,
:root[data-theme="light"] .integrations-command,
:root[data-theme="light"] .revenue-integration-grid > *,
:root[data-theme="light"] .media-empty-panel,
:root[data-theme="light"] .chatpane-list,
:root[data-theme="light"] .chatpane-thread,
:root[data-theme="light"] .chatpane-lead,
:root[data-theme="light"] .chatpane-acts {
  box-shadow: 0 1px 2px rgba(15, 32, 74, 0.05), 0 10px 24px rgba(15, 32, 74, 0.07) !important;
}

:root[data-theme="light"] .brand-mark.has-logo,
:root[data-theme="light"] .auth-brand-mark.has-logo {
  background: radial-gradient(circle at 32% 26%, #1b2b4a, #0d1626 68%);
  border-radius: 12px;
  padding: 4px;
  box-shadow: inset 0 0 0 1px rgba(148, 178, 255, 0.18), 0 2px 6px rgba(15, 32, 74, 0.18);
}

:root[data-theme="light"] .boro-avatar {
  background: radial-gradient(closest-side, rgba(15, 32, 74, 0.16), rgba(15, 32, 74, 0.05) 62%, transparent 82%);
  border-radius: 50%;
  filter: drop-shadow(0 10px 14px rgba(15, 32, 74, 0.32));
}

:root[data-theme="light"] .rp-search-control {
  background: rgb(var(--ch-lift) / 0.07);
}

/* The same four, for "system" under a light OS. The attribute value survives
   in storage even though the switch no longer offers it, so the state is kept
   honest rather than assumed away. */
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] .control-card,
  :root[data-theme="system"] .xo-card,
  :root[data-theme="system"] .module-header,
  :root[data-theme="system"] .rp-kpi,
  :root[data-theme="system"] .crm-kpi-strip,
  :root[data-theme="system"] .crm-kpi-tile,
  :root[data-theme="system"] .crm-attention,
  :root[data-theme="system"] .crm-segrail,
  :root[data-theme="system"] .kb-card,
  :root[data-theme="system"] .chat-card,
  :root[data-theme="system"] .agent-cards-panel,
  :root[data-theme="system"] .agent-cabhead,
  :root[data-theme="system"] .agent-integrations,
  :root[data-theme="system"] .ac-nav,
  :root[data-theme="system"] .ac-section,
  :root[data-theme="system"] .ac-soon,
  :root[data-theme="system"] .integrations-command,
  :root[data-theme="system"] .revenue-integration-grid > *,
  :root[data-theme="system"] .media-empty-panel,
  :root[data-theme="system"] .chatpane-list,
  :root[data-theme="system"] .chatpane-thread,
  :root[data-theme="system"] .chatpane-lead,
  :root[data-theme="system"] .chatpane-acts {
    box-shadow: 0 1px 2px rgba(15, 32, 74, 0.05), 0 10px 24px rgba(15, 32, 74, 0.07) !important;
  }
  :root[data-theme="system"] .brand-mark.has-logo,
  :root[data-theme="system"] .auth-brand-mark.has-logo {
    background: radial-gradient(circle at 32% 26%, #1b2b4a, #0d1626 68%);
    border-radius: 12px;
    padding: 4px;
    box-shadow: inset 0 0 0 1px rgba(148, 178, 255, 0.18), 0 2px 6px rgba(15, 32, 74, 0.18);
  }
  :root[data-theme="system"] .boro-avatar {
    background: radial-gradient(closest-side, rgba(15, 32, 74, 0.16), rgba(15, 32, 74, 0.05) 62%, transparent 82%);
    border-radius: 50%;
    filter: drop-shadow(0 10px 14px rgba(15, 32, 74, 0.32));
  }
  :root[data-theme="system"] .rp-search-control {
    background: rgb(var(--ch-lift) / 0.07);
  }
}

/* 5. THE DATE INPUTS ON THE RANGE CONTROL. styles.css pins them with
   `color-scheme: dark` and a solid rgba(7, 13, 24, .92) plate — written when
   the product had one theme, and immune to tokens because color-scheme is not
   a colour. On light they were the last two black rectangles on the Marketing
   page. Dark keeps its declaration untouched; these rules only exist when the
   light palette is active. */
:root[data-theme="light"] .range-control input[type="date"] {
  color-scheme: light;
  background: var(--rp-plate);
}
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] .range-control input[type="date"] {
    color-scheme: light;
    background: var(--rp-plate);
  }
}

/* ---------------------------------------------------------------------------
   ACCOUNTING WORKSPACE — the tab's own sections had no card styling at all
   (a bare `.card` class nothing in this codebase actually defines), so every
   section rendered as unstyled text stacked on the page background. This
   block gives it the same card/grid/chip vocabulary the Desk (.idesk-*) and
   the Revenue tab (.revenue-kpi-*) already established — no new colours, no
   new shapes, just the existing system applied here too.
--------------------------------------------------------------------------- */
.acc-section {
  padding: 16px 18px;
  margin: 0 0 16px;
  border: 1px solid var(--pk-line, var(--border));
  border-radius: 14px;
  background: var(--pk-card, var(--surface));
}
.acc-section h2 {
  margin: 0 0 12px;
  font-size: 15px;
  letter-spacing: 0.01em;
}
/* «РаботаетИз Zoho Books» (владелец, 20 сентября 2026). Плашка состояния и
   подпись к ней — два соседних узла без единого правила раскладки: строка
   `.status-line` была описана только внутри шапки страницы, а в карточках
   раздела осталась голым блоком, и слова слипались без пробела. */
.accounting-workspace .acc-section .status-line {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px;
}
.accounting-workspace .page-header .status-line {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 8px;
}
.accounting-workspace .revenue-kpi-grid {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.accounting-workspace .revenue-kpi-card { min-height: 92px; }
.accounting-workspace .revenue-kpi-card .metric-delta {
  color: var(--pk-dim, var(--text-muted));
  font-size: 11.5px;
  line-height: 1.5;
}
@media (max-width: 900px) {
  .accounting-workspace .revenue-kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .accounting-workspace .revenue-kpi-grid { grid-template-columns: 1fr; }
}
.revenue-kpi-card.tone-bad,
.revenue-kpi-card.tone-risk { border-color: rgba(248, 113, 113, 0.30); background: rgba(248, 113, 113, 0.06); }
.revenue-kpi-card.tone-neutral { border-color: var(--pk-line-2, var(--border)); }
.revenue-kpi-card.tone-good { border-color: rgba(74, 222, 128, 0.24); }
.revenue-kpi-card.tone-warning { border-color: rgba(251, 191, 36, 0.30); background: rgba(251, 191, 36, 0.05); }

/* The document/entry lists are plain <table> elements inside .table-wrap, so
   they already inherit the product's table rules; this only tightens the
   fit inside a narrower card than most tables live in. */
.acc-section .acc-list-table { min-width: 520px; }
.acc-section .acc-list-table th,
.acc-section .acc-list-table td { padding: 10px 12px; font-size: 12.5px; }
.acc-section .empty-state.compact { padding: 14px 4px; }
/* «Провести в Zoho» (11 Sep 2026): the row's button, the preview of exactly
   what will be written, and the result that stays on the row afterwards. */
.acc-post-cell { display: flex; flex-direction: column; gap: 8px; min-width: 220px; }
.acc-post-buttons { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.acc-post-preview {
  display: flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: 12px;
  border: 1px solid rgba(96, 165, 250, 0.35); background: rgba(96, 165, 250, 0.06); max-width: 420px;
}
.acc-post-title { font-size: 12.5px; }
.acc-post-lines { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; margin: 0; font-size: 12.5px; }
.acc-post-lines dt { color: var(--muted, #94a3b8); }
.acc-post-lines dd { margin: 0; overflow-wrap: anywhere; }
.acc-post-ok { margin: 0; font-size: 12.5px; color: var(--success, #4ade80); }
.acc-post-warn { margin: 0; font-size: 12.5px; color: var(--warning, #fbbf24); }
/* Zoho connect feedback — same convention as every other *-note-bad in this
   file: red text for a refusal, plain muted for anything else. */
.acc-connect-feedback-bad { color: var(--pk-high); }

/* AI Accounting — the gaps closed on 12 Sep 2026: the upload card (also a
   drop target), the invoice row actions and payment form, company details,
   the mode cards and the monthly bars. Same tokens as the block above; the
   two bar colours were checked with the dataviz validator in both themes
   (light #1550ba/#a16207, dark #4f86ff/#d97706 on #182029 — all checks pass),
   and they follow the sparklines' entities: receivable blue, overdue amber. */
.acc-upload {
  position: relative;
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 16px;
  padding: 16px; margin: 0 0 14px;
  border: 1.5px dashed var(--pk-line-2, var(--border)); border-radius: 12px;
  background: rgba(96, 165, 250, 0.04);
  transition: border-color 0.15s ease, background 0.15s ease;
}
.acc-upload.is-drag { border-color: rgba(96, 165, 250, 0.75); background: rgba(96, 165, 250, 0.10); }
.acc-upload.is-busy { opacity: 0.85; }
.acc-upload-copy { display: flex; flex-direction: column; gap: 4px; flex: 1 1 260px; min-width: 0; }
.acc-upload-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.acc-upload-state { flex: 1 1 100%; margin: 0; font-size: 12.5px; color: var(--pk-dim, var(--text-muted)); min-height: 1em; }
.acc-upload-state:empty { display: none; }
.acc-upload-state.is-ok { color: var(--success, #4ade80); }
.acc-upload-state.is-bad { color: var(--warning, #fbbf24); }
.acc-missing-chip { align-self: flex-start; }
.acc-inv-actions { display: flex; flex-direction: column; gap: 6px; min-width: 200px; }
.acc-inv-status-select { max-width: 190px; font-size: 12px; padding: 4px 8px; border-radius: 8px; }
.acc-pay-row > td { background: rgba(96, 165, 250, 0.04); }
.acc-pay-form { display: flex; flex-direction: column; gap: 8px; max-width: 640px; }
.acc-pay-grid,
.acc-form-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 12px; max-width: 640px; }
.acc-form-wide { grid-column: 1 / -1; }
@media (max-width: 620px) {
  .acc-pay-grid, .acc-form-grid { grid-template-columns: 1fr; }
}
.acc-mode-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; margin: 0 0 10px; }
@media (max-width: 760px) { .acc-mode-grid { grid-template-columns: 1fr; } }
.acc-mode-card {
  display: flex; gap: 10px; align-items: flex-start; padding: 12px 14px; cursor: pointer;
  border: 1px solid var(--pk-line-2, var(--border)); border-radius: 12px;
}
.acc-mode-card.is-chosen { border-color: rgba(96, 165, 250, 0.6); background: rgba(96, 165, 250, 0.06); }
.acc-mode-card input { margin-top: 3px; }
.acc-mode-copy { display: flex; flex-direction: column; gap: 4px; line-height: 1.45; }
.acc-month-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 8px; }
.acc-month-head h2 { margin-bottom: 6px; }
.acc-bars-legend { display: flex; gap: 14px; font-size: 12px; color: var(--pk-dim, var(--text-muted)); }
.acc-bars-key { display: inline-flex; align-items: center; gap: 6px; }
.acc-bars-key::before { content: ""; width: 10px; height: 10px; border-radius: 3px; }
.acc-bars-key-receivable::before { background: light-dark(#1550ba, #4f86ff); }
.acc-bars-key-overdue::before { background: light-dark(#a16207, #d97706); }
.acc-month-chart svg { display: block; width: 100%; height: auto; max-height: 220px; }
.acc-bars-receivable { fill: light-dark(#1550ba, #4f86ff); }
.acc-bars-overdue { fill: light-dark(#a16207, #d97706); }
.acc-bars-receivable:hover, .acc-bars-overdue:hover { opacity: 0.85; }
.acc-bars-grid { stroke: var(--pk-line, rgba(148, 163, 184, 0.18)); stroke-width: 1; stroke-dasharray: 2 4; }
.acc-bars-baseline { stroke: var(--pk-line-2, rgba(148, 163, 184, 0.35)); stroke-width: 1; }
.acc-bars-axis { fill: var(--pk-dim, #94a3b8); font-size: 10.5px; }
.acc-month-details summary { cursor: pointer; margin-top: 4px; }

/* The daily-report toggle was a bare <input type="checkbox"> — no styling of
   its own anywhere in this codebase, so it fell back to the OS's native
   checkbox, which on a dark theme renders as an unstyled grey square.
   Owner-flagged live as "артефакт кубик" — a real rendering defect, not a
   monitor artifact. appearance:none + a drawn pill/knob, same construction
   as this file's other custom controls (e.g. .lw-headline-select's own
   fix), toggled purely by :checked so no JS beyond the existing enabledEl.
   checked assignment is needed. */
#acc-tg-enabled {
  appearance: none; -webkit-appearance: none;
  position: relative;
  width: 36px; height: 20px; flex: none;
  border-radius: 999px;
  background: rgb(var(--ch-line, 150 166 190) / 0.35);
  cursor: pointer;
  transition: background 0.15s ease;
}
#acc-tg-enabled::after {
  content: "";
  position: absolute; top: 2px; inset-inline-start: 2px;
  width: 16px; height: 16px;
  border-radius: 50%;
  /* var(), not a bare #fff — test-theme-tokens.mjs counts any literal hex/rgb
     background as a new hard-coded colour outside the light-dark() system. */
  background: var(--rp-on-accent, #fff);
  transition: transform 0.15s ease;
}
#acc-tg-enabled:checked { background: var(--rp-green, #22c55e); }
#acc-tg-enabled:checked::after { transform: translateX(16px); }
#acc-tg-enabled:disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Help Center (/help) ─────────────────────────────────────────────────── */
.help-center-page { max-width: 880px; }
.help-center-lede { color: var(--bd-ink-2, var(--muted)); max-width: 60ch; }
.help-center-search { margin: 4px 0 18px; }
.help-center-search input[type="search"] {
  width: 100%; max-width: 480px; padding: 10px 14px; border-radius: 10px;
  border: 1px solid var(--pk-line-2, var(--border)); background: var(--bd-panel, var(--surface));
  color: var(--bd-ink, var(--text)); font-size: 14px;
}
.help-center-count { margin-top: 8px; font-size: 12.5px; color: var(--bd-ink-3, var(--muted)); }
.help-center-empty { color: var(--bd-ink-2, var(--muted)); padding: 20px 0; }
.help-center-sections { display: flex; flex-direction: column; gap: 10px; }
.help-center-section {
  border: 1px solid var(--pk-line-2, var(--border)); border-radius: 12px;
  background: var(--bd-panel, var(--surface)); padding: 2px 16px;
}
.help-center-section > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center;
  justify-content: space-between; gap: 12px; padding: 14px 0; font-weight: 600;
  color: var(--bd-ink, var(--text));
}
.help-center-section > summary::-webkit-details-marker { display: none; }
.help-center-section-count {
  font-size: 11.5px; font-weight: 500; color: var(--bd-ink-3, var(--muted));
  background: var(--bd-raised, rgba(0,0,0,0.04)); border-radius: 999px; padding: 2px 9px;
}
.help-center-rows { margin: 0 0 14px; padding-block: 0 0; padding-inline: 18px 0; display: flex; flex-direction: column; gap: 8px; }
.help-center-rows li { font-size: 13.5px; line-height: 1.55; color: var(--bd-ink-2, var(--muted)); }
.help-center-footer { margin-top: 22px; font-size: 13px; color: var(--bd-ink-3, var(--muted)); }


/* ── ЭКРАН ВХОДА И РЕГИСТРАЦИИ: ФОН С ЛЕНДИНГА ─────────────────────────────
   Owner's call 2026-08-25: the sign-in screen should carry the landing's look,
   but NOT its hero video — he ruled the hero out and asked for the animation
   instead. So this is the landing's OWN ambient field, the drifting point web
   that sits behind every one of its sections, ported in src/lib/authField.js.

   It is also the better engineering answer for a form: the field costs no
   download at all, where the hero costs 1.3 MB before a person can type an
   email.

   Rules the backdrop obeys, in order of importance:
     1. The card stays readable. A scrim sits between the field and the content,
        so contrast never depends on where the points happen to have drifted.
     2. It never intercepts a click — pointer-events: none on the whole layer.
     3. It never scrolls with the card. Fixed, and the shell clips it.
     4. Reduced motion means no motion: startAuthField simply never starts, the
        canvas stays empty, and the panel gradient below carries the look on
        its own. */
/* NO overflow: hidden HERE. I put it on this element to clip the backdrop and
   it broke registration outright: the sign-up form is taller than the viewport,
   and clipping the shell made the page unscrollable — the owner could see the
   email field but never reach the button. The backdrop is position: fixed, so
   the viewport already clips it; the overflow was solving a problem that did
   not exist and creating one that mattered. */
.auth-shell {
  position: relative;
  isolation: isolate;
}
.auth-backdrop {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* The look survives with no canvas at all — this gradient is what a
     reduced-motion visitor sees, and it is a finished background, not a
     fallback. */
  background:
    radial-gradient(1200px 700px at 18% 8%, rgba(47, 123, 255, 0.16), transparent 62%),
    radial-gradient(900px 600px at 88% 92%, rgba(232, 177, 85, 0.10), transparent 60%),
    var(--t5, #0b1018);
}
/* A canvas is a REPLACED element: with width:auto it takes its intrinsic size
   from the width/height attributes and inset:0 does NOT stretch it. The
   landing learned this the expensive way — 210px of field hanging off the side
   of every phone — so the size is declared here too. */
.auth-backdrop-field {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity 900ms ease;
}
.auth-backdrop-field.on { opacity: 0.85; }
/* Barely there. The first version ran 0.28 -> 0.42 and, stacked on a field I
   had already dimmed, left an animation nobody could see — the owner asked
   three times whether it had been done. Readability is carried by the card's
   own blurred surface, which is where it belongs; the backdrop only needs to
   stop the very top of the screen from competing with the heading. */
.auth-backdrop-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(6, 10, 17, 0.20) 0%, rgba(6, 10, 17, 0.10) 45%, rgba(6, 10, 17, 0.22) 100%);
}
/* EVERYTHING EXCEPT THE BACKDROP SITS ABOVE IT — and it is written as
   "everything except" for a reason I got wrong once, live.
   The first version listed the classes it expected: .auth-brand, .auth-card,
   .auth-workspace, section, form. The registration screen's content is
   .auth-workspace-PAGE, which matched none of them, so it stayed unpositioned —
   and an unpositioned block paints BELOW a positioned z-index:0 sibling. The
   backdrop covered the whole sign-up form; the owner saw a page with a logo,
   three bullets and nothing to fill in.
   A list of class names is a guess about markup that will change. This is not. */
.auth-shell > *:not(.auth-backdrop) {
  position: relative;
  z-index: 1;
}
/* The card earns a little more weight now that it floats on a moving field: a
   real surface with a blur behind it, instead of a panel the same colour as
   the air. */
.auth-shell .auth-card {
  /* Tokenised, not a literal: this card must follow the theme like every other
     surface, and a hard-coded dark hex is exactly what test-theme-tokens.mjs
     exists to stop. color-mix keeps the translucency the blur needs while the
     colour itself still comes from --pk-card. */
  background: color-mix(in srgb, var(--pk-card) 84%, transparent);
  backdrop-filter: blur(14px) saturate(1.1);
  border: 1px solid rgba(148, 178, 255, 0.16);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45);
}

/* ── ЭКРАН ВХОДА: ВОЗДУХ МЕЖДУ ЭЛЕМЕНТАМИ ─────────────────────────────────
   Owner, 2026-08-25, pointing at the gap under the email field and the one
   under «Получить код»: they sit on top of one another and need separating.

   Measured before changing anything — the gaps down the card were
   14 → 0 → 16 → 0 → 4 px. Two of them were literally ZERO: the hint panel
   touches the field above it, and «Создать пространство» touches the button
   above it. That is what reads as stuck together, and no amount of padding
   inside those blocks fixes a zero gap between them.

   The three that were 0 or 4 get real separation; the two that already had
   some grow a little. Scoped to .auth-shell so the setup wizard, which uses
   the same .setup-panel elsewhere, is untouched. */
.auth-shell .setup-panel > .draft-field { margin-top: 18px; }
.auth-shell .setup-panel > .media-safety-note { margin-top: 14px; }
.auth-shell .setup-panel > .primary-button { margin-top: 22px; }
.auth-shell .setup-panel > .page-actions { margin-top: 18px; }
.auth-shell .setup-panel > .auth-demo-line { margin-top: 14px; }

/* ── THE SIGN-IN SCREEN, WITH DEPTH ───────────────────────────────────────
   The owner looked at one layer of drifting dots and asked, fairly, whether
   so few effects was really my idea of finished. It was not — it was thin.
   Three layers were missing, and none of them is allowed to compete with the
   form: a person is here to type an email address.
     1. cursor attraction, in authField.js — the field notices you
     2. a slow aurora, below — depth behind the points instead of flat black
     3. one entrance, below — the screen composes itself once and then stops
   Each is off entirely under prefers-reduced-motion. */

/* AURORA. Two very large, very slow radial washes. Deliberately CSS and not
   canvas: transform/opacity animation is composited on the GPU, so this costs
   nothing per frame and cannot slow the point field down. 48 and 61 seconds,
   coprime enough that the pair never visibly repeats its arrangement. */
.auth-backdrop::before,
.auth-backdrop::after {
  content: "";
  position: absolute;
  inset: -25%;
  pointer-events: none;
  /* Below the canvas, which is the subject; this is the room it stands in. */
  z-index: 0;
  will-change: transform, opacity;
}
.auth-backdrop::before {
  background: radial-gradient(38% 34% at 22% 26%,
    color-mix(in srgb, var(--pk-accent, #37d2ff) 16%, transparent) 0%,
    transparent 68%);
  animation: authAuroraA 48s ease-in-out infinite alternate;
}
.auth-backdrop::after {
  background: radial-gradient(34% 30% at 78% 72%,
    rgba(232, 177, 85, 0.13) 0%, transparent 66%);
  animation: authAuroraB 61s ease-in-out infinite alternate;
}
@keyframes authAuroraA {
  from { transform: translate3d(-4%, -2%, 0) scale(1); opacity: 0.75; }
  to   { transform: translate3d(5%, 4%, 0) scale(1.12); opacity: 1; }
}
@keyframes authAuroraB {
  from { transform: translate3d(3%, 3%, 0) scale(1.08); opacity: 0.65; }
  to   { transform: translate3d(-5%, -3%, 0) scale(1); opacity: 0.95; }
}
/* The canvas sits above both washes. */
.auth-backdrop-field { position: relative; z-index: 1; }
.auth-backdrop-scrim { z-index: 2; }

/* ENTRANCE. Once, on arrival, and then never again — a form that keeps moving
   is a form that is harder to fill in. `backwards` holds the starting state
   during the delay so nothing flashes at full opacity first. */
.auth-shell > *:not(.auth-backdrop) {
  animation: authRise 620ms cubic-bezier(0.16, 0.84, 0.34, 1) backwards;
}
.auth-shell > *:not(.auth-backdrop):nth-child(2) { animation-delay: 40ms; }
.auth-shell > *:not(.auth-backdrop):nth-child(3) { animation-delay: 130ms; }
.auth-shell > *:not(.auth-backdrop):nth-child(4) { animation-delay: 210ms; }
@keyframes authRise {
  from { opacity: 0; transform: translate3d(0, 14px, 0); }
  to   { opacity: 1; transform: none; }
}

/* A PERSON WHO ASKED FOR LESS MOTION GETS A FINISHED STILL SCREEN, not a
   broken one: the washes stay, at their mid position, and nothing moves. */
@media (prefers-reduced-motion: reduce) {
  .auth-backdrop::before,
  .auth-backdrop::after { animation: none; opacity: 0.85; }
  .auth-shell > *:not(.auth-backdrop) { animation: none; }
}

/* RU | EN on the public screens.
   Top-right, above the backdrop, out of the form's way. Two letters and a
   separator: a person who needs it finds it, and a person who does not is not
   asked to read anything. */
.auth-lang {
  position: fixed;
  top: 18px;
  inset-inline-end: 22px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--pk-line-2) 70%, transparent);
  background: color-mix(in srgb, var(--pk-card) 72%, transparent);
  backdrop-filter: blur(6px);
}
.auth-lang-btn {
  border: 0;
  background: none;
  padding: 2px 4px;
  font-size: 12px;
  letter-spacing: 0.08em;
  color: var(--pk-muted);
  cursor: pointer;
  border-radius: 5px;
  line-height: 1.4;
}
.auth-lang-btn:hover { color: var(--pk-text); }
/* The active language is stated, not merely implied by a hover colour: on a
   two-item control the reader has to know which one they are already on. */
.auth-lang-btn.is-on { color: var(--pk-text); font-weight: 600; }
.auth-lang-sep { color: var(--pk-muted); opacity: 0.5; font-size: 12px; }

/* ПЕРЕКЛЮЧАТЕЛЬ ЯЗЫКА ПАДАЛ В ПОТОК И НАКРЫВАЛ БРЕНД.
   Измерено на живой странице входа 2026-08-29: у элемента оказался
   position: relative и left 171 — он перекрывал и «Boardroom / Revenue
   Control OS», и строку «ВХОД В РАБОЧЕЕ ПРОСТРАНСТВО».
   Причина — вес селекторов, а не ошибка в самом .auth-lang. Правило подъёма
   над фоном (.auth-shell > *:not(.auth-backdrop)) весит 0,2,0, а .auth-lang
   всего 0,1,0: position fixed проигрывал, и элемент вставал в поток сразу за
   брендом. Заметно это стало, когда языков стало три и пилюля выросла.
   Общее правило не трогаем — оно намеренно не перечисляет классы. Позиция
   возвращается правилом того же веса, стоящим ниже по файлу. */
.auth-shell > .auth-lang {
  position: fixed;
  z-index: 3;
}

@media (max-width: 760px) {
  /* Clear of the brand mark on a narrow screen, where the two would otherwise
     sit on the same line. */
  .auth-lang { top: 14px; inset-inline-end: 14px; padding: 4px 8px; }
}

/* THE GLOW I FIXED WAS THE ACTIVE ONE. THE ONE THE OWNER KEPT SEEING WAS HOVER.
   styles.css lights BOTH states from a single rule:
     .nav-item:hover, .nav-item.active {
       background: linear-gradient(135deg, rgba(59,130,246,.24), rgba(14,165,233,.08));
       box-shadow: inset 3px 0 0 rgba(56,189,248,.72), 0 12px 30px rgba(2,6,23,.18); }
   The active half was already beaten — `.sidebar .nav-item.active` is three
   classes to its two — so the screen looked right until a cursor crossed the
   rail. Nothing in this file, cabinet-system.css or redesign.css ever answered
   `:hover`, so every sidebar row still carried a blue wash and a 30px drop
   shadow on the way past. That is the "засвет" on Marketing and AI-Accounting:
   not the item you are on, the item you are pointing at.
   Fixed at the same specificity as the active rule, so both states are decided
   in one place instead of one being decided here and the other in a stylesheet
   that declares .sidebar thirteen times. */
.sidebar .nav-item:hover,
.sidebar a[aria-current="page"]:hover {
  /* A hint of the accent, and nothing that reads as light spilling off the
     rail. The active row keeps its inset bar; hover must not out-shout it. */
  background: color-mix(in srgb, var(--pk-accent-soft) 55%, transparent);
  border-color: transparent;
  box-shadow: none;
}
/* Hovering the row you are already on must not change it: two treatments on one
   element is how a rail starts flickering under the cursor. */
.sidebar .nav-item.active:hover {
  background: var(--pk-accent-soft);
  box-shadow: inset 3px 0 0 var(--pk-accent);
}

/* The webhook address a client pastes into the provider's own settings.
   Selectable, wrapping, and visibly a value rather than prose — it is copied by
   hand into another product, so it has to survive being read aloud. */
.idesk-webhook {
  display: inline-block;
  margin-top: 3px;
  padding: 3px 7px;
  border-radius: 6px;
  border: 1px solid var(--pk-line-2);
  background: var(--rp-plate);
  color: var(--pk-text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  line-height: 1.5;
  /* A URL has no spaces, so it must be told it may break anywhere or it will
     push the card wider than the shelf. */
  overflow-wrap: anywhere;
  user-select: all;
}

/* ── the one-button sweep across every live connection ──────────────────────
   Sits in the desk header beside the connection count, because that count is
   the claim it is checking. Ghost-styled rather than primary: it is a question,
   not an action, and nothing on this screen changes when it runs. */
.idesk-sweep-btn { align-self: flex-start; margin-top: 4px; }
.idesk-sweep {
  list-style: none; margin: 8px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 4px;
  width: 100%;
}
.idesk-sweep-line {
  font-size: 12px; line-height: 1.45; color: var(--pk-dim);
  padding-inline-start: 14px; position: relative;
}
/* A mark rather than a colour alone: the failing line has to survive a
   screenshot, a colour-blind reader and a printed page. */
.idesk-sweep-line::before { content: "·"; position: absolute; inset-inline-start: 2px; }
.idesk-sweep-line.is-ok { color: var(--pk-dim); }
.idesk-sweep-line.is-ok::before { content: "✓"; color: var(--pk-green); }
.idesk-sweep-line.is-bad { color: var(--pk-red, #f87171); }
.idesk-sweep-line.is-bad::before { content: "!"; font-weight: 700; }

/* ── START HERE: the order thirty-one cards do not have ─────────────────────
   A numbered path, not a grid, because the whole point is that these four are
   sequential and the catalogue below is not. It disappears once the required
   steps are done — a finished to-do list left on screen is one people learn to
   stop reading, which is how the next unfinished thing gets missed. */
.idesk-path {
  list-style: none; counter-reset: idesk-path; margin: 10px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 8px; width: 100%;
}
.idesk-path-step {
  counter-increment: idesk-path;
  position: relative; padding-block: 8px 8px; padding-inline: 34px 12px;
  border: 1px solid var(--pk-line-2); border-radius: 10px;
  background: rgba(148, 178, 255, 0.04);
  display: flex; flex-direction: column; gap: 2px; align-items: flex-start;
}
.idesk-path-step::before {
  content: counter(idesk-path);
  position: absolute; inset-inline-start: 10px; top: 9px;
  width: 16px; height: 16px; border-radius: 999px;
  display: grid; place-items: center;
  font-size: 10px; font-weight: 700; line-height: 1;
  border: 1px solid var(--pk-line-2); color: var(--pk-dim);
}
.idesk-path-title { font-size: 13px; color: var(--pk-text); }
.idesk-path-why { font-size: 11.5px; line-height: 1.45; color: var(--pk-dim); }
.idesk-path-go { margin-top: 6px; }

/* Done is quiet. It is context for where you are, not an achievement to look
   at — the eye belongs on the step that is still open. */
.idesk-path-step.is-done { opacity: 0.6; }
.idesk-path-step.is-done::before {
  content: "✓"; border-color: rgba(74, 222, 128, 0.34); color: var(--pk-green);
}
/* Exactly one step is ever "next", and it is the only one that looks like it
   wants something. */
.idesk-path-step.is-next {
  border-color: rgba(148, 178, 255, 0.34);
  background: rgba(148, 178, 255, 0.09);
}
.idesk-path-step.is-next::before { border-color: rgba(148, 178, 255, 0.45); color: var(--pk-text); }
/* Optional and not done: present, readable, and visibly not blocking. A client
   with no CRM must not be held at a door they are not meant to walk through. */
.idesk-path-step.is-optional { border-style: dashed; }

/* The stand-in line on a connector that stores a key and nothing more. Dimmer
   than a real `gives`, because it describes an absence — but present, because a
   card with blank space under its name reads as a rendering fault. */
.idesk-gives-quiet { color: var(--pk-dim); font-style: italic; }

/* ПЛИТКА, КОТОРАЯ ВЕДЁТ К СВОИМ СДЕЛКАМ.
   Ссылку получают только те две, под которые заведены точные признаки доски
   (new_24h и stale_14) — см. kpiGo в main.js. Раз плитка кликается, это должно
   быть видно до нажатия, а не выясняться после: курсор, подсветка рамки и
   заметная фокусная рамка для тех, кто ходит с клавиатуры. */
a.rp-kpi-go {
  cursor: pointer;
  text-decoration: none;
  color: inherit;
  transition: border-color 120ms ease, transform 120ms ease;
}
a.rp-kpi-go:hover { border-color: var(--pk-blue-line, #2f7bff); }
a.rp-kpi-go:focus-visible {
  outline: 2px solid var(--pk-blue, #2f7bff);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: no-preference) {
  a.rp-kpi-go:hover { transform: translateY(-1px); }
}

/* «Ждёт ответа клиента» — не тревога, а состояние.
   Отдельный от pk-chat-off цвет намеренно: жёлтый зовёт человека вмешаться,
   а здесь вмешиваться не нужно — Мария вернётся сама, как только клиент
   напишет. Владелец дважды за вечер 31 августа принял такую паузу за поломку,
   потому что обе выглядели одинаково. */
.pk-chat-waitreply {
  color: light-dark(#4a5568, #94a3b8);
  background: rgba(148, 163, 184, .10);
  border-color: rgba(148, 163, 184, .22);
}

/* ЗАМЕТКИ МЕНЕДЖЕРА НА КАРТОЧКЕ.
   Переехали сюда из строки чата 31 августа. Поле намеренно НЕ похоже на поле
   отправки сообщения: другой фон, другая рамка, подпись под ним прямо говорит,
   что клиент этого не увидит. Два поля рядом, выглядящие одинаково, — это то,
   из-за чего заметка однажды уходит клиенту. */
.lw-notes { display: flex; flex-direction: column; gap: 10px; }
.lw-note-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.lw-note {
  /* Логические свойства, а не left/padding-left: на арабском экране
     полоса и отступ обязаны переехать на другую сторону сами. Гейт это
     проверяет — physical left/right он не пропускает. */
  border-inline-start: 2px solid light-dark(#c9d3e0, #2f3b4d);
  padding-block: 2px;
  padding-inline-start: 10px;
}
.lw-note-text { margin: 0; font-size: 13.5px; line-height: 1.5; white-space: pre-wrap; }
.lw-note-meta { margin: 3px 0 0; font-size: 11.5px; opacity: .62; }
/* «Изменить» у заметки (19.09.2026): тихая ссылка в строке автора — не вторая
   кнопка рядом с «Добавить заметку». */
.lw-note-edit { margin-inline-start: 8px; padding: 0; border: 0; background: none; color: var(--accent-cyan, #38bdf8); font: inherit; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.lw-note-edit:hover, .lw-note-edit:focus-visible { opacity: 1; filter: brightness(1.25); }
.lw-note-editing .lw-note-input { width: 100%; box-sizing: border-box; }
.lw-note-input {
  width: 100%; box-sizing: border-box; resize: vertical;
  min-height: 58px; padding: 10px 12px; border-radius: 8px;
  font: inherit; font-size: 14px; line-height: 1.5;
  background: light-dark(#f6f8fb, rgba(255,255,255,.03));
  border: 1px dashed light-dark(#c2cddb, #3a4759);
  color: inherit;
}
.lw-note-actions { display: flex; justify-content: flex-end; }

/* УКАЗАТЕЛЬ НА ЖИВУЮ НАСТРОЙКУ.
   Стоит под предупреждением о черновике и читается как его вторая половина:
   «это черновик — а работает вот здесь». Раньше раздел говорил только первую
   половину, и человек оставался в тупике: понял, что не работает, и не понял,
   где тогда работает. */
.agent-live-pointer {
  margin: -4px 0 18px;
  font-size: 13.5px;
  opacity: .9;
}
.agent-live-pointer a {
  color: light-dark(#1a5fd9, #7aa7ff);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
}
.agent-live-pointer a:hover { opacity: .8; }

/* ШЕСТЬ ДВЕРЕЙ В СВОЕГО АГЕНТА.
   Владелец 31 августа: «как мне моего агента найти? нету что-то». Экран
   назывался «Ваш AI-сотрудник», показывал его цифры и не давал ни одного
   способа его открыть — сразу за цифрами шёл каталог чужих пресетов.
   Плитка крупная намеренно: это точка входа, а не список настроек. */
.agent-home-blocks { margin-top: 22px; }
.agent-home-blocks-lead { margin: 0 0 12px; font-size: 14px; opacity: .78; }
.agent-block-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  gap: 12px;
  min-width: 0;
}
.agent-block {
  display: flex; flex-direction: column; gap: 5px; min-width: 0;
  text-align: start; cursor: pointer;
  padding: 16px 16px 14px;
  border-radius: 12px;
  border: 1px solid light-dark(#dbe3ee, #263041);
  background: light-dark(#fff, rgba(255,255,255,.02));
  color: inherit; font: inherit;
  transition: border-color .15s, transform .15s;
}
.agent-block:hover {
  border-color: light-dark(#1a5fd9, #3d7dff);
  transform: translateY(-1px);
}
.agent-block-ico { font-size: 20px; line-height: 1; }
.agent-block-title { font-size: 16px; font-weight: 600; }
.agent-block-sub { font-size: 13px; opacity: .68; line-height: 1.45; overflow-wrap: anywhere; }

/* ВЕСЬ ПУТЬ МАТЕРИАЛА — ВОСЕМЬ ДВЕРЕЙ ПО ПОРЯДКУ РАБОТЫ.
   Двенадцать разделов медиафабрики жили в узкой колонке слева одним плоским
   списком, где «Бренд-база» и «Подготовка к рекламе» весят одинаково, хотя
   нужны в разные моменты. Порядок плиток — порядок работы, а не алфавит. */
.mf-doors { margin-top: 22px; }
.mf-door-grid {
  display: grid;
  /* min(190px, 100%) — иначе auto-fit создаёт колонки шире контейнера, и
     подписи обрезаются справа: ровно это и случилось на первом выкате. */
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  gap: 12px;
  margin-top: 12px;
  min-width: 0;
}
.mf-door {
  display: flex; flex-direction: column; gap: 5px; min-width: 0;
  text-align: start; cursor: pointer;
  padding: 15px 15px 13px;
  border-radius: 12px;
  border: 1px solid light-dark(#dbe3ee, #263041);
  background: light-dark(#fff, rgba(255,255,255,.02));
  color: inherit; font: inherit;
  transition: border-color .15s, transform .15s;
}
.mf-door:hover {
  border-color: light-dark(#a855f7, #c084fc);
  transform: translateY(-1px);
}
.mf-door-ico { font-size: 19px; line-height: 1; }
.mf-door-title { font-size: 15.5px; font-weight: 600; }
.mf-door-copy { font-size: 12.8px; opacity: .68; line-height: 1.45; overflow-wrap: anywhere; }

/* ЛЕВОЕ МЕНЮ КРУПНЕЕ.
   Владелец 31 августа: «меню слева крупнее». Рельс — то, по чему ходят весь
   день, и он был набран мельче, чем содержимое страниц, к которым ведёт. */
.workspace .nav-item-text {
  font-size: 15.5px;
}
.workspace .nav-section-label {
  font-size: 11.5px;
  letter-spacing: .09em;
}

/* КОНВЕЙЕР ВМЕСТО ЧЕТЫРЁХ ПУСТЫХ ПОЛОС.
   Владелец: «вот тут тоже скучно очень». Полоса, которая никогда не
   заполнится, — это не диаграмма, а место, занятое под диаграмму. Теперь на
   каждом этапе настоящее число, заливка от самого нагруженного этапа и
   переход на экран этого этапа. */
.mf-flow {
  display: grid;
  min-width: 0;
  grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
  gap: 10px;
  margin: 14px 0 10px;
}
.mf-flow-step {
  display: flex; flex-direction: column; gap: 7px;
  text-align: start; cursor: pointer; font: inherit; color: inherit;
  padding: 13px 14px 12px;
  border-radius: 11px;
  border: 1px solid light-dark(#dbe3ee, #263041);
  background: light-dark(#fbfcfe, rgba(255,255,255,.02));
  transition: border-color .15s, transform .15s;
}
.mf-flow-step:hover {
  border-color: light-dark(#a855f7, #c084fc);
  transform: translateY(-1px);
}
.mf-flow-name { font-size: 12.5px; letter-spacing: .05em; text-transform: uppercase; opacity: .66; }
.mf-flow-num { font-size: 26px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.mf-flow-num.is-zero { opacity: .42; }
.mf-flow-num.is-unknown { opacity: .3; font-weight: 500; }
.mf-flow-bar {
  display: block; height: 4px; border-radius: 999px;
  background: light-dark(#e6ebf3, rgba(255,255,255,.06));
  overflow: hidden;
}
.mf-flow-fill {
  display: block; height: 100%; border-radius: 999px;
  /* Обе ветки темы: на светлом фоне фиолетовый берётся насыщеннее, иначе
     заливка сливается с подложкой полосы. */
  background: linear-gradient(90deg, light-dark(#9333ea, #a855f7), light-dark(#6d28d9, #7c3aed));
  min-width: 0;
}
.mf-flow-hint { font-size: 12px; opacity: .6; line-height: 1.4; }

/* ЛЕНТА АКТИВНОСТИ ПО МАТЕРИАЛАМ.
   Панель писала «нет источника» — и это была правда: журнала не существовало.
   Источник нашёлся в самих данных (дата создания, тип, тема, дата решения),
   а с 31 августа решения ещё и пишутся в audit_events. */
/* ИЗМЕРЕНО, А НЕ УГАДАНО: список выходил 451px, а строка внутри — 40px.
   В колоночном flex-контейнере дети растягиваются по ширине только при
   align-items: stretch; где-то выше по каскаду он был переопределён, и строка
   сжималась по содержимому. Отсюда и колонка «Rev / en / ue»: сжатую строку
   overflow-wrap: anywhere ломал на каждой букве. */
.mf-act-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 9px; align-items: stretch; }
.mf-act { display: flex; gap: 10px; align-items: flex-start; width: 100%; }
.mf-act-dot {
  width: 7px; height: 7px; border-radius: 50%; flex: none; margin-top: 6px;
}
.mf-act-new { background: light-dark(#7c3aed, #a855f7); }
.mf-act-yes { background: light-dark(#059669, #3ecf8e); }
.mf-act-no  { background: light-dark(#dc2626, #f26a6a); }
/* flex: 1 обязателен. Без него тело строки сжимается по содержимому, а
   overflow-wrap: anywhere разрешает ломать слово на каждой букве — лента
   выстроилась колонкой по одному символу. Ширину надо не только разрешить
   занять (min-width: 0), но и потребовать. */
.mf-act-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.mf-act-what { font-size: 13.5px; line-height: 1.4; overflow-wrap: anywhere; }
.mf-act-meta { font-size: 11.5px; opacity: .58; }

/* ЕДИНЫЙ БЛОК ДВЕРЕЙ — src/pages/shared/sectionDoors.js.
   Владелец 1 сентября: привести остальные экраны к тому же порядку, что у
   кабинета агента и медиафабрики; «разнеси смежное, объедини, дай места,
   убери слипшиеся мелкие названия».
   Размеры совпадают с уже выкаченными плитками агента и медиафабрики
   намеренно: единый контур держится одинаковыми числами, а не похожестью. */
.bd-doors { margin: 24px 0 6px; }
.bd-doors-title { margin: 0 0 4px; font-size: 19px; font-weight: 600; letter-spacing: -.01em; }
.bd-doors-lead { margin: 0 0 14px; font-size: 14px; opacity: .72; max-width: 70ch; }
.bd-door-grid {
  display: grid;
  /* min(...) обязателен: без него auto-fit строит колонки шире контейнера и
     подписи обрезаются справа — уже случалось на медиафабрике. */
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
  gap: 12px;
  min-width: 0;
}
.bd-door {
  display: flex; flex-direction: column; gap: 5px; min-width: 0;
  text-align: start; cursor: pointer;
  padding: 16px 16px 14px;
  border-radius: 12px;
  border: 1px solid light-dark(#dbe3ee, #263041);
  background: light-dark(#fff, rgba(255,255,255,.02));
  color: inherit; font: inherit;
  transition: border-color .15s, transform .15s;
}
.bd-door:hover {
  border-color: light-dark(#1a5fd9, #3d7dff);
  transform: translateY(-1px);
}
.bd-door-ico { font-size: 20px; line-height: 1; }
.bd-door-title { font-size: 16px; font-weight: 600; }
.bd-door-sub { font-size: 13px; opacity: .68; line-height: 1.45; overflow-wrap: anywhere; }
.bd-door-state {
  margin-top: 6px; align-self: flex-start;
  font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px; border: 1px solid transparent;
}
.bd-state-live  { color: light-dark(#047857, #3ecf8e); background: rgba(62,207,142,.12); border-color: rgba(62,207,142,.28); }
.bd-state-draft { color: light-dark(#92400e, #e8b155); background: rgba(232,177,85,.10); border-color: rgba(232,177,85,.26); }
.bd-state-off   { color: light-dark(#475569, #94a3b8); background: rgba(148,163,184,.10); border-color: rgba(148,163,184,.22); }

/* ПЛИТКА — ЭТО BUTTON, А КНОПКАМ В ЭТОМ ПРОДУКТЕ НАВЯЗАНЫ nowrap И hidden.
   Измерено в браузере: у .bd-door computed white-space: nowrap,
   overflow: hidden, ширина 248px при scrollWidth 342 — подпись обрезалась
   ровно по краю плитки, без переноса и без многоточия.
   Три предыдущие правки (min() в колонках, min-width: 0, overflow-wrap)
   были верными и лечили другие причины; эта — настоящая.
   Правило идёт последним намеренно: оно должно перебить глобальное. */
.bd-door,
.bd-door-title,
.bd-door-sub,
.agent-block,
.agent-block-title,
.agent-block-sub,
.mf-door,
.mf-door-title,
.mf-door-copy,
.mf-flow-step,
.mf-flow-hint {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}


/* ТЕНЬ ТОЛЬКО В СВЕТЛОЙ ТЕМЕ.
   Белая карточка на светлом фоне не может стать светлее фона — единственное,
   что её приподнимает, это тень. В тёмной теме она не нужна и не ставится:
   там карточка уже светлее того, на чём лежит. Значения мягкие намеренно —
   владелец просил «чуть темнее», а не выпуклые плитки. */
:root[data-theme="light"] .control-card,
:root[data-theme="light"] .rp-kpi,
:root[data-theme="light"] .metric-card,
:root[data-theme="light"] .detail-card,
:root[data-theme="light"] .roster-card,
:root[data-theme="light"] .agl-card {
  box-shadow: 0 1px 2px rgba(15, 32, 74, .07), 0 10px 26px rgba(15, 32, 74, .06);
}
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] .control-card,
  :root[data-theme="system"] .rp-kpi,
  :root[data-theme="system"] .metric-card,
  :root[data-theme="system"] .detail-card,
  :root[data-theme="system"] .roster-card,
  :root[data-theme="system"] .agl-card {
    box-shadow: 0 1px 2px rgba(15, 32, 74, .07), 0 10px 26px rgba(15, 32, 74, .06);
  }
}

/* ЖУРНАЛ ОШИБОК.
   Строки читаются сверху вниз одним потоком, а не таблицей: у записи разная
   длина — объяснение, что делать, техническая строка, — и колонки заставили бы
   каждую строку быть высотой с самую длинную. Разобранные записи не исчезают,
   а гаснут: список, из которого пропадает то, что ты только что нажал, теряет
   место, где ты читал. */
.elg { display: flex; flex-direction: column; gap: 14px; }
.elg-top { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; justify-content: space-between; }
.elg-top h2 { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -.02em; color: var(--rp-ink); }
.elg-sub { margin: 3px 0 0; font-size: 14px; color: var(--rp-ink-2); }
.elg-filters { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }
.elg-chip {
  height: 32px; padding: 0 13px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--rp-line); background: transparent;
  color: var(--rp-ink-2); font: inherit; font-size: 13px;
}
.elg-chip.on { background: rgb(var(--ch-blue) / .14); border-color: rgb(var(--ch-blue) / .42); color: var(--rp-ink); }
.elg-count { margin: 0; font-size: 14px; color: var(--rp-ink-2); }
.elg-bad { margin: 0; font-size: 14px; color: var(--pk-amber, #d69a5c); }
.elg-empty { margin: 8px 0 0; font-size: 14px; color: var(--rp-ink-2); line-height: 1.55; }
.elg-list { display: flex; flex-direction: column; gap: 10px; }
.elg-row {
  border: 1px solid var(--rp-line); border-radius: 13px; padding: 15px 16px;
  background: var(--rp-panel); display: flex; flex-direction: column; gap: 6px;
}
.elg-row.is-done { opacity: .55; }
.elg-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 9px; }
.elg-head h3 { margin: 0; font-size: 15.5px; font-weight: 620; color: var(--rp-ink); }
.elg-sev {
  padding: 3px 9px; border-radius: 999px; font-size: 11px; font-weight: 600;
  letter-spacing: .02em; white-space: nowrap;
}
.elg-sev-error { background: rgb(var(--ch-late) / .16); color: var(--lw-late-2); }
.elg-sev-warn { background: rgb(var(--ch-amber) / .16); color: var(--lw-warm); }
/* «Случилось 26 раз» — это не украшение счётчика. Одинаковые отказы схлопнуты
   в одну строку, и без этого числа один сломанный канал читается как одна
   мелкая неприятность. */
.elg-times { font-size: 12.5px; color: var(--lw-warm); font-variant-numeric: tabular-nums; }
.elg-when { margin-inline-start: auto; font-size: 12.5px; color: var(--rp-ink-3); white-space: nowrap; }
.elg-what { margin: 0; font-size: 14px; line-height: 1.55; color: var(--rp-ink-2); }
.elg-raw { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }
.elg-todo { margin: 0; font-size: 14px; line-height: 1.55; color: var(--rp-ink); }
.elg-tech {
  margin: 2px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--rp-ink-3);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; word-break: break-word;
}
.elg-actions { display: flex; gap: 8px; align-items: center; margin-top: 2px; }
.elg-done-mark { font-size: 12.5px; color: var(--lw-ok); }

/* ИСТОРИЯ ПЕРЕПИСКИ.
   Строка — это ПАРА «вопрос → ответ», а не сообщение. Вопрос и ответ стоят
   друг под другом с разными фонами: таблицей в две колонки они читались бы
   только при одинаковой длине, а её не бывает. */
.hst { display: flex; flex-direction: column; gap: 14px; }
.hst-top { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-end; justify-content: space-between; }
.hst-top h2 { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -.02em; color: var(--rp-ink); }
.hst-sub { margin: 3px 0 0; font-size: 14px; color: var(--rp-ink-2); }
.hst-search { display: flex; gap: 8px; align-items: center; flex: 1 1 320px; max-width: 560px; }
.hst-search .bc-input { flex: 1 1 auto; min-width: 0; }
.hst-filters { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }
.hst-gap { flex: 0 0 14px; }
.hst-chip {
  height: 32px; padding: 0 13px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--rp-line); background: transparent;
  color: var(--rp-ink-2); font: inherit; font-size: 13px;
}
.hst-chip.on { background: rgb(var(--ch-blue) / .14); border-color: rgb(var(--ch-blue) / .42); color: var(--rp-ink); }
.hst-count { margin: 0; font-size: 14px; color: var(--rp-ink-2); }
.hst-bad { margin: 0; font-size: 14px; color: var(--pk-amber, #d69a5c); }
.hst-empty { margin: 8px 0 0; font-size: 14px; color: var(--rp-ink-2); line-height: 1.55; }
.hst-list { display: flex; flex-direction: column; gap: 10px; }
.hst-row {
  border: 1px solid var(--rp-line); border-radius: 13px; padding: 13px 15px;
  background: var(--rp-panel); display: flex; flex-direction: column; gap: 8px;
}
.hst-meta { display: flex; flex-wrap: wrap; gap: 10px; align-items: baseline; font-size: 12.5px; color: var(--rp-ink-3); }
.hst-chan { padding: 2px 8px; border-radius: 999px; background: rgb(var(--ch-lift) / .07); }
.hst-who { font-variant-numeric: tabular-nums; }
.hst-pair { display: flex; flex-direction: column; gap: 6px; }
.hst-q, .hst-a { margin: 0; font-size: 14px; line-height: 1.55; border-radius: 10px; padding: 9px 11px; }
.hst-q { background: rgb(var(--ch-lift) / .06); color: var(--rp-ink); }
.hst-a { background: rgb(var(--ch-blue) / .09); color: var(--rp-ink-2); }
/* «На это никто не ответил» — самая важная строка на экране, и она обязана
   выглядеть как тревога, а не как пустая ячейка. */
.hst-a.hst-none { background: rgb(var(--ch-late) / .13); color: var(--lw-late-2); font-style: italic; }
.hst-by { margin: 0; font-size: 12px; color: var(--rp-ink-3); }
.hst-more { display: flex; justify-content: center; padding: 4px 0 8px; }

/* АНАЛИТИКА АГЕНТА.
   Плитки в один ряд, первой — «спросили и не получили ответа»: это
   единственное число на экране, которое требует действия сегодня, и стоять
   вторым оно не может. */
.ana { display: flex; flex-direction: column; gap: 14px; }
.ana-top { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-end; justify-content: space-between; }
.ana-top h2 { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -.02em; color: var(--rp-ink); }
.ana-sub { margin: 3px 0 0; font-size: 14px; color: var(--rp-ink-2); }
.ana-filters { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }
.ana-chip {
  height: 32px; padding: 0 13px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--rp-line); background: transparent;
  color: var(--rp-ink-2); font: inherit; font-size: 13px;
}
.ana-chip.on { background: rgb(var(--ch-blue) / .14); border-color: rgb(var(--ch-blue) / .42); color: var(--rp-ink); }
.ana-bad { margin: 0; font-size: 14px; color: var(--pk-amber, #d69a5c); }
.ana-count, .ana-empty { margin: 0; font-size: 14px; color: var(--rp-ink-2); }
.ana-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 10px; }
.ana-tile {
  border: 1px solid var(--rp-line); border-radius: 13px; padding: 14px 16px;
  background: var(--rp-panel); display: flex; flex-direction: column; gap: 3px; min-width: 0;
}
.ana-tile b { font-size: 27px; font-weight: 700; letter-spacing: -.025em; color: var(--rp-ink); font-variant-numeric: tabular-nums; }
.ana-tile-label { font-size: 12.5px; color: var(--rp-ink-2); }
.ana-tile-note { font-size: 12px; color: var(--rp-ink-3); line-height: 1.45; }
/* Тревожная плитка отличается краем и цветом числа, а не фоном: заливка сделала
   бы её плакатом, и рядом с ней остальные читались бы как выключенные. */
.ana-alarm { border-color: rgb(var(--ch-late) / .55); }
.ana-alarm b { color: var(--lw-late-2); }
.ana-ok b { color: var(--lw-ok); }
.ana-card {
  border: 1px solid var(--rp-line); border-radius: 13px; padding: 15px 16px;
  background: var(--rp-panel); display: flex; flex-direction: column; gap: 10px;
}
.ana-card h3 { margin: 0; font-size: 15.5px; font-weight: 620; color: var(--rp-ink); }
.ana-note { margin: 0; font-size: 12.5px; line-height: 1.5; color: var(--rp-ink-3); }
.ana-legend { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 12px; color: var(--rp-ink-3); }
.ana-key { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
.ana-key-in { background: rgb(var(--ch-blue) / .55); margin-inline-start: 4px; }
.ana-key-ag { background: rgb(var(--ch-ok) / .6); margin-inline-start: 10px; }
/* Столбики, а не линия: линия между днями обещает, что между ними что-то
   происходило, а каждый день здесь — отдельное число. */
.ana-bars { display: flex; align-items: flex-end; gap: 3px; height: 132px; overflow-x: auto; padding-bottom: 2px; }
.ana-bar { flex: 1 0 8px; min-width: 8px; height: 100%; display: flex; align-items: flex-end; gap: 2px; }
.ana-bar span { flex: 1 1 0; border-radius: 3px 3px 0 0; min-height: 2px; }
.ana-bar-in { background: rgb(var(--ch-blue) / .55); }
.ana-bar-ag { background: rgb(var(--ch-ok) / .6); }
.ana-scale { margin: 0; font-size: 11.5px; color: var(--rp-ink-3); font-variant-numeric: tabular-nums; }
.ana-rows { display: flex; flex-direction: column; gap: 7px; }
.ana-row { display: grid; grid-template-columns: minmax(120px, 1fr) auto minmax(0, 1.4fr); gap: 10px; align-items: baseline; }
.ana-row-name { font-size: 14px; color: var(--rp-ink); }
.ana-row-num { font-size: 15px; font-weight: 640; color: var(--rp-ink); font-variant-numeric: tabular-nums; }
.ana-row-note { font-size: 12px; color: var(--rp-ink-3); line-height: 1.45; }
.ana-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2px; }

/* ПРАВИЛА, ПО КОТОРЫМ ЧТО-ТО НЕ УХОДИТ (рассылка) И КОГДА ЗВОНИТ АГЕНТ.
   Карточки, а не список абзацев: каждое правило — отдельный ответ на отдельный
   вопрос, и слипшись в текст они перестают читаться ровно тогда, когда нужны —
   когда человек ищет глазами, почему ушло меньше, чем в списке. */
.rule-list { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; margin-top: 10px; }
.rule-card {
  border: 1px solid var(--rp-line); border-radius: 12px; padding: 13px 15px;
  background: var(--rp-panel-2); display: flex; flex-direction: column; gap: 5px; min-width: 0;
}
.rule-card b { font-size: 14px; font-weight: 620; color: var(--rp-ink); }
.rule-card p { margin: 0; font-size: 13px; line-height: 1.55; color: var(--rp-ink-2); }
/* Собственные слова провайдера в журнале. Не курсив и не цитата: это не мнение,
   а ответ машины, и он должен читаться как факт — но тише объяснения. */
.elg-said {
  margin: 0; font-size: 12.5px; line-height: 1.5; color: var(--rp-ink-2);
  padding: 7px 10px; border-radius: 9px; background: rgb(var(--ch-lift) / .06);
  border-inline-start: 2px solid rgb(var(--ch-line) / .35);
}
/* «Затихло» — запись, которой больше двух суток. Гаснет, но не прячется: она
   всё ещё была, и её ещё можно разобрать. Красная метка «Сбой» на недельной
   строке — ровно то, что отправило чинить уже починенный Gmail. */
.elg-row.is-quiet { opacity: .72; }
.elg-sev-quiet { background: rgb(var(--ch-lift) / .10); color: var(--rp-ink-3); }

/* ── THE DIALOGUE SITS CLOSE TO THE CARD (2026-09-04, evening) ──────────────
   Owner: «влево наполовину придвинь, прям близко — маленький промежуток между
   левым блоком и вторым». The page gap is for cards in a grid; two halves of
   one working screen read as one thing with a hairline of air between them. */
.lw-page.has-card { column-gap: 6px; }

/* ── FUNNEL CARD: «NO TASKS» DOT AND MONEY FIRST (2026-09-05, amoCRM spec) ──
   Owner, 4 Sep: an orange dot on the card when nothing is planned for the
   lead, and the budget as the first data line of the card. Both are facts
   the board already had and did not show. */
.pk-lead-next.is-none { color: var(--pk-dim); }
.pk-lead-next.is-none .pk-lead-next-ic { color: #f0b64d; font-size: 10px; }
.pk-lead-money { margin-top: 4px; font-size: 12.5px; font-weight: 600; color: var(--pk-text); font-variant-numeric: tabular-nums; }

/* Свои поля на карточке доски (2026-09-07): одна строка, «Врач: Ахмедов ·
   Бюджет: 3 000», обрезается многоточием; полный текст — в title. */
.pk-lead-cf { margin-top: 3px; font-size: 11.5px; line-height: 1.25; color: var(--pk-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pk-lead-cf-k { color: var(--pk-faint); }
.pk-lead-cf-v { color: var(--pk-text); }

/* Фильтр по своим полям в ящике (2026-09-07): имя поля, чипы операций,
   значение(я). Поля ввода — того же роста, что чипы. */
.pk-cf-row { padding: 6px 0; border-top: 1px dashed rgba(148, 178, 255, 0.10); }
.pk-cf-row:first-child { border-top: 0; padding-top: 0; }
.pk-cf-row.is-on .pk-cf-name { color: var(--pk-text); }
.pk-cf-name { margin-bottom: 4px; font-size: 12px; font-weight: 600; color: var(--pk-faint); }
.pk-cf-ops { margin-bottom: 4px; }
.pk-cf-inputs { display: flex; gap: 6px; }
.pk-cf-in { min-height: 0; height: 28px; width: 96px; padding: 0 8px; border-radius: 8px; font: inherit; font-size: 12px;
  border: 1px solid rgba(148, 178, 255, 0.18); background: rgba(148, 178, 255, 0.06); color: var(--pk-text); }
.pk-cf-in-wide { width: 100%; }
.pk-cf-values { margin-top: 2px; }

/* ── PRINT THE CARD (2026-09-05): chrome off, content on — lives here, not in lead-workspace.css, which must not restyle the shared composer (test-crm-lead-workspace) ──────────────────── */
@media print {
  .app-shell .rail, .app-shell nav, .rp-topbar, .lw-card-head, .lw-panel-hide, .lw-menu-btn, .lw-menu,
  .ck-composer, .lw-panel-show, .lw-grip, .lw-feed-bar, .boro-mascot { display: none !important; }
  .lw-page { display: block !important; }
  .lw-card, .lw-main { box-shadow: none !important; border: 0 !important; overflow: visible !important; }
  .lw-scroll { overflow: visible !important; max-height: none !important; }
}

/* ── API AND MCP CARDS (2026-09-05) ──────────────────────────────────────────── */
.idesk-form .idesk-form-row { display: flex; gap: 8px; align-items: center; margin: 8px 0; }
.idesk-form .idesk-form-row .idesk-input { flex: 1 1 auto; min-width: 0; }
.idesk-form .idesk-list { list-style: none; margin: 8px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.idesk-form .idesk-list li { display: flex; justify-content: space-between; align-items: center; gap: 10px; font-size: 12.5px; color: var(--pk-text); }
.idesk-form .idesk-list li span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.idesk-diagnostic summary { cursor: pointer; color: var(--pk-dim); font-size: 12px; }
.idesk-state-module { color: var(--pk-muted); border-color: var(--pk-line); }
.idesk-installed-toggle {
  display: inline-flex; align-items: center; height: 28px; padding: 0 12px; margin: 0 0 8px;
  border-radius: 999px; border: 1px solid var(--pk-line); background: none; color: var(--pk-muted); font: inherit; font-size: 12.5px; cursor: pointer;
}
.idesk-installed-toggle.is-on { border-color: var(--pk-blue-line); color: var(--pk-text); background: rgba(47, 123, 255, 0.10); }

/* ── THE COMPOSER PANEL, BIGGER AND LAID OUT INSIDE (2026-09-05, morning) ───
   Owner: «попробуй больше само табло сделать и внутри как-то распредели,
   потому что опять некрасиво». The edge trick (buttons hanging half under the
   frame) is undone: one panel with more room, the text area IS the panel's
   inside — no second box inside the box — and the action row sits inside the
   frame, «+» on the left, «Отправить» on the right. Loaded last, so it
   outranks composer-kit's layers without touching their anchors. */
.workspace .ck-composer, .ck-composer {
  overflow: visible; padding: 8px 12px 8px; margin: 0 8px 10px;
  row-gap: 6px; column-gap: 10px; border-radius: 14px;
}
.ck-composer > .ck-tools, .ck-composer > .ck-row > .ck-send-col { margin-bottom: 0; }
.ck-composer .ck-more-btn, .ck-composer .ck-send { box-shadow: none; }
/* 30% lower on the owner's next look («чуть поменьше поле, 30%», same
   morning): 88 → 62px. Everything still sits inside the one frame. */
.workspace .ck-composer .ck-input, .ck-composer .ck-input {
  height: 62px; min-height: 62px; max-height: 320px;
  padding: 4px 4px; border: 0; border-radius: 0; background: transparent; box-shadow: none;
}
.ck-composer .ck-send { min-height: 0; height: 30px; line-height: 30px; padding: 0 22px; border-radius: 9px; font-size: 13px; }
.ck-composer .ck-more-btn { min-height: 0; height: 30px; width: 36px; border-radius: 9px; font-size: 16px; }

/* ── SALES ANALYTICS (2026-09-05): three reports on one quiet page ───────────
   Period chips, four tiles, then cards. Bars are plain divs so the page needs
   no library; the funnel bar is width in percent of the widest stage. Tokens
   only — no hard-coded dark backgrounds (theme-tokens). */
.an-page { display: flex; flex-direction: column; gap: 14px; }
.an-bar { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; }
.an-chips { display: flex; gap: 6px; }
.an-chip {
  min-height: 0; height: 30px; padding: 0 12px; border-radius: 999px; font: inherit; font-size: 12.5px; cursor: pointer;
  border: 1px solid rgb(var(--ch-line) / .35); background: rgb(var(--ch-lift) / .05); color: var(--pk-text);
}
.an-chip.is-on { border-color: rgb(var(--ch-accent) / .7); background: rgb(var(--ch-blue) / .18); font-weight: 600; }
.an-dates { display: flex; align-items: center; gap: 6px; }
.an-date { min-height: 0; height: 30px; padding: 0 8px; border-radius: 8px; font: inherit; font-size: 12.5px; border: 1px solid rgb(var(--ch-line) / .35); background: rgb(var(--ch-lift) / .05); color: var(--pk-text); }
.an-dash { color: var(--pk-dim); }
.an-range { margin-inline-start: auto; font-size: 12px; color: var(--pk-dim); font-variant-numeric: tabular-nums; }
.an-error { padding: 10px 12px; border-radius: 10px; border: 1px solid rgb(var(--ch-red) / .45); color: var(--pk-text); }
.an-retry, .an-link { min-height: 0; padding: 0 4px; border: 0; background: none; color: rgb(var(--ch-accent)); font: inherit; cursor: pointer; text-decoration: underline; }
.an-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
.an-tile { padding: 12px 14px; border-radius: 12px; border: 1px solid rgb(var(--ch-line) / .28); background: rgb(var(--ch-lift) / .04); }
.an-tile-label { font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: var(--pk-dim); }
.an-tile-value { margin-top: 4px; font-size: 24px; font-weight: 700; font-variant-numeric: tabular-nums; }
.an-tile-sub { margin-top: 2px; font-size: 12px; color: var(--pk-dim); }
.an-card { padding: 14px 16px; border-radius: 14px; border: 1px solid rgb(var(--ch-line) / .28); background: rgb(var(--ch-lift) / .03); }
.an-h { margin: 0; font-size: 15px; font-weight: 700; }
.an-sub { margin: 2px 0 10px; font-size: 12.5px; color: var(--pk-dim); }
.an-empty, .an-foot { font-size: 12.5px; color: var(--pk-dim); }
.an-funnel { display: flex; flex-direction: column; gap: 6px; }
.an-frow { display: grid; grid-template-columns: minmax(120px, 1.2fr) minmax(0, 3fr) 48px 52px 64px 96px; align-items: center; gap: 10px; font-size: 13px; }
.an-fname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.an-fbar { height: 14px; border-radius: 7px; background: rgb(var(--ch-lift) / .08); overflow: hidden; }
.an-ffill { height: 100%; border-radius: 7px; background: rgb(var(--ch-accent) / .75); }
.an-frow.is-won .an-ffill { background: rgb(var(--ch-ok) / .8); }
.an-frow.is-lost .an-ffill { background: rgb(var(--ch-red) / .6); }
.an-fnum, .an-fpct, .an-fstep, .an-fnow { font-variant-numeric: tabular-nums; text-align: end; }
.an-fnum { font-weight: 600; }
.an-fpct, .an-fstep, .an-fnow { color: var(--pk-dim); font-size: 12px; }
.an-table-wrap { overflow-x: auto; }
.an-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.an-table th, .an-table td { padding: 6px 8px; border-bottom: 1px solid rgb(var(--ch-line) / .18); text-align: start; }
.an-table th { font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: var(--pk-dim); font-weight: 600; }
.an-table .an-num { text-align: end; font-variant-numeric: tabular-nums; }
.an-table .is-bad { color: rgb(var(--ch-red)); font-weight: 600; }
.an-table-quiet { margin-top: 12px; }
.an-days { display: flex; align-items: flex-end; gap: 3px; height: 72px; }
.an-day { flex: 1 1 0; display: flex; align-items: flex-end; min-width: 3px; height: 100%; }
.an-daybar { width: 100%; border-radius: 3px 3px 0 0; background: rgb(var(--ch-accent) / .6); }
@media (max-width: 900px) {
  .an-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .an-frow { grid-template-columns: minmax(90px, 1fr) minmax(0, 2fr) 40px 48px; }
  .an-fstep, .an-fnow { display: none; }
}

/* ── /agents IN THREE BLOCKS (2026-09-05, owner): my agents · library · preset market ─
   One page, three stacked sections with a jump strip on top. The old two tabs
   hid the library behind a click and the live agent behind another. */
.agl-blocks { display: flex; flex-direction: column; gap: 18px; }
.agl-jumps { position: sticky; top: 0; z-index: 2; padding: 6px 0; background: var(--pk-bg, transparent); }
.agl-block { scroll-margin-top: 56px; padding: 14px 16px 16px; border-radius: 14px; border: 1px solid rgb(var(--ch-line) / .28); background: rgb(var(--ch-lift) / .03); }
.agl-block-head { margin-bottom: 10px; }
.agl-block-title { margin: 0; font-size: 16px; font-weight: 700; }
.agl-block-sub { margin: 3px 0 0; font-size: 12.5px; color: var(--pk-dim); max-width: 70ch; }
.agl-mine-none { display: flex; flex-direction: column; gap: 6px; }

/* ── SETTINGS SUB-PAGES (2026-09-05): profile and notifications ─────────────
   Reuse the analytics card tokens; two small rows of their own. */
.settings-profile-page .set13 { margin: 0; }
.settings-toggle-row { display: flex; align-items: center; gap: 8px; font-size: 13.5px; cursor: pointer; }
.settings-notify-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; font-size: 13px; }
.settings-notify-state { color: var(--pk-dim); }

/* Response-speed tones on the analytics page (same benchmark as the card). */
.an-tone-good { color: rgb(var(--ch-ok)); }
.an-tone-warn { color: rgb(var(--ch-amber)); }
.an-tone-bad { color: rgb(var(--ch-red)); }

/* Revenue by week: a small bar per week with the amount under it. */
.an-weeks { display: flex; align-items: flex-end; gap: 10px; overflow-x: auto; padding-bottom: 4px; }
.an-week { display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 64px; }
.an-weekbar { width: 34px; height: 72px; display: flex; align-items: flex-end; border-radius: 6px; background: rgb(var(--ch-lift) / .08); overflow: hidden; }
.an-weekfill { width: 100%; background: rgb(var(--ch-ok) / .75); border-radius: 6px 6px 0 0; }
.an-weeklabel { font-size: 11px; color: var(--pk-dim); font-variant-numeric: tabular-nums; }
.an-weekvalue { font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.an-weekn { font-size: 11px; color: var(--pk-dim); }

/* Шаблон возврата после 24 часов — по языкам (5 сентября). */
.chatpane-template-slot { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
.chatpane-template-lang { min-width: 84px; font-size: 12px; opacity: 0.8; }
.chatpane-template-slot .agent-assist-input { flex: 1; min-width: 0; }

/* Кампании Meta плитками (владелец, 5 сентября: «квадратики с компаниями и показателями»). */
.mk-camp-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 12px; }
.mk-camp-tile { border: 1px solid var(--pk-line, rgba(255, 255, 255, 0.1)); border-radius: 14px; padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; background: rgba(255, 255, 255, 0.02); }
.mk-camp-tile-head { display: flex; gap: 6px; flex-wrap: wrap; }
.mk-camp-tile-name { margin: 0; font-size: 13.5px; line-height: 1.3; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.mk-camp-tile-grid { margin: 0; display: grid; grid-template-columns: 1fr auto; gap: 3px 10px; font-size: 12.5px; }
.mk-camp-tile-grid dt { color: var(--pk-muted, #8b96a8); }
.mk-camp-tile-grid dd { margin: 0; text-align: end; font-variant-numeric: tabular-nums; }
.mk-camp-tile > .ghost-button { align-self: flex-start; }

/* Валюта и средний чек в настройке воронки (владелец, 5 сентября). */
.crm-setup-dv { margin-top: 6px; }
.crm-setup-dvrow { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 10px; }
.crm-dv-label { font-size: 12px; color: var(--bd-ink-3); }
.crm-dv-select { width: auto; min-width: 90px; }
.crm-dv-amount { width: 120px; }
.crm-dv-usd { color: var(--bd-ink-3); font-size: 12px; }
.crm-dv-check { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; margin-inline-start: auto; }

/* Скорость ответа в аналитике агента (6 сентября). */
.ana-speed { margin-top: 18px; }
.ana-speed-days { margin-top: 12px; overflow-x: auto; }
.ana-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.ana-table th, .ana-table td { text-align: left; padding: 6px 8px; border-bottom: 1px solid rgb(var(--ch-line) / .14); white-space: nowrap; }
.ana-table th { color: var(--bd-ink-3); font-weight: 500; font-size: 12px; }
.ana-bad-cell { color: var(--rp-red, #ff7b7b); font-weight: 600; }

/* «Задачи» — вложенный пункт CRM, а не отдельный продукт (владелец, 6 сентября:
   «слева у нас продукты»). Значок остаётся ради свёрнутой рейки; в развёрнутой —
   отступ и тише текст, как у ИИ-бухгалтерии под Интеграциями. */
.nav-list .nav-item[href="/crm/tasks"] { padding-inline-start: 26px; }
.nav-list .nav-item[href="/crm/tasks"] .nav-icon { transform: scale(.85); }

/* СВЕТЛАЯ ТЕМА, ПЕРВЫЙ ПРОХОД ПО QUEUE_LIGHT_THEME.md: рёбра и тени, не тон.
   Диагноз 18 августа: карточки сливались в один лист, потому что край при
   rgba(15,32,74,.20) невидим, а теней нет. Здесь — только светлая ветвь: край
   плотнее, у карточных семейств появляется тень. Тёмная тема не тронута ни
   байтом: блок стоит под [data-theme="light"] и системной светлой схемой. */
:root[data-theme="light"] {
  --bd-line: rgb(var(--ch-line) / 0.34);
  --bd-line-2: rgb(var(--ch-line) / 0.52);
  --rp-line: rgba(15, 32, 74, 0.30);
  --light-card-shadow: 0 1px 2px rgba(15, 32, 74, 0.06), 0 8px 24px rgba(15, 32, 74, 0.08);
}
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] {
    --bd-line: rgb(var(--ch-line) / 0.34);
    --bd-line-2: rgb(var(--ch-line) / 0.52);
    --rp-line: rgba(15, 32, 74, 0.30);
    --light-card-shadow: 0 1px 2px rgba(15, 32, 74, 0.06), 0 8px 24px rgba(15, 32, 74, 0.08);
  }
}
:root[data-theme="light"] .metric-card, :root[data-theme="light"] .kb-card, :root[data-theme="light"] .control-card,
:root[data-theme="light"] .an-card, :root[data-theme="light"] .ana-tile, :root[data-theme="light"] .lw-section,
:root[data-theme="light"] .revenue-kpi-card, :root[data-theme="light"] .readiness-card, :root[data-theme="light"] .tsk-meet,
:root[data-theme="light"] .mk-camp-tile, :root[data-theme="light"] .an-tile {
  box-shadow: var(--light-card-shadow);
}
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] .metric-card, :root[data-theme="system"] .kb-card, :root[data-theme="system"] .control-card,
  :root[data-theme="system"] .an-card, :root[data-theme="system"] .ana-tile, :root[data-theme="system"] .lw-section,
  :root[data-theme="system"] .revenue-kpi-card, :root[data-theme="system"] .readiness-card, :root[data-theme="system"] .tsk-meet,
  :root[data-theme="system"] .mk-camp-tile, :root[data-theme="system"] .an-tile {
    box-shadow: var(--light-card-shadow);
  }
}
/* Карточки Обзора и доски носят свои имена: rp-kpi, xo-card, drawer-block. Им —
   тот же край и та же тень; край rgba(15,32,74,.20) был тем самым невидимым. */
:root[data-theme="light"] .rp-kpi, :root[data-theme="light"] .xo-card, :root[data-theme="light"] .drawer-block,
:root[data-theme="light"] .rp-card, :root[data-theme="light"] .chatpane-card {
  border-color: var(--rp-line);
  box-shadow: var(--light-card-shadow);
}
@media (prefers-color-scheme: light) {
  :root[data-theme="system"] .rp-kpi, :root[data-theme="system"] .xo-card, :root[data-theme="system"] .drawer-block,
  :root[data-theme="system"] .rp-card, :root[data-theme="system"] .chatpane-card {
    border-color: var(--rp-line);
    box-shadow: var(--light-card-shadow);
  }
}
.tsk-refreshed { font-size: 12px; color: var(--bd-ink-3); margin-inline-start: 8px; }

/* Автономия Марии (6 сентября): режим и галочки. */
.set-autonomy { display: grid; gap: 8px; margin: 6px 0 4px; }
.set-auto-mode { display: inline-flex; align-items: center; gap: 6px; margin-inline-end: 18px; font-size: 14px; cursor: pointer; }
.set-auto-list { display: grid; gap: 6px; margin-top: 4px; }
.set-auto-row { display: grid; grid-template-columns: 18px 1fr; column-gap: 10px; align-items: start; padding: 8px 10px; border: 1px solid var(--bd-line); border-radius: 10px; cursor: pointer; }
.set-auto-row input { margin-top: 3px; }
.set-auto-text { font-size: 14px; color: var(--bd-ink); }
.set-auto-hint { grid-column: 2; font-size: 12px; color: var(--bd-ink-3); }
/* Скрипт следующих шагов (Мария-задачи v2, 12 сентября). */
.set-auto-script { display: grid; gap: 6px; margin-top: 4px; }
.set-auto-script textarea { width: 100%; box-sizing: border-box; font: inherit; font-size: 13px; padding: 8px 10px; border-radius: 10px; border: 1px solid var(--bd-line); background: transparent; color: var(--bd-ink); resize: vertical; }

/* Структура базы знаний по правилам (6 сентября). */
.kb-structure { display: grid; gap: 6px; margin: 4px 0 14px; }
.kb-structure-row { display: grid; grid-template-columns: 22px 1fr auto; gap: 10px; align-items: center; padding: 8px 10px; border: 1px solid var(--bd-line); border-radius: 10px; }
.kb-structure-row.is-have { opacity: .85; }
.kb-structure-mark { font-weight: 700; color: var(--bd-ink-3); }
.kb-structure-row.is-have .kb-structure-mark { color: var(--lw-ok, #78dcaa); }
.kb-structure-body { display: grid; gap: 2px; min-width: 0; }
.kb-structure-hint { font-size: 12px; color: var(--bd-ink-3); }
/* Чек-лист приёмки в тестовом чате. */
.agent-acceptance { margin: 8px 0 10px; padding: 8px 12px; border: 1px solid var(--bd-line); border-radius: 12px; }
.agent-acceptance > summary { cursor: pointer; font-weight: 600; font-size: 14px; }
.agent-acceptance-list { display: grid; gap: 6px; margin: 8px 0 0; padding-inline-start: 0; list-style: none; }
.agent-acceptance-row { display: grid; grid-template-columns: auto 1fr; gap: 10px; align-items: start; padding: 6px 8px; border-radius: 10px; }
.agent-acceptance-row.is-pass { background: rgb(var(--ch-ok, 120 220 170) / .08); }
.agent-acceptance-row.is-fail { background: rgb(var(--ch-late, 224 138 106) / .10); }
.agent-acceptance-body { display: grid; gap: 2px; min-width: 0; }
.agent-acceptance-msg { font-size: 13px; color: var(--bd-ink-2, var(--bd-ink)); }
.agent-acceptance-judge, .agent-acceptance-verdict { font-size: 12px; color: var(--bd-ink-3); }
.agent-acceptance-verdict { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 2px; }
.agent-acceptance-verdict .ok { color: var(--lw-ok, #78dcaa); }
.agent-acceptance-verdict .bad { color: var(--lw-late, #e0785c); }

/* ── Boardroom AI Academy (/academy), 6 September 2026 ─────────────────── */
.academy-page .help-center-lede { max-width: 72ch; }
.academy-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; margin-top: 10px; }
.academy-tile { border: 1px solid var(--bd-line, rgba(255,255,255,0.08)); border-radius: 12px; padding: 14px; display: flex; flex-direction: column; gap: 6px; }
.academy-tile-featured { border-color: var(--bd-accent, #4950bc); box-shadow: 0 0 0 1px var(--bd-accent, #4950bc) inset; }
.academy-tile strong { font-size: 16px; }
.academy-days { margin: 10px 0 0; padding-inline-start: 20px; display: grid; gap: 6px; }
.academy-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }

/* Событие, которое сделкой ещё не стало: пометка и «с кем это было».
   Не красное — ничего не сломалось, просто карточки пока нет. */
.ws-journal-unattached {
  display: inline-block;
  padding: 1px 6px;
  border: 1px solid var(--pk-line, rgba(255,255,255,.14));
  border-radius: 999px;
  font-size: 11px;
  color: var(--pk-muted);
  white-space: nowrap;
}

.ws-journal-who { color: var(--pk-muted); font-size: 12px; }

/* Открытая карточка коннектора подводится под шапку, а не вплотную к ней:
   scrollIntoView({block:"start"}) ставит верх карточки в верх окна, и под
   липкой шапкой её первая строка оказывалась перекрыта. */
.idesk-card { scroll-margin-top: 72px; }

/* НАСТРОЙКИ ВИДЖЕТА С ПРЕВЬЮ (11 сентября 2026): поля слева, настоящий виджет
   в песочнице справа; на узком экране — одно под другим. */
.idesk-widget-editor { gap: 10px; }
.idesk-widget-h { margin: 4px 0 0; font-size: 15px; }
.idesk-widget-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 380px); gap: 18px; align-items: start; }
.idesk-widget-fields { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.idesk-widget-preview-box { position: sticky; top: 80px; }
.idesk-widget-preview { width: 100%; height: 580px; border: 1px solid var(--pk-line, rgba(148,163,184,.25)); border-radius: 14px; background: light-dark(#dfe6ef, #1b2433); }
.idesk-check { flex-direction: row; align-items: center; gap: 8px; font-size: 14px; cursor: pointer; }
.idesk-check input { width: 17px; height: 17px; }
.idesk-color { width: 64px; height: 34px; padding: 2px; border-radius: 8px; border: 1px solid var(--pk-line, rgba(148,163,184,.25)); background: transparent; cursor: pointer; }
@media (max-width: 900px) {
  .idesk-widget-grid { grid-template-columns: 1fr; }
  .idesk-widget-preview-box { position: static; }
}

/* «ВХОДЯЩИЕ · N» (12 сентября 2026) — ручной приём новых входящих перед первым
   этапом, как Incoming leads у Kommo. Колонка — не этап: пунктирная рамка и
   синяя полоса вместо цвета позиции, чтобы её не читали как ещё одну стадию.
   На неё нельзя бросить карточку — у неё нет onDrop. Длинные свойства, не
   сокращение `border`: общая рамка этапа (прозрачная, её красят .is-won /
   .is-lost) остаётся той же — меняются только стиль и цвет у этой колонки. */
.pk-col.pk-col-incoming { border-style: dashed; border-color: var(--pk-blue-line); background-color: var(--pk-blue-soft); }
.pk-inbox-rule { background: var(--pk-blue); }
.pk-inbox-card {
  border: 1px solid var(--pk-line-2);
  border-radius: 11px;
  background: var(--pk-card);
  padding: 12px 13px 11px;
  display: grid;
  gap: 7px;
}
.pk-inbox-card.is-busy { opacity: 0.6; }
.pk-inbox-open {
  display: grid; gap: 2px; min-width: 0;
  padding: 0; border: 0; background: none; color: inherit; text-align: start; cursor: pointer;
}
.pk-inbox-who {
  font-size: 14px; font-weight: 600; color: var(--pk-text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pk-inbox-title {
  font-size: 12.5px; color: var(--pk-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pk-inbox-open:hover .pk-inbox-who { text-decoration: underline; }
.pk-inbox-meta { margin: 0; font-size: 12px; color: var(--pk-dim); display: flex; flex-wrap: wrap; gap: 6px; }
.pk-inbox-waiting { color: var(--pk-amber); }
.pk-inbox-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.pk-inbox-btn {
  flex: 1 1 auto;
  min-height: 30px; padding: 4px 10px;
  border: 1px solid var(--pk-line-2); border-radius: 8px;
  background: none; color: var(--pk-text); font-size: 12.5px; cursor: pointer;
}
.pk-inbox-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.pk-inbox-btn.is-accept { background: var(--pk-blue); border-color: var(--pk-blue); color: var(--rp-on-accent, #fff); }
.pk-inbox-btn.is-decline:hover:not(:disabled), .pk-inbox-btn.is-spam:hover:not(:disabled) { border-color: var(--pk-high); }
.pk-inbox-btn.is-quiet { flex: 0 0 auto; color: var(--pk-muted); }
.pk-inbox-said { margin: 0; font-size: 12.5px; color: var(--pk-muted); }

/* ═══ MEDIA FACTORY · MENU WITH WHAT IT DOES (13 Sep 2026) ═══════════════════
   Owner: «сейчас мелкие названия, навигации мало, надо описание дать, что куда
   нажимать и что будет». Each rail row is now an icon, a 14.5px name and one
   line saying what pressing it does; a state chip only where the state is
   actually known. Tokens only — no new colours, light and dark both follow
   from --pk-* via light-dark(). */
.media-workspace-nav {
  max-height: calc(100vh - 120px);
  overflow-y: auto !important;
  scrollbar-width: thin;
}
.media-workspace-nav .mw-nav-label { font-size: 10.5px; letter-spacing: 0.1em; color: var(--pk-dim); }
.media-workspace-nav button.mw-nav-item {
  display: grid !important;
  grid-template-columns: 26px minmax(0, 1fr);
  align-items: start; gap: 10px;
  width: 100%; min-height: 0;
  padding: 9px 10px !important;
  border: 0 !important; border-radius: 10px !important;
  background: none; text-align: start; white-space: normal;
  color: var(--pk-text);
  font-size: 14.5px !important; line-height: 1.3;
}
.media-workspace-nav button.mw-nav-item + button.mw-nav-item { margin-top: 2px; }
.media-workspace-nav button.mw-nav-item:hover { background: var(--pk-card) !important; }
.mw-nav-ico {
  display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: 8px;
  background: var(--pk-card); font-size: 14px; line-height: 1;
}
.mw-nav-text { display: grid; gap: 3px; min-width: 0; }
.mw-nav-title {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-weight: 560; color: var(--pk-text);
}
.mw-nav-desc { font-size: 12.5px; line-height: 1.4; color: var(--pk-muted); font-weight: 400; }
.media-workspace-nav button.mw-nav-item.active .mw-nav-ico,
.media-workspace-nav button.mw-nav-item[aria-current="page"] .mw-nav-ico { background: var(--pk-accent-soft); }
.media-workspace-nav button.mw-nav-item.active .mw-nav-title,
.media-workspace-nav button.mw-nav-item[aria-current="page"] .mw-nav-title { color: var(--pk-accent-ink); }

/* One chip shape for every honest state on the module. */
.mf-state-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 600; line-height: 1.5; white-space: nowrap;
  border: 1px solid var(--pk-line-2); color: var(--pk-muted); background: none;
}
.mf-state-chip::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.mf-state-chip.is-live { color: var(--pk-green); border-color: color-mix(in srgb, var(--pk-green) 40%, transparent); background: color-mix(in srgb, var(--pk-green) 10%, transparent); }
.mf-state-chip.is-partial,
.mf-state-chip.is-warn,
.mf-state-chip.is-needs_setup { color: var(--pk-amber); border-color: color-mix(in srgb, var(--pk-amber) 40%, transparent); background: color-mix(in srgb, var(--pk-amber) 10%, transparent); }
.mf-state-chip.is-draft { color: var(--pk-accent-ink); border-color: var(--pk-line-2); background: var(--pk-accent-soft); }
.mf-state-chip.is-hidden { display: none; }

/* «Как это работает» — four steps across the top of every Media Factory screen. */
.mf-howto {
  border: 1px solid var(--pk-line); border-radius: 14px;
  background: var(--pk-panel); padding: 14px 16px 12px;
}
.mf-howto-head { margin: 0 0 10px; font-size: 13px; font-weight: 600; color: var(--pk-text); }
.mf-howto-steps {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px;
}
.mf-howto-step {
  display: grid; grid-template-columns: 26px minmax(0, 1fr); grid-template-rows: auto auto;
  column-gap: 10px; row-gap: 2px; align-items: center;
  width: 100%; height: 100%; padding: 10px 12px;
  border: 1px solid var(--pk-line); border-radius: 11px;
  background: var(--pk-card); color: var(--pk-text); text-align: start; cursor: pointer;
  white-space: normal;
}
.mf-howto-step:hover { border-color: var(--pk-line-2); }
.mf-howto-step.is-here { border-color: var(--pk-accent); box-shadow: inset 0 0 0 1px var(--pk-accent); }
.mf-howto-n {
  grid-row: 1 / span 2; display: grid; place-items: center;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--pk-accent-soft); color: var(--pk-accent-ink);
  font-size: 13px; font-weight: 700;
}
.mf-howto-t { font-size: 14px; font-weight: 600; }
.mf-howto-d { font-size: 12.5px; color: var(--pk-muted); line-height: 1.35; }
.mf-howto-note { margin: 10px 0 0; font-size: 12.5px; color: var(--pk-muted); line-height: 1.5; }

/* Order screen: production state and the estimate, both before the press. */
.mf-prod-state {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 6px 10px; align-items: start;
  margin: 12px 0 4px; padding: 12px 14px;
  border: 1px solid var(--pk-line-2); border-radius: 12px; background: var(--pk-card);
}
.mf-prod-state.is-hidden { display: none; }
.mf-prod-state.is-needs_setup, .mf-prod-state.is-partial { border-color: color-mix(in srgb, var(--pk-amber) 45%, transparent); }
.mf-prod-text { font-size: 13.5px; line-height: 1.5; color: var(--pk-text); }
.mf-prod-locks-head { grid-column: 1 / -1; margin: 4px 0 0; font-size: 12px; color: var(--pk-dim); }
.mf-prod-locks { grid-column: 1 / -1; margin: 0; padding-inline-start: 18px; font-size: 12.5px; color: var(--pk-muted); line-height: 1.6; }
.mf-estimate {
  margin: 14px 0 4px; padding: 12px 14px;
  border: 1px dashed var(--pk-line-2); border-radius: 12px;
}
.mf-estimate-t { margin: 0 0 4px; font-size: 12.5px; font-weight: 600; color: var(--pk-text); }
.mf-estimate-l { margin: 2px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--pk-muted); }
.cs-brand-line { margin-top: 10px; }

.mf-approvals-wrap { display: grid; gap: 12px; }
.mf-approvals-note { margin: 0; font-size: 13.5px; color: var(--pk-muted); }

/* «В рекламу» — the campaign draft. Form left, check + final step right. */
.mf-adb-headrow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.mf-adb-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
  gap: 18px; margin-top: 16px; align-items: start;
}
.mf-adb-form { display: grid; gap: 14px; min-width: 0; }
.mf-adb-step {
  margin: 0; padding: 14px 16px 16px; min-width: 0;
  border: 1px solid var(--pk-line); border-radius: 12px; background: var(--pk-card);
  display: grid; gap: 10px;
}
.mf-adb-step > legend {
  display: flex; align-items: center; gap: 8px; padding: 0 4px;
  font-size: 14.5px; font-weight: 600; color: var(--pk-text);
}
.mf-adb-n {
  display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  background: var(--pk-accent-soft); color: var(--pk-accent-ink); font-size: 12px; font-weight: 700;
}
.mf-adb-assets { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
.mf-adb-asset {
  display: grid; gap: 6px; padding: 8px; text-align: start; cursor: pointer;
  border: 1px solid var(--pk-line); border-radius: 10px; background: var(--pk-panel); color: var(--pk-text);
}
.mf-adb-asset.is-on { border-color: var(--pk-accent); box-shadow: inset 0 0 0 1px var(--pk-accent); }
.mf-adb-thumb {
  display: grid; place-items: center; aspect-ratio: 4 / 5; border-radius: 8px;
  background: var(--pk-card) center / cover no-repeat; color: var(--pk-muted); font-size: 18px;
}
.mf-adb-thumb.is-empty { font-size: 12px; }
/* ПЛИТКА РОЛИКА — ЭТО ЕГО ПЕРВЫЙ КАДР. Видео лежит в той же клетке сетки, что
   и треугольник поверх него, поэтому и обрезается по той же рамке, и не
   двигает соседей. `pointer-events: none` — чтобы нажатие выбирало материал,
   а не проваливалось в плеер. */
.mf-adb-thumb.is-video { position: relative; overflow: hidden; background: var(--pk-card); }
.mf-adb-thumb-v {
  grid-area: 1 / 1; width: 100%; height: 100%; object-fit: cover;
  border-radius: 8px; pointer-events: none; background: var(--pk-card);
}
.mf-adb-thumb-play {
  grid-area: 1 / 1; place-self: center; pointer-events: none;
  font-size: 18px; color: #fff; text-shadow: 0 1px 6px rgba(0, 0, 0, 0.75);
}
.mf-adb-asset-name { font-size: 13px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mf-adb-asset-kind { font-size: 12px; color: var(--pk-muted); }
.mf-adb-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.mf-adb-chip {
  padding: 6px 12px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--pk-line-2); background: none; color: var(--pk-text); font-size: 13px;
}
.mf-adb-chip.is-on { background: var(--pk-accent-soft); border-color: var(--pk-accent); color: var(--pk-accent-ink); font-weight: 600; }
.mf-adb-field { display: grid; gap: 5px; min-width: 0; }
.mf-adb-label { font-size: 12.5px; font-weight: 600; color: var(--pk-muted); }
.mf-adb-field input, .mf-adb-field textarea {
  width: 100%; min-width: 0; padding: 9px 11px; border-radius: 9px;
  border: 1px solid var(--pk-line-2); background: var(--pk-panel); color: var(--pk-text); font: inherit; font-size: 14px;
}
.mf-adb-field textarea { resize: vertical; line-height: 1.5; }
.mf-adb-hint { margin: 0; font-size: 12.5px; color: var(--pk-muted); line-height: 1.5; }
.mf-adb-count { justify-self: end; font-size: 12px; color: var(--pk-dim); font-variant-numeric: tabular-nums; }
.mf-adb-count.is-long { color: var(--pk-amber); }
.mf-adb-warn { margin: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 12.5px; color: var(--pk-amber); }
.mf-adb-row2 { display: grid; grid-template-columns: repeat(2, minmax(0, 140px)); gap: 10px; }
.mf-adb-row3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.mf-adb-total { margin: 0; font-size: 13.5px; color: var(--pk-text); font-variant-numeric: tabular-nums; }
.mf-adb-total.is-over { color: var(--pk-high); }
.mf-adb-side { display: grid; gap: 12px; position: sticky; top: 0; min-width: 0; }
.mf-adb-card {
  padding: 14px 16px; border: 1px solid var(--pk-line); border-radius: 12px; background: var(--pk-card);
  display: grid; gap: 10px; min-width: 0;
}
.mf-adb-card h4 { margin: 0; font-size: 14px; font-weight: 600; color: var(--pk-text); }
.mf-adb-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.mf-adb-issues, .mf-adb-blockers { margin: 0; padding: 0; list-style: none; display: grid; gap: 6px; }
.mf-adb-issue, .mf-adb-blockers li {
  position: relative; padding-inline-start: 16px; font-size: 12.5px; line-height: 1.45; color: var(--pk-muted);
}
.mf-adb-issue::before, .mf-adb-blockers li::before {
  content: ""; position: absolute; inset-inline-start: 0; top: 6px; width: 7px; height: 7px; border-radius: 50%;
  background: var(--pk-dim);
}
.mf-adb-issue.is-block { color: var(--pk-text); }
.mf-adb-issue.is-block::before { background: var(--pk-high); }
.mf-adb-issue.is-warn::before { background: var(--pk-amber); }
.mf-adb-issue.is-ok::before { background: var(--pk-green); }
.mf-adb-blockers li::before { background: var(--pk-amber); }
.mf-adb-publish { width: 100%; }
.mf-adb-publish:disabled { opacity: 0.55; cursor: not-allowed; }
.mf-adb-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.mf-adb-preview-card > summary { cursor: pointer; font-size: 13.5px; font-weight: 600; color: var(--pk-text); }
.mf-adb-preview {
  margin: 0; max-height: 360px; overflow: auto; padding: 10px 12px; border-radius: 9px;
  background: var(--pk-panel); border: 1px solid var(--pk-line);
  font-size: 11.5px; line-height: 1.5; color: var(--pk-muted); white-space: pre;
}

@media (max-width: 1180px) {
  .mf-howto-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mf-adb-grid { grid-template-columns: minmax(0, 1fr); }
  .mf-adb-side { position: static; }
}
@media (max-width: 900px) {
  .media-workspace-body { grid-template-columns: minmax(0, 1fr); }
  .media-workspace-nav { position: static; max-height: none; }
  .mf-adb-row3 { grid-template-columns: minmax(0, 1fr); }
}

/* ═══ МЕНЮ СЛЕВА: БЛОКИ ПО СМЫСЛУ, КРУПНЫЕ ИКОНКИ В ПЛАШКАХ ЦВЕТА БЛОКА ═══════
   Владелец, 13 сентября 2026: «иконки чуть больше, как-то интереснее, и раздели
   логично по блоками — блоки разные, ясность внести визуально». Блоки задаёт
   NAV_SECTIONS в main.js (overview · sales · money · ai · system); здесь у
   каждого блока один свой цвет, и он виден трижды: метка у подписи блока,
   плашка под иконкой и полоса у пункта, на котором стоишь. Раньше иконка была
   голой линией 19 px без плашки (redesign.css, «NO ICON PLATE»), и десять
   пунктов читались одним столбиком. */
.sidebar .nav-section { --nav-block: light-dark(#41526c, #9fb0c8); }
.sidebar .nav-section-overview { --nav-block: light-dark(#0e7490, #38d1ee); }
.sidebar .nav-section-sales { --nav-block: light-dark(#1a5fd9, #6aa6ff); }
.sidebar .nav-section-money { --nav-block: light-dark(#0f7a4a, #3ddc97); }
.sidebar .nav-section-ai { --nav-block: light-dark(#6d3fd4, #b196ff); }
.sidebar .nav-section-system { --nav-block: light-dark(#475569, #9fb0c8); }

.sidebar .nav-section + .nav-section {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid rgb(var(--ch-line) / .14);
}
.sidebar .nav-section-label {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-block: 0 6px;
  margin-inline: 10px 0;
  font-size: 10.5px;
  letter-spacing: .09em;
  color: color-mix(in srgb, var(--nav-block) 70%, var(--rp-nav-label));
}
.sidebar .nav-section-label::before {
  content: "";
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  background: var(--nav-block);
}

.sidebar .nav-item {
  min-height: 40px;
  gap: 11px;
  padding: 0 8px;
  font-size: 13.5px;
}
.sidebar .nav-item .nav-icon {
  display: grid;
  place-items: center;
  flex: 0 0 30px;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  border: 1px solid color-mix(in srgb, var(--nav-block) 24%, transparent);
  background: color-mix(in srgb, var(--nav-block) 15%, transparent);
  color: var(--nav-block);
  opacity: 1;
}
.sidebar .nav-item .nav-icon[class*="nav-icon-"]::before { width: 18px; height: 18px; }
/* «Задачи» были уменьшены до 85 % как подпункт CRM; в плашке они — полноправный
   пункт блока. */
.sidebar .nav-list .nav-item[href="/crm/tasks"] .nav-icon { transform: none; }

.sidebar .nav-item:hover {
  background: color-mix(in srgb, var(--nav-block) 8%, transparent);
  box-shadow: none;
}
.sidebar .nav-item:hover .nav-icon {
  background: color-mix(in srgb, var(--nav-block) 24%, transparent);
}
/* Пункт, на котором стоишь: полоса и подложка цвета блока, плашка залита. */
.sidebar .nav-item.active,
.sidebar a[aria-current="page"],
.sidebar .nav-item.active:hover {
  background: color-mix(in srgb, var(--nav-block) 15%, transparent);
  border-color: transparent;
  box-shadow: inset 3px 0 0 var(--nav-block);
  color: var(--rp-ink-max);
}
.sidebar .nav-item.active .nav-icon,
.sidebar a[aria-current="page"] .nav-icon {
  background: var(--nav-block);
  border-color: transparent;
  color: light-dark(#ffffff, #0b1016);
}

/* Свёрнутое меню (72 px): плашки остаются, блоки разделены той же линией. */
.rail-collapsed .sidebar .nav-item,
.sidebar.rail-collapsed .nav-item { min-height: 40px; }
/* В свёрнутом меню подписи блоков не помещаются («КЛИЕНТ И ПРОДАЖ») — там
   блоки разделяет линия, а цвет блока остаётся на плашках. */
.rail-collapsed .sidebar .nav-section-label { display: none; }
/* «Операции» стояли в меню с пустой плашкой — значка у ключа operations не
   было никогда. Маршрут между отделами: два блока, связь и стрелка. */
.nav-icon-operations {
  --nav-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='3.5' width='7' height='5.5' rx='1.4'/%3E%3Crect x='13.5' y='15' width='7' height='5.5' rx='1.4'/%3E%3Ccircle cx='17' cy='6.25' r='2.4'/%3E%3Cpath d='M10.5 6.25h4.1'/%3E%3Cpath d='M7 9v5.3a1.5 1.5 0 0 0 1.5 1.5h4.5'/%3E%3Cpath d='M11.4 13.9l1.9 1.9-1.9 1.9'/%3E%3C/svg%3E");
}
/* Подпись блока — в одну строку: «КЛИЕНТЫ И ПРОДАЖИ» переносилась. */
.sidebar .nav-section-label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding-inline-end: 0;
  letter-spacing: .07em;
}
/* «Задачи» — полноправный пункт блока «Клиенты и продажи», без отступа
   подпункта: сдвинутая плашка ломала ровный столбик иконок. */
.sidebar .nav-list .nav-item[href="/crm/tasks"] { padding-inline-start: 8px; }

/* ЛЕВОЕ МЕНЮ НЕ ПРОКРУЧИВАЛОСЬ (владелец, 13 сентября 2026: «левая часть вниз,
   где виджеты и названия, вниз не спускается»). Колонка — ровно высота окна
   (flex column, overflow visible), содержимое — 1025 px при окне 920: низ —
   карточка пространства, строка подключений, «Свернуть» — уходил за край.
   Теперь прокручивается только список пунктов, а низ колонки всегда на месте. */
.sidebar .nav-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: rgb(var(--ch-line) / .35) transparent;
}
.sidebar .nav-list::-webkit-scrollbar { width: 6px; }
.sidebar .nav-list::-webkit-scrollbar-thumb { background: rgb(var(--ch-line) / .35); border-radius: 3px; }
.sidebar .nav-item { min-height: 38px; }
.sidebar .nav-section + .nav-section { margin-top: 8px; padding-top: 8px; }

/* СТРОКА ИНСТРУМЕНТОВ CRM — В ОДНУ СТРОКУ (владелец, 13 сентября 2026: «такая
   большая кнопка „Новый лид“ забирает целую широкую строку»). На ширине 1536
   (экран 1920 при масштабе 125 %) последняя кнопка переносилась одна на вторую
   строку. Кнопка встала за поиском (CrmPipelinePage.js), все кнопки строки —
   одной высоты, «🔥 Сначала горячие» уже 1800 px — один значок с подсказкой,
   поиск сжимается первым. */
.workspace .pk-bar { flex-wrap: nowrap; }
.workspace .pk-bar .crm-search { flex: 1 1 220px; min-width: 150px; }
.workspace .pk-bar .pk-ctl,
.workspace .pk-bar .pk-new,
.workspace .pk-bar .crm-more > button {
  height: 32px;
  min-height: 32px;
}
.workspace .pk-bar .pk-new {
  flex: 0 0 auto;
  padding: 0 12px;
  font-size: 13px;
  box-shadow: none;
  white-space: nowrap;
}
.workspace .pk-bar .pk-ctl { white-space: nowrap; }
@media (max-width: 1799px) {
  .workspace .pk-bar .pk-score-sort { padding: 0 9px; }
  .workspace .pk-bar .pk-score-sort-text { display: none; }
}
/* Совсем узко (планшет) — перенос разрешён, иначе строка вылезла бы за экран. */
@media (max-width: 1100px) {
  .workspace .pk-bar { flex-wrap: wrap; }
}
/* ОТКРЫТЫ ФИЛЬТРЫ — центр уже на 380 px, и строка в одну линию вылезала за
   него: «Automate» ложилась поверх заголовка «Filters» (владелец, 13 сентября
   2026, скриншот). Пока панель открыта, кнопки переносятся. */
.workspace .pk-page.has-drawer .pk-bar { flex-wrap: wrap; }
/* И прокрутка. С открытыми фильтрами страница высотой в экран и обрезает
   доску (11 сентября, раздел выше), поэтому список сделок одной стадии
   нельзя было докрутить, пока не нажмёшь «Применить». Теперь центр в этом
   состоянии — сам себе рельс: строка инструментов прилипает к его верху
   (.pk-centre > .pk-bar уже sticky), карточки не выходят за его край. */
.page-stack.crm-page > .pk-page.has-drawer > .pk-centre { overflow-y: auto; overscroll-behavior: contain; }

/* «РАБОЧЕЕ ПРОСТРАНСТВО»: РАЗДЕЛЫ — ПОЛОСОЙ ВКЛАДОК (13 сентября 2026).
   Страница брала класс бокового меню Медиафабрики; когда тому дали прокрутку
   и предел высоты, здесь оно сжалось в полоску 30 px со стрелками прокрутки
   (владелец: «по центру артефакт»). Обзор · Команда · Безопасность · Журнал
   событий — горизонтально, по размеру содержимого. */
.media-workspace-nav.ws-sections-nav {
  display: flex !important;
  flex-wrap: wrap;
  gap: 6px;
  position: static;
  max-height: none;
  overflow: visible !important;
  padding: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: none !important;
}
.media-workspace-nav.ws-sections-nav button {
  display: inline-flex;
  align-items: center;
  width: auto;
  min-height: 32px;
  padding: 0 14px !important;
  border: 1px solid var(--pk-line) !important;
  border-radius: 999px !important;
  font-size: 13px !important;
  white-space: nowrap;
}

/* ОКНО BORO — МАЛЕНЬКОЕ И БОЛЬШОЕ (владелец, 13 сентября 2026: «маленькая и
   большая всё ещё не идеально выглядит»). В маленьком переписке оставалось
   106 px из 429, «Ассистент…» обрезался, а в большом между сообщением и
   кнопками-подсказками стояла пустота. */
/* Переписка прижата к низу, как в мессенджере: сообщение стоит прямо над
   кнопками, пустое место уходит наверх. margin-top:auto у первого, а не
   justify-content:flex-end — иначе верх длинной переписки нельзя прокрутить. */
.boro-messages > :first-child { margin-top: auto; }
/* Маленькое окно: пояснение «Поможет разобраться…» уже сказано в шапке
   («Ассистент по выручке · помощник») — прячем, место отдаём переписке. */
.boro-panel:not(.boro-panel-wide) .boro-head-note { display: none; }
.boro-panel:not(.boro-panel-wide) .boro-boundary { -webkit-line-clamp: 1; padding-bottom: 9px; }
/* «ТЕКСТ ВНИЗУ ЗА РАМКОЙ» (владелец, 19.09.2026, и в малом, и в большом окне).
   -webkit-line-clamp здесь перебивается (вычисляется display: flow-root — та же
   история, что в «Источниках данных»), подпись росла на 3–4 строки, а с
   зелёной плашкой голоса сумма блоков превышала высоту окна. Теперь: одна
   строка с многоточием без line-clamp (полный текст в title), переписка может
   сжиматься, и пока идёт голосовой разговор, подпись уходит. */
.boro-panel .boro-boundary {
  display: block !important; flex: 0 0 auto;
  white-space: nowrap; overflow: hidden !important; text-overflow: ellipsis;
}
.boro-panel .boro-messages { min-height: 56px; flex: 1 1 auto; }
.boro-panel .boro-composer,
.boro-panel .boro-panel-head,
.boro-panel .boro-voice-hint { flex-shrink: 0; }
.boro-panel:has(.boro-voice-hint:not([style*="none"])) .boro-boundary { display: none !important; }
.boro-panel:not(.boro-panel-wide) .boro-panel-head { gap: 7px; padding: 10px 12px; }
.boro-panel:not(.boro-panel-wide) .boro-panel-head-avatar { width: 32px; height: 32px; flex: 0 0 32px; }
/* «История» — значком: текстом кнопка забирала 60 px, и названию оставалось 41. */
.boro-panel:not(.boro-panel-wide) .boro-sessions-toggle {
  font-size: 0;
  width: 28px;
  min-width: 28px;
  padding: 0;
}
.boro-panel:not(.boro-panel-wide) .boro-sessions-toggle::before { content: "🕘"; font-size: 13px; }
.boro-panel-head-main { min-width: 0; flex: 1 1 auto; }
.boro-panel:not(.boro-panel-wide) .boro-panel-head-main > * { max-width: 100%; }
/* Маленькое окно: ещё ~30 px переписке — поджаты «Мой день», подсказки и
   поле ввода (отступы, не размеры кнопок и не шрифт). */
.boro-panel:not(.boro-panel-wide) .boro-day-head { padding-block: 7px; }
.boro-panel:not(.boro-panel-wide) .boro-suggestions { padding-block: 6px; }
.boro-panel:not(.boro-panel-wide) .boro-composer { padding: 8px 12px; gap: 6px; }
.boro-panel:not(.boro-panel-wide) .boro-composer input,
.boro-panel:not(.boro-panel-wide) .boro-composer .boro-send { height: 36px; min-height: 36px; }

/* «📅 Часы для встреч» в «⚙️ Как работает» → «⏱ Антиспам и часы» (13 сентября
   2026): день недели, галочка, до двух промежутков «с – до». */
.bh-wrap { margin-top: 14px; padding: 12px 14px; border: 1px solid var(--pk-line); border-radius: 12px; }
.bh-title { margin: 0 0 4px; font-size: 14px; }
.bh-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 4px 0; }
.bh-row input[type="checkbox"] { width: 16px; height: 16px; margin: 0; }
.bh-day { min-width: 32px; font-weight: 600; font-size: 13px; }
.bh-row .bh-time { width: 112px; min-height: 32px; padding: 0 8px; }
.bh-row .bh-time:disabled { opacity: .45; }
.bh-sep { color: var(--pk-dim); font-size: 12.5px; }

/* СВЁРНУТОЕ МЕНЮ: НИЗ БЕЗ ПУСТОЙ РАМКИ И ОБРЕЗКОВ (владелец, 13 сентября 2026,
   скриншот карточки лида). Правило «слова уходят» (cabinet-system.css) прятало
   у кнопки пространства каждый span — и кружок с буквой тоже, оставалась пустая
   рамка 56x50. Кружок возвращается; у статуса платформы остаётся точка цвета
   состояния, слова — в подсказке (title), вместо «All …». */
.app-shell.rail-collapsed .sidebar-workspace-button > span.sidebar-account-avatar { display: grid; }
.app-shell.rail-collapsed .rail-health { justify-content: center; padding-inline: 0; }
.app-shell.rail-collapsed .rail-health .rail-health-text { display: none; }
.app-shell.rail-collapsed .rail-health .rail-health-dot { font-size: 12px; }

/* РАЗБОР ЗВОНКА: ОБЕ ВКЛАДКИ НАРИСОВАНЫ, ВИДНА ОДНА (13 сентября 2026).
   Переключение «Итог и оценка» / «Транскрипт» больше не перерисовывает весь
   экран (LeadWorkspacePage.js, showCallPaneTab) — оно только прячет вторую. */
.lw-callpane .lw-callpane-scroll.is-idle { display: none; }

/* НИЗ МЕНЮ — ПОД ПУНКТЫ, А НЕ ПОД ДУБЛИ (владелец, 13 сентября 2026).
   Карточка «Boardroom Digital… · Владелец» повторяла меню справа сверху (там
   же «Рабочее пространство»), строка «Проверяем / Все системы» — зелёную
   «AI-агенты: Активны» и «Интеграции» в самом меню. Обе уходят из бокового
   меню; карточка остаётся в DOM скрытой — её название читают другие экраны
   (.sidebar-workspace-button .brand-copy strong). Место — пунктам меню. */
.sidebar .sidebar-workspace-button,
.sidebar .rail-health { display: none !important; }
/* Свёрнутое меню: «Задачи» стояли на 8 px правее остальных значков (отступ
   из развёрнутого вида), и у списка появлялась горизонтальная прокрутка. */
.app-shell.rail-collapsed .sidebar .nav-list .nav-item[href="/crm/tasks"] { padding-inline-start: 0; }
.sidebar .nav-list { overflow-x: hidden; }
.kb-fineprint { font-size: 12px; line-height: 1.45; color: var(--pk-dim, #8a94a8); margin: 6px 0 4px; max-width: 76ch; }
.team-bulk { margin-top: 12px; }
.team-bulk > summary { cursor: pointer; font-weight: 600; font-size: 13.5px; color: var(--pk-text, inherit); }
.team-bulk[open] { display: grid; gap: 8px; }
.team-bulk-area { width: 100%; min-height: 96px; resize: vertical; font-family: inherit; }
.team-bulk .compact-button { justify-self: start; }

/* ДАТЫ В ФИЛЬТРАХ БУХГАЛТЕРИИ — ВРОВЕНЬ С ПОИСКОМ (владелец, 14 сентября
   2026: «даты чуть криво нарисованы»). Поле поиска рядом ~46 px высотой и со
   скруглением, даты были 30 px, узкие и без рамки — строка фильтров «прыгала».
   color-scheme — чтобы значок календаря был виден на тёмном фоне. */
.acc-date-field { height: auto; gap: 8px; }
.acc-date-input {
  height: 46px;
  min-height: 46px;
  line-height: normal;
  padding: 0 12px;
  border-radius: 12px;
  border: 1px solid var(--pk-line-2, rgba(148, 178, 255, 0.18));
  background: var(--t79, rgba(10, 14, 22, 0.9));
  color: inherit;
  font: inherit;
  min-width: 160px;
  color-scheme: dark;
}
:root[data-theme="light"] .acc-date-input { color-scheme: light; }

/* «Агент возвращается через» → своё время (14 сентября). */
.chatpane-rulescustom { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; }
.chatpane-rulescustom .chatpane-customn,
.chatpane-rulescustom .chatpane-customunit {
  height: 34px;
  padding: 0 10px;
  border-radius: 10px;
  border: 1px solid var(--pk-line-2, rgba(148, 178, 255, 0.18));
  background: var(--t79, rgba(10, 14, 22, 0.9));
  color: inherit;
  font: inherit;
}
.chatpane-rulescustom .chatpane-customn { width: 76px; }

/* «Маршруты между отделами»: что / кого / зачем + заготовки (14 сентября). */
.ops-why { display: grid; gap: 6px; margin: 4px 0 14px; }
.ops-why-row { margin: 0; line-height: 1.5; }
.ops-why-row strong { font-weight: 600; }
.ops-why-example { margin: 4px 0 0; padding: 10px 12px; border-radius: 12px; border: 1px dashed var(--pk-line-2, rgba(148, 178, 255, 0.18)); opacity: 0.9; line-height: 1.5; }
.ops-step .ops-step-title.ops-step-hours { flex: 0 0 84px; min-inline-size: 70px; }
.ops-presets { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 12px; }

/* «Срок первого ответа»: подписанные поля и единица времени (14 сентября). */
.sla-field { display: grid; gap: 4px; flex: 1 1 220px; min-inline-size: 0; }
.sla-time { display: flex; gap: 8px; }
.sla-time input { flex: 0 0 96px; min-inline-size: 0; }
.sla-time select { flex: 1 1 auto; }
.queue-legend { margin: 6px 0 2px; }

/* «Движение по стадиям»: порог квалификации — своей строкой под подсказкой,
   а не поверх выбора стадии (там он рисовался цифрой внутри поля, 14 сентября). */
.set-stage-rules .set-stage-rule .set-stage-min-label { grid-row: 3; grid-column: 2; justify-self: end; align-self: center; margin: 0; }
.set-stage-rules .set-stage-rule .set-stage-min { grid-row: 3; grid-column: 3; justify-self: start; }
/* Лестница: новый шаг — число, единица, кто пишет, текст. */
.fu-new-step { flex-wrap: wrap; }
.fu-new-step .agent-fu-unit, .fu-new-step .agent-fu-mode { flex: 0 0 auto; }
.agent-fu-external-more > summary { cursor: pointer; }
/* Триггеры по словам: у каждого поля подпись (14 сентября). */
.kb-cap { display: grid; gap: 4px; min-width: 0; }
.kb-cap .kb-cap-text { font-size: 12px; color: var(--rp-muted, #9aa7bd); }
.kb-trigger-example { margin: 6px 0 10px; }
.kb-structure-why { display: block; font-size: 12px; color: var(--bd-ink-2, #c3cee0); margin-top: 3px; }
/* Стоп-фразы звонков: галочка не прижата к краю и не срезается (14 сентября). */
.vsp-row { padding: 8px 10px; border-radius: 10px; }
.vsp-on { padding-inline-start: 2px; }
.vsp-on input { width: 16px; height: 16px; flex: 0 0 16px; }
/* «Задачи»: список во всю высоту (14 сентября, владелец: «добавь вниз
   возможность больше видеть — мало места»). Сетка страницы с фиксированной
   высотой сжимала блок со своим скроллом до ~350px; теперь он высотой со
   свой список, а прокручивается страница. */
.tsk-page > .tsk-scroll { min-height: max-content; }
/* Интеграции: три входа сверху — строкой карточек, как плитки ниже. */
/* ПЯТЬ КАРТОЧЕК В ОДИН РЯД — ЭТО ПЯТЬ УЗКИХ КАРТОЧЕК. При minmax(260px) на
   ноутбуке помещались все пять по 271 px, заголовки резались, и владелец
   прислал скриншот со словами «карточки наехали, не мельчи, там два ряда».
   330 px дают четыре в ряд и пятую во второй — та же полка, читаемый текст. */
.ih-entries { display: grid; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); gap: 12px; margin: 4px 0 10px; align-items: start; }
.ih-entries .ih-entry {
  flex-direction: column; align-items: flex-start; gap: 6px; height: 100%;
  background: var(--pk-card, rgba(255, 255, 255, 0.03)); border-color: var(--pk-line-2, rgba(148, 178, 255, 0.18));
}
.ih-entries .ih-entry:hover { border-color: var(--pk-blue-line); background: var(--pk-blue-soft); }
/* Карточка полки — это <button>, и `white-space: nowrap` прилетает в неё от
   общего правила для кнопок, а оттуда НАСЛЕДУЕТСЯ в заголовок. Разрешить
   заголовку переносить (`flex: 0 1 auto`, `min-width: 0`) было мало: он всё
   равно оставался в одну строку и резался по краю карточки — проверено на
   боевом экране, «🔔 Для команды: оповещения сотрудникам» вылезал на 21 px.
   Снимаем nowrap с самой карточки; для span это уже было сделано строкой ниже
   тем же способом. */
.ih-entries .ih-entry { white-space: normal; }
.ih-entries .ih-entry span { white-space: normal; line-height: 1.45; }
/* …и статус в такой карточке (24.09.2026): «Включено · отправляем события в
   Meta, что…» — одна строка 514 px, потому что styles.css держит у каждой
   .status-pill `white-space: nowrap !important` («подпись пилюли не режется»).
   Длинный статус в карточке — это фраза, а не пилюля: переносится. Только
   на узком экране: мобильный проход не двигает раскладку рабочего стола. */
@media (max-width: 980px) {
  .ih-entries .ih-entry .status-pill { white-space: normal !important; max-width: 100%; }
}
.ih-entries .ih-entry .ih-entry-go { margin-inline-start: 0; margin-top: auto; }
.ih-entries .tg2 { min-width: 0; }
.ih-entries .tg2:has(.idesk-card) { grid-column: 1 / -1; }
/* Модули для своей CRM: крупнее и продающе (14 сентября, владелец: «текст
   мелкий, не продающий, пользу выделить красивее»). */
.micro-catalog > p:first-of-type { font-size: 15px; line-height: 1.55; color: var(--pk-text, inherit); }
.micro-catalog-table { font-size: 14.5px; border-collapse: separate; border-spacing: 0 10px; }
.micro-catalog-table th { font-size: 11.5px; padding: 0 16px; border-bottom: 0; }
.micro-catalog-table td {
  padding: 16px; border-bottom: 0; line-height: 1.5;
  background: var(--pk-card, rgba(255, 255, 255, 0.03));
  border-top: 1px solid var(--pk-line-2, rgba(148, 178, 255, 0.16));
  border-bottom: 1px solid var(--pk-line-2, rgba(148, 178, 255, 0.16));
}
.micro-catalog-table td:first-child { border-inline-start: 1px solid var(--pk-line-2, rgba(148, 178, 255, 0.16)); border-start-start-radius: 14px; border-end-start-radius: 14px; font-size: 16px; font-weight: 700; }
.micro-catalog-table td:last-child { border-inline-end: 1px solid var(--pk-line-2, rgba(148, 178, 255, 0.16)); border-start-end-radius: 14px; border-end-end-radius: 14px; }
.micro-catalog-price { font-size: 20px; font-weight: 800; color: var(--pk-text, inherit); }
.micro-catalog-includes li::marker { color: var(--ok, #3ccf8e); content: "✓  "; }

/* ── ИНТЕГРАЦИИ: ПЛАШКА ГОВОРИТ, ЧЕЙ ХОД (15 сентября 2026) ─────────────────
   «Нужна настройка» ушла с плашки (владелец читал её как «вы не настроили»).
   Цвет — только подсказка к слову, не замена ему:
     not_connected       нейтральная — кнопка на карточке, ход клиента;
     soon,
     boardroom_enable    синяя — ход наш, клиенту ждать или оставить заявку;
     elsewhere           нейтральная — настраивается в другом разделе;
     connection_error    красная, как check_failed — провайдер отказал.
   Переносится по словам, как saved: слова и есть содержание. */
.idesk-pill-not_connected,
.idesk-pill-elsewhere { color: var(--pk-muted); }
.idesk-pill-soon,
.idesk-pill-boardroom_enable {
  border-color: var(--pk-blue-line, rgba(47, 107, 255, 0.35));
  background: var(--pk-blue-soft, rgba(47, 107, 255, 0.08));
  color: var(--pk-text);
  white-space: normal;
  text-align: end;
  line-height: 1.25;
}
.idesk-pill-connection_error {
  border-color: rgba(248, 113, 113, 0.38);
  background: rgba(248, 113, 113, 0.12);
  color: var(--pk-red, #f87171);
  white-space: normal;
  text-align: end;
  line-height: 1.25;
}
/* ── ИНТЕГРАЦИИ: САМОСТОЯТЕЛЬНОЕ ПОДКЛЮЧЕНИЕ И «СКОРО» (23 сентября 2026) ──
   Владелец: «клиент подключает всё сам». На полке у карточки одна кнопка
   внизу — «Подключить» (или «Настроить» у подключённой, дверь в модуль у
   своего модуля); всё, что сегодня не подключить самому, — компактные плитки
   в свёрнутой полке «Скоро» каждого раздела. У каждого коннектора своя
   метка: логотип, если он у нас есть, иначе инициалы на цвете бренда
   (channelMark с monogram) — сплошной цвет с подобранным по контрасту
   текстом одинаково читается в светлой и тёмной теме. */
/* ТЕЛЕФОН, 375 px: ВЕСЬ СТОЛ БЫЛ ШИРИНОЙ 2047 px (замерено в превью 23
   сентября; и до этой правки — 1965 px). .page-stack — сетка с неявной
   колонкой auto, и её распирало до max-content соседей (сетка карточек с
   auto-fill, ленты, каталог), а overflow: hidden у предков прятал лишнее:
   карточки выглядели целыми, а плитки «Скоро» во всю ширину колонки уезжали
   за край вместе с кнопкой. Только на странице стола — колонка не шире
   экрана; на остальных страницах сетка не тронута. */
.page-stack:has(> section.idesk) { grid-template-columns: minmax(0, 1fr); }
.idesk-card-cta { margin-top: auto; padding-top: 4px; display: flex; gap: 8px; }
.idesk-card-cta .idesk-btn { min-height: 34px; }
.idesk-card-cta .idesk-btn-primary { flex: 1 1 auto; justify-content: center; }
.chan-mark.chan-mark-monogram {
  font-weight: 800; font-size: 13px; letter-spacing: -0.02em; line-height: 1;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.10);
  text-transform: none; user-select: none;
}
.chan-mark.chan-mark-monogram-long { font-size: 10.5px; letter-spacing: -0.03em; }
.idesk-more[data-soon-fold] { margin-top: 14px; }
.idesk-more[data-soon-fold] > summary { display: inline-flex; align-items: center; gap: 8px; }
.idesk-soon-count {
  display: inline-flex; min-width: 20px; height: 20px; padding: 0 6px;
  align-items: center; justify-content: center; border-radius: 999px;
  background: rgb(var(--ch-lift) / 0.12); font-size: 11px; font-weight: 700;
}
.idesk-soon-note { margin: 10px 0 0; color: var(--pk-dim); font-size: 12px; line-height: 1.5; }
.idesk-soon-grid {
  margin-top: 10px; display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(208px, 1fr));
}
.idesk-soon-tile {
  display: flex; flex-direction: column; gap: 8px; min-width: 0;
  padding: 10px 11px; border-radius: 12px;
  border: 1px dashed var(--pk-line-2, rgba(148, 178, 255, 0.2));
  background: transparent;
}
.idesk-soon-head { display: flex; align-items: center; gap: 9px; min-width: 0; }
.idesk-soon-head .idesk-mark { width: 30px; height: 30px; border-radius: 9px; }
.idesk-soon-name {
  flex: 1 1 auto; min-width: 0; padding: 0; border: 0; background: transparent;
  color: var(--pk-text); font: inherit; font-size: 13px; font-weight: 600; text-align: start;
  cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.idesk-soon-name:hover { text-decoration: underline; }
.idesk-soon-tile .idesk-want { width: 100%; justify-content: center; min-height: 32px; font-size: 12px; }
.idesk-want.is-done { color: var(--pk-green, #4ade80); border-color: rgba(74, 222, 128, 0.3); opacity: 1; cursor: default; }
.idesk-soon-tile .idesk-msg { margin: 0; font-size: 11.5px; }
@media (max-width: 720px) {
  .idesk-soon-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 420px) {
  /* На телефоне плитка — строка: метка и имя слева, кнопка справа, чтобы
     тринадцать плиток телефонии не растягивались на три экрана. */
  .idesk-soon-grid { grid-template-columns: 1fr; gap: 6px; }
  .idesk-soon-tile { flex-direction: row; flex-wrap: wrap; align-items: center; padding: 8px 10px; }
  .idesk-soon-head { flex: 1 1 0; min-width: 0; }
  .idesk-soon-tile .idesk-want { width: auto; flex: 0 0 auto; padding-inline: 12px; }
  .idesk-soon-tile .idesk-msg { flex: 1 0 100%; }
}

/* Первая строка экрана коннектора — чей ход и что нажать. Чуть заметнее
   обычного «Нужно:», потому что это единственное, что надо прочитать. */
.idesk-lead-line { color: var(--pk-text); font-size: 12.5px; }
/* Что включает одно подключение — списком, а не абзацем (Google Workspace). */
.idesk-features {
  margin: 0; padding-inline-start: 18px;
  display: flex; flex-direction: column; gap: 5px;
  color: var(--pk-text); font-size: 12.5px; line-height: 1.55;
}
/* «Подробнее»: всё правдивое, что не является следующим шагом. Внизу
   карточки, свёрнуто; раскрытость помнит модуль (DETAIL_MORE_OPEN). */
.idesk-more-info {
  margin-top: 6px; padding-top: 8px;
  border-top: 1px solid var(--pk-line, rgba(148, 178, 255, 0.12));
}
.idesk-more-info > summary {
  cursor: pointer; color: var(--pk-dim); font-size: 12px; font-weight: 600;
}
.idesk-more-info[open] > summary { margin-bottom: 8px; }
.idesk-more-info > p + p,
.idesk-more-info > details { margin-top: 8px; }
/* «Что должно получиться» и «Если не работает» (23.09.2026): под шагами,
   до «Подробнее». Раскрытость «Если не работает» помнит модуль (TROUBLE_OPEN). */
.idesk-expect { margin-top: 8px; }
.idesk-trouble {
  margin-top: 8px; padding: 8px 10px;
  border: 1px solid var(--pk-line, rgba(148, 178, 255, 0.12));
  border-radius: 8px;
}
.idesk-trouble > summary {
  cursor: pointer; color: var(--pk-text); font-size: 12.5px; font-weight: 600;
}
.idesk-trouble[open] > summary { margin-bottom: 6px; }
.idesk-trouble-row { margin: 6px 0 0; }
.idesk-trouble-row::before { content: "• "; color: var(--pk-dim); }

/* КАРТОЧКА «1С:ПРЕДПРИЯТИЕ» (24.09.2026, OneCConnector.js): что читается —
   список с отметками, должники — таблица, которая на телефоне прокручивается
   внутри себя, а не растягивает страницу. Цвет не единственный носитель:
   отметка «✓» / «—» стоит словом рядом. */
.onec-panel { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.onec-coverage { list-style: none; padding-inline-start: 0; }
.onec-coverage .onec-cov-mark { display: inline-block; width: 1.2em; font-weight: 700; }
.onec-coverage .onec-cov-ok .onec-cov-mark { color: var(--pk-green); }
.onec-coverage .onec-cov-missing { color: var(--pk-muted); }
.onec-debtors-box { display: flex; flex-direction: column; gap: 8px; min-width: 0; overflow-x: auto; }
.onec-debtors { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.onec-debtors th, .onec-debtors td { padding: 6px 8px; border-bottom: 1px solid var(--pk-line); text-align: start; vertical-align: top; }
.onec-debtors th { color: var(--pk-muted); font-weight: 600; white-space: nowrap; }
.onec-debtors .onec-num { text-align: end; white-space: nowrap; font-variant-numeric: tabular-nums; }
.onec-change > summary, .onec-guide > summary { cursor: pointer; color: var(--pk-text); font-size: 12.5px; font-weight: 600; }
/* Запись в 1С (шаг 3, 26.09.2026): выключатель, состояние, очередь карточек. */
.onec-writes { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; min-width: 0; padding: 10px 12px; border: 1px solid var(--pk-line); border-radius: 10px; }
.onec-writes .onec-writes-state { font-weight: 700; }
.onec-writes .onec-writes-state.is-on { color: var(--pk-green); }
.onec-writes .onec-writes-state.is-off, .onec-writes .onec-writes-state.is-server_off, .onec-writes .onec-writes-state.is-needs_setup { color: var(--pk-muted); }
.onec-switch { max-width: 100%; white-space: normal; text-align: start; }
.onec-queue { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.onec-card { display: flex; flex-direction: column; gap: 6px; min-width: 0; padding: 10px 12px; border: 1px solid var(--pk-line); border-radius: 10px; }
.onec-card-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 8px; min-width: 0; }
.onec-card-title { min-width: 0; overflow-wrap: anywhere; }
.onec-card-summary { overflow-wrap: anywhere; }
.onec-lines-box { min-width: 0; max-width: 100%; overflow-x: auto; }
.onec-card-actions { margin-top: 2px; }
.onec-card .idesk-form-note, .onec-writes .idesk-form-note { overflow-wrap: anywhere; }
.onec-change[open] > summary { margin-bottom: 8px; }

/* ── ПЛАНШЕТ И УЗКОЕ ОКНО: 701–980 px (19.09.2026, пункт 19 владельца) ─────
   Ниже 980 px styles.css превращал оболочку в блок, и меню ложилось столбцом
   во всю ширину (замер: 900×1024), а страница уезжала на экран ниже. На такой
   ширине места хватает на узкое меню слева — оставляем его, как на ноутбуке
   со свёрнутым меню. Телефонная полоса (≤700 px) не тронута. */
@media (min-width: 701px) and (max-width: 980px) {
  .app-shell { display: grid !important; grid-template-columns: 84px minmax(0, 1fr) !important; }
  .app-shell > .sidebar { position: sticky !important; top: 0; height: 100vh !important; overflow-y: auto !important; border-bottom: 0 !important; }
  .app-shell > .sidebar .nav-list { display: flex !important; flex-direction: column !important; overflow-x: visible !important; }
  .app-shell > .sidebar .nav-item span:not([class*="nav-icon"]) { display: inline !important; }
}

/* «Почта — только отправка» (19.09.2026): Google отправляет письма, агент
   входящие ещё не читает. Жёлтая рамка — «наполовину», а не «выключено». */
.dash-int-tile.is-half { border-color: rgba(245, 165, 36, 0.4); }
.dash-int-tile.is-half .dash-int-state { color: var(--rp-amber, #f5a524); }
.dash-int-tile.is-half:hover, .dash-int-tile.is-half:focus-visible { border-color: rgba(245, 165, 36, 0.75); }

/* «Риски» и «Следующие действия»: плашки своей высоты, стопкой сверху
   (19.09.2026). Карточки в ряду одной высоты, и единственная плашка
   растягивалась на всю карточку — число «5» повисало посередине справа. */
.rp-panels { align-content: start; }

/* РАСКРЫТАЯ КАРТОЧКА «РАБОТА ПОВЕРХ CRM» — НА ВЕСЬ РЯД (20.09.2026).
   Карточка стоит в сетке .ih-entries из трёх колонок. Открытая часть выходила
   за пределы своей ячейки и накладывалась на соседей: текст поверх текста.
   Нашлось на съёмке ролика 29 — снимали экран и увидели наложение.
   Открытая карточка занимает весь ряд, заголовок не растягивается на высоту
   ряда, содержимое идёт под ним. */
.crmwb { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.crmwb > .ih-entry { height: auto; align-items: flex-start; }
.ih-entries > .crmwb[data-open="1"] { grid-column: 1 / -1; }

/* ═══ CRM, ВОЛНА A (26.09.2026): ПОЧЕМУ ТАКАЯ ОЦЕНКА, БОКОВАЯ ПАНЕЛЬ СДЕЛКИ,
   УМНЫЕ СПИСКИ, КАРТОЧКА ПОДТВЕРЖДЕНИЯ ═══════════════════════════════════════
   Цвета — только из токенов --pk-* (светлая и тёмная тема через light-dark).
   Прокрутка — только overflow-y у тела панели: сбоку на CRM прокручивается
   одна доска (test-crm-scroll-discipline). */

/* 1. Чип скоринга с причинами — кнопка: наведение на столе, касание на
   телефоне. Без причин — только число, не кнопка и без подсказки. */
button.pk-score { font-family: inherit; font-size: 11px; line-height: 1.3; }
.pk-score.has-why { cursor: pointer; }
.pk-score.has-why:hover { border-color: color-mix(in srgb, var(--pk-text) 38%, transparent); }
.pk-score.has-why:focus-visible { outline: 2px solid var(--pk-blue); outline-offset: 1px; }
.pk-score.is-bare { cursor: default; }
/* Подсказка — узел в <body>, position: fixed от чипа (scoreWhy.js): колонка
   доски её не обрежет, и морф перерисовки её не снимет. */
.pk-score-pop {
  position: fixed; z-index: 90; box-sizing: border-box; max-width: 320px;
  padding: 10px 12px; border-radius: 10px;
  background: var(--pk-panel); color: var(--pk-text);
  border: 1px solid var(--pk-line-2); box-shadow: 0 14px 34px rgba(0, 0, 0, 0.32);
  font-size: 12.5px; line-height: 1.4;
}
.pk-score-pop[hidden] { display: none; }
.pk-score-pop-head { display: block; margin-bottom: 6px; font-weight: 600; }
.pk-score-pop-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 4px; }
.pk-score-pop-list > li { padding-inline-start: 7px; border-inline-start: 2px solid var(--pk-line-2); }
.pk-score-pop-list > li.is-plus { border-inline-start-color: var(--pk-low); }
.pk-score-pop-list > li.is-minus { border-inline-start-color: var(--pk-high); }

/* 2. Боковая панель сделки поверх доски. Не колонка и не подложка: доска под
   ней не сдвигается и не перестраивается — прокрутка доски остаётся на месте.
   На телефоне (≤ 640 px) — лист во весь экран. */
.crm-peek {
  position: fixed; inset-block: 0; inset-inline-end: 0; z-index: 61;
  box-sizing: border-box; width: min(420px, 100vw);
  display: flex; flex-direction: column;
  background: var(--pk-panel); color: var(--pk-text);
  border-inline-start: 1px solid var(--pk-line-2);
  box-shadow: -24px 0 60px rgba(0, 0, 0, 0.34);
}
.crm-peek-head { display: flex; align-items: flex-start; gap: 10px; padding: 16px 18px 12px; border-bottom: 1px solid var(--pk-line); }
.crm-peek-titles { min-width: 0; flex: 1 1 auto; display: grid; gap: 4px; }
.crm-peek-title { margin: 0; font-size: 16px; font-weight: 650; line-height: 1.25; overflow-wrap: anywhere; }
.crm-peek-stage { color: var(--pk-muted); font-size: 12.5px; }
.crm-peek-x {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 9px;
  border: 1px solid var(--pk-line-2); background: none; color: var(--pk-text);
  font-size: 20px; line-height: 1; cursor: pointer;
}
.crm-peek-x:hover, .crm-peek-x:focus-visible { border-color: var(--pk-blue-line); }
.crm-peek-body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 14px 18px; display: grid; gap: 16px; align-content: start;
}
.crm-peek-facts { margin: 0; display: grid; gap: 10px; }
.crm-peek-fact { display: grid; grid-template-columns: 118px minmax(0, 1fr); gap: 10px; align-items: baseline; }
.crm-peek-fact dt { color: var(--pk-muted); font-size: 12.5px; }
.crm-peek-fact dd { margin: 0; min-width: 0; font-size: 13.5px; overflow-wrap: anywhere; }
.crm-peek-fact dd .pk-score { margin-inline-start: 0; }
.crm-peek-contact { display: grid; gap: 2px; min-width: 0; }
.crm-peek-name.is-standin { font-style: italic; opacity: 0.8; }
.crm-peek-link { color: var(--pk-blue); text-decoration: none; overflow-wrap: anywhere; }
.crm-peek-link:hover { text-decoration: underline; }
.crm-peek-sec h4 { margin: 0 0 6px; font-size: 11.5px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--pk-muted); }
.crm-peek-muted { margin: 0; color: var(--pk-muted); font-size: 13px; }
.crm-peek-err { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.crm-peek-next { margin: 0; font-size: 13.5px; }
.crm-peek-next.is-late .crm-peek-next-d { color: var(--pk-high); font-weight: 600; }
.crm-peek-msgs { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.crm-peek-msg { display: grid; gap: 3px; max-width: 92%; padding: 8px 10px; border-radius: 10px; background: var(--pk-card); }
.crm-peek-msg.is-in { justify-self: start; }
.crm-peek-msg.is-out { justify-self: end; background: var(--pk-blue-soft); }
.crm-peek-msg-meta { color: var(--pk-muted); font-size: 11.5px; }
.crm-peek-msg-text { font-size: 13px; line-height: 1.4; white-space: pre-wrap; overflow-wrap: anywhere; }
.crm-peek-foot { padding: 12px 18px 16px; border-top: 1px solid var(--pk-line); }
.crm-peek-full { display: inline-flex; align-items: center; justify-content: center; width: 100%; box-sizing: border-box; text-decoration: none; }
@media (max-width: 640px) {
  /* Лист во весь экран — краями, а не 100vw/100vh: 100vw шире окна на
     полосу прокрутки, 100vh на телефоне выше видимого окна (адресная строка),
     и «Открыть полностью» уезжала бы под край. */
  .crm-peek {
    inset: 0; width: auto; height: auto; z-index: 70;
    border-inline-start: 0; box-shadow: none;
  }
  .crm-peek-head { padding: 12px 14px 10px; }
  .crm-peek-body { padding: 12px 14px; }
  .crm-peek-foot { padding: 10px 14px 14px; }
  .crm-peek-fact { grid-template-columns: 96px minmax(0, 1fr); }
}
/* Панель живёт внутри <main>, а <main> открывает свой слой (z-index 1), и
   никакой z-index панели изнутри не перевесит то, что висит на <body>:
   · до 700 px — строку меню кабинета (.mobile-bar, fixed, z 57): замер на
     375×812 — она закрывала «×» панели. Панель начинается под строкой, как
     .lw-ctor-drawer (lead-workspace.css);
   · Boro (z 50) и «Наверх» (z 45) — рисовались поверх переписки и «Открыть
     полностью». Пока панель открыта, они уступают ей, как карточке сделки и
     диалогам (cabinet-system.css, «Boro yields to an open workflow surface»). */
@media (max-width: 700px) {
  body.has-rail .crm-peek { inset-block-start: calc(65px + env(safe-area-inset-top)); }
}
body:has(.crm-peek) .boro-root,
body:has(.crm-peek) .br-to-top { visibility: hidden; pointer-events: none; }
body:has(.crm-peek) .boro-root.boro-dragging { visibility: visible; pointer-events: auto; opacity: 1; }

/* 3. Умные списки — полоса над списком: имя списка и число. */
.crm-smart { display: grid; gap: 6px; margin: 8px 0 10px; min-width: 0; }
.crm-smart-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; min-width: 0; }
.crm-smart-label { color: var(--pk-muted); font-size: 12px; font-weight: 600; }
.crm-smart-chips { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
.crm-smart-chip {
  display: inline-flex; align-items: center; gap: 7px; max-width: 100%;
  height: var(--pk-row-h); padding: 0 10px; border-radius: 999px;
  border: 1px solid var(--pk-line-2); background: var(--pk-card); color: var(--pk-text);
  font-family: inherit; font-size: 12.5px; cursor: pointer;
}
.crm-smart-chip:hover:not(:disabled) { border-color: var(--pk-blue-line); }
.crm-smart-chip.is-on { border-color: var(--pk-blue-line); background: var(--pk-blue-soft); }
.crm-smart-chip:disabled { opacity: 0.55; cursor: not-allowed; }
.crm-smart-name { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.crm-smart-count {
  min-width: 22px; padding: 1px 6px; border-radius: 999px; box-sizing: border-box;
  background: var(--pk-card-hi); text-align: center; font-size: 12px; font-variant-numeric: tabular-nums;
}
.crm-smart-chip.has-hits .crm-smart-count { background: color-mix(in srgb, var(--pk-amber) 24%, transparent); }
.crm-smart-note { color: var(--pk-muted); font-size: 12px; }
.crm-smart-rule { margin: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; color: var(--pk-muted); font-size: 12.5px; line-height: 1.45; }
.crm-smart-exit { padding: 0; border: 0; background: none; color: var(--pk-blue); font-family: inherit; font-size: 12.5px; cursor: pointer; }

/* 4. Массовое действие над умным списком — карточка подтверждения. */
.crm-sbulk {
  display: grid; gap: 8px; margin: 0 0 10px; padding: 10px 12px; min-width: 0;
  border: 1px solid var(--pk-line-2); border-radius: 12px; background: var(--pk-panel);
}
.crm-sbulk-sel { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 13px; }
.crm-sbulk-all, .crm-sbulk-clear {
  padding: 4px 10px; border: 1px solid var(--pk-line-2); border-radius: 8px;
  background: none; color: var(--pk-text); font-family: inherit; font-size: 12.5px; cursor: pointer;
}
.crm-sbulk-all:hover, .crm-sbulk-clear:hover { border-color: var(--pk-blue-line); }
.crm-sbulk-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-width: 0; }
.crm-sbulk-actions select { min-width: 0; max-width: 100%; height: var(--pk-row-h); padding: 0 10px; border-radius: 8px; font-size: 12.5px; }
.crm-sbulk-note { color: var(--pk-muted); font-size: 12.5px; }
.crm-sbulk-confirm {
  display: grid; gap: 6px; padding: 12px 14px; border-radius: 10px;
  border: 1px solid var(--pk-blue-line); background: var(--pk-blue-soft);
}
.crm-sbulk-confirm-title { margin: 0; font-size: 14px; font-weight: 650; }
.crm-sbulk-confirm p { margin: 0; font-size: 13px; line-height: 1.45; overflow-wrap: anywhere; }
.crm-sbulk-what { font-weight: 600; }
.crm-sbulk-what.is-sub { font-weight: 400; color: var(--pk-muted); }
.crm-sbulk-cost { font-weight: 600; }
.crm-sbulk-list, .crm-sbulk-rules { color: var(--pk-muted); }
.crm-sbulk-notice { color: var(--pk-amber); font-weight: 600; }
.crm-sbulk-buttons { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.crm-sbulk-done p { margin: 0 0 6px; font-size: 13px; line-height: 1.45; }
.crm-sbulk-journal { color: var(--pk-muted); font-size: 12px; }
.crm-sbulk-error { margin: 0; color: var(--pk-high); font-size: 13px; }

/* 5. Колонка «почему в списке»: встаёт на место «Источника» и «Создан»
   (6,5 % + 4,5 %), сумма ширин та же. */
.crm-listv.is-smart .crm-list.by-key th.col-smart { width: 11%; }
.crm-listv .crm-list td.c-smart { white-space: nowrap; color: var(--pk-muted); }
