/* Admin styling — hand-written, no framework, no build step (ADR-026).
 *
 * The whole design system is the block of custom properties below: five type sizes, the brand's
 * three weights, one 4px space scale, the brand palette and one grey ramp. Every rule after it
 * spends those tokens and nothing else — there are no bare hex literals and no magic
 * spacing values past this point, so a change to the system is a change in one place.
 *
 * It IS the Appsyoulove identity, not a lookalike: Ubuntu in three weights, #e8393f as the
 * structural accent, #f3f3f3 panels, the brand's own link blue, and the real logo artwork placed
 * as an image (assets/brand/appsu). The guidelines are emphatic that the wordmark is never rebuilt
 * from type plus a drawn heart — so nothing here draws one, in CSS or anywhere else.
 *
 * Restraint is the point, not an aesthetic preference, and it survives the rebrand: there are no
 * gradients, no blur and no shadows: a 1px hairline in a low-contrast neutral separates things, and
 * whitespace does the rest. Colour never carries meaning alone — every state that is coloured also
 * says its state in a word, because a state you can only see is a state a colourblind
 * operator cannot audit. That rule now carries more weight than before, because the brand accent
 * and the destructive hue are the same red: what separates «send» from «erase» here is the shape
 * of the control and the word on it, never the colour.
 *
 * Nothing here visualises a person. There is no chart, no meter and no bar (ADR-023).
 */

/* Ubuntu, self-hosted. The brand guidelines are explicit that the font is not optional: when
 * Ubuntu is missing the renderer silently substitutes something else and the output is
 * recognisably off-brand while looking, at a glance, fine. Served from our own static directory
 * rather than a CDN for two reasons that both already applied here — the admin UI is LAN-only and
 * must not depend on the public internet, and the extension ships under a CSP that forbids
 * third-party origins. Same three files in both places, one source of truth in assets/brand/appsu.
 *
 * `swap`: text renders immediately in Arial and re-lays out when Ubuntu arrives. On a LAN that is
 * one frame; blocking the first paint on a 350 KB font to avoid it would be the worse trade. */
@font-face {
  font-family: "Ubuntu";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/admin/static/fonts/Ubuntu-Regular.ttf") format("truetype");
}
@font-face {
  font-family: "Ubuntu";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/admin/static/fonts/Ubuntu-Medium.ttf") format("truetype");
}
@font-face {
  font-family: "Ubuntu";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/admin/static/fonts/Ubuntu-Bold.ttf") format("truetype");
}

:root {
  color-scheme: light dark;

  /* Type. Five sizes and the brand's three weights. The family is the brand stack verbatim —
   * Arial is the fallback the guidelines name, so a host without the font degrades the way the
   * brand expects rather than into a platform UI font. */
  --font: "Ubuntu", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --t-caption: 12px;
  --t-small: 13px;
  --t-body: 15px;
  --t-title: 17px;
  --t-display: 24px;
  /* Three weights, because the brand defines three roles: Bold for titles, Medium for
   * subheadings and card titles, Regular for everything read as prose. This replaces the
   * two-weight rule this file used to state — the old 600 was a synthetic middle that Ubuntu
   * does not ship, so it rendered as a faux-bold Medium on every screen. */
  --w-regular: 400;
  --w-medium: 500;
  --w-bold: 700;

  /* Space. One scale, 4px based. */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s6: 24px;
  --s8: 32px;
  --s12: 48px;

  /* Comfortable measure for Russian prose — roughly 70 characters at body size. Long
   * paragraphs are never window-wide. Fixed in rem rather than ch so that a caption, a
   * paragraph and a card all end on the same right edge instead of three ragged ones. */
  --measure: 33rem;
  --page: 1080px;

  /* Shape. The brand puts card radius in the 8–16px band; controls take the lower end so a
   * button inside a card never looks rounder than the card holding it. */
  --r-control: 8px;
  --r-container: 12px;

  /* Colour — the brand palette, verbatim where the brand states a value.
   *
   * #e8393f is the structural red: accent bars, table headers, primary buttons, focus. The
   * brighter #ec4c56 exists in the guidelines for the logo heart and chart lines and is
   * explicitly NOT for borders or dividers, so it appears nowhere below.
   *
   * The page is white and panels are #f3f3f3 — the inverse of what this file used to do, and the
   * arrangement the guidelines actually prescribe for cards.
   *
   * Semantic states borrow real brand hues rather than inventing a second palette: the HR green
   * and the marketing orange are already part of the identity, so «done» and «attention» stay on
   * brand instead of drifting into stock traffic-light colours. Red is BOTH the accent and the
   * destructive hue, which is why destructive controls are outlined rather than filled and every
   * state also says its state in a word — the rule this file already had, now load-bearing.
   *
   * Links keep the brand's own link blue and stay underlined, per the guidelines. That is also
   * what keeps a page of red accents readable: prose links do not compete with actions. */
  --bg: #ffffff;
  --panel: #f3f3f3;
  --fg: #000000;
  --fg-muted: #3c3c3c;
  --fg-caption: #6d6d6d;
  --line: #e2e2e2;
  --line-strong: #8a8a8a;
  --accent: #e8393f;
  --accent-strong: #c62d33;
  --accent-fg: #ffffff;
  --accent-soft: #fdecec;
  /* Red comes in three jobs, because one value cannot do all three legibly. Measured in a browser
   * against the real tokens, not judged by eye:
   *
   *   --accent      #e8393f  the exact brand red. Structure only: accent bars, borders, focus
   *                          rings, underlines. Nothing small and white ever sits on it.
   *   --accent-fill #da363b  surfaces that CARRY white text — buttons, badges. The brand names
   *                          the pairing (red fill, white label) but it measures 4.13:1, under the
   *                          4.5:1 floor for normal text. 6% darker reads as the same red and
   *                          measures 4.59:1, so the label is legible and the identity is intact.
   *   --accent-text #c62d33  red as TYPE on a light background. #e8393f as text on white is
   *                          4.0:1; this shade of the same hue clears the floor.
   *
   * A deviation of 6% on one token is the smallest honest answer to a real conflict between the
   * guidelines and the accessibility commitment stated at the top of this file. It is recorded
   * here rather than silently applied. */
  --accent-text: #c62d33;
  --danger-text: #c62d33;
  --accent-fill: #da363b;
  /* The same split the reds needed, for the same measured reason: the brand states these hues,
   * and each one FAILS as small text on our panel grey. Measured on #f3f3f3, the harder of the two
   * backgrounds: link blue 3.56:1, HR green 3.13:1, marketing orange 2.19:1, caption grey 3.19:1.
   * So each keeps its exact brand value for fills, bars and borders — where it is a surface, not
   * type — and gets a darker sibling of the SAME hue for text. Nothing here invents a colour; the
   * darkening is the smallest step that clears 4.5:1. */
  --link: #366dc8;
  --link-brand: #4285f4;
  --link-strong: #1a66d0;
  --danger: #e8393f;
  --danger-soft: #fdecec;
  --warn: #f28e00;
  --warn-text: #a05e00;
  --warn-soft: #fef3e3;
  --ok: #009e5b;
  --ok-text: #007e49;
}

/* An alternative accent, chosen by the person looking at the screen (stored per browser, no
 * server state). Red is the brand's own and stays the default; blue is the brand's PM #1e4b9b —
 * a real value from the department palette, not a colour invented for this switch.
 *
 * The three jobs a red needed, a blue needs too, and the numbers differ enough to matter:
 * #1e4b9b is dark, so as a FILL on a light page it is excellent (white on it, 8.28:1) and as a
 * fill on a DARK page it disappears — 2.01:1 against #1e1e1e is a button with no visible edge.
 * Hence the dark theme lifts the fill to #3366cc (3.11:1 against the page, 5.37:1 under white)
 * and takes accent TYPE lighter still.
 *
 * Links keep their own blue and their underline in both accents. When the accent is blue those
 * two blues sit on the same screen, and what separates them is the underline — which is exactly
 * the job it already had. */
:root[data-accent="blue"] {
  --accent: #1e4b9b;
  --accent-strong: #163a78;
  --accent-fill: #1e4b9b;
  --accent-text: #1e4b9b;
  --accent-soft: #e8eefa;
  --danger-text: #c62d33;
}

@media (prefers-color-scheme: dark) {
  :root[data-accent="blue"]:not([data-theme="light"]) {
    --accent: #3366cc;
    --accent-strong: #4a79d6;
    --accent-fill: #3366cc;
    --accent-text: #7ba0e8;
    --accent-soft: #1b2740;
    --danger-text: #ff7a7f;
  }
}

/* Dark is designed, not inverted — and it is on-brand rather than a departure: the guidelines
 * name #3c3c3c as a brand dark background, put white text on it, and ship a dedicated
 * white-wordmark-red-heart logo for exactly this case.
 *
 * The greys are the brand's dark grey and a step below it for the page, so panels sit ON the
 * background instead of glowing above it. The three reds keep their three jobs: the fill is the
 * same #da363b as in light (white-on-red does not care which theme it is in), while accent TEXT
 * lightens to #ff7a7f — measured 5.62:1 on a dark panel, where the light-theme shade would be
 * unreadable. Same reason the link blue lightens to the brand blue's dark-mode sibling. */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #1e1e1e;
    --panel: #2b2b2b;
    --fg: #ffffff;
    --fg-muted: #c6c6c6;
    --fg-caption: #9a9a9a;
    --line: #3c3c3c;
    --line-strong: #787878;
    /* The fill stays the brand red — white on #e8393f is the brand's own pairing and holds its
     * contrast on any background. Only TEXT lightens, which is what the comment above is about. */
    --accent: #e8393f;
    --accent-strong: #f5555b;
    --accent-fg: #ffffff;
    --accent-soft: #3a2223;
    --accent-text: #ff7a7f;
    --danger-text: #ff7a7f;
    --accent-fill: #da363b;
    --link: #8ab4f8;
    --link-brand: #8ab4f8;
    --link-strong: #adc8fa;
    --danger: #ff5a60;
    --danger-soft: #3a2223;
    --warn: #f5a623;
    --warn-text: #f5a623;
    --warn-soft: #33280f;
    --ok: #3ec98a;
    --ok-text: #3ec98a;
  }
}

/* --- base --------------------------------------------------------------- */

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

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--t-body);
  font-weight: var(--w-regular);
  line-height: 1.5;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

.wrap { max-width: var(--page); margin: 0 auto; padding: 0 var(--s6); }
main.page { padding: var(--s6) 0 var(--s12); }

/* The brand's three roles, mapped once: Bold is the page title, Medium is a section or card
 * title, Regular is anything read as prose. */
h1, h2, h3 { line-height: 1.25; font-weight: var(--w-medium); }
h1 { font-size: var(--t-display); font-weight: var(--w-bold); letter-spacing: -0.01em; margin: 0 0 var(--s2); }
h2 { font-size: var(--t-title); margin: var(--s8) 0 var(--s3); }
h3 { font-size: var(--t-body); margin: var(--s6) 0 var(--s2); }
p { margin: 0 0 var(--s3); }

/* Two weights means two. Left alone, <b> and <strong> render at 700 in every browser, which
 * would put a third weight next to the 600 of every heading — and <b> is how this interface
 * emphasises the load-bearing sentence on almost every screen. */
b, strong { font-weight: var(--w-medium); }

/* Links are the brand's link blue and stay underlined — both are stated in the guidelines. The
 * underline is also what keeps this readable now that red means «action»: a sentence with three
 * links in it must not look like a row of buttons. */
a { color: var(--link); text-decoration-thickness: 1px; text-underline-offset: 2px; }
a:hover { color: var(--link-strong); }

/* Monospace for identifiers, keys and timestamps only — the things that are compared
 * character by character. The family is separated from the size, because the two jobs mono
 * does here are not the same job:
 *
 * `.mono` is scaffolding — a timestamp column, an actor column — and a step down, the same
 * way the transcript gutter is. `<code>` is a value: the excluded pattern, the address that
 * objected, the uuid of the meeting. Those are the subject of their row and must not render
 * smaller than the prose beside them, which is what one shared size was doing. Inline in a
 * sentence `<code>` takes the step down again, because there it really is an aside. */
code, .mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.mono, p code { font-size: var(--t-small); }

.muted { color: var(--fg-muted); }
.small { font-size: var(--t-small); }
.ok { color: var(--ok-text); }
.lede { font-size: var(--t-title); max-width: var(--measure); margin: 0 0 var(--s6); }
.prose, .prose p, .prose li { max-width: var(--measure); }
.prose ul, .prose ol { margin: 0 0 var(--s4); padding-left: var(--s6); }
.prose li { margin-bottom: var(--s2); }
.subtitle { font-size: var(--t-small); color: var(--fg-muted); max-width: var(--measure); margin: 0 0 var(--s6); }
/* Form-level guidance under a specific control — same voice as .subtitle, tighter margin. */
.hint { font-size: var(--t-small); color: var(--fg-muted); max-width: var(--measure); margin: var(--s1) 0 var(--s3); }
.back { display: block; font-size: var(--t-small); margin: 0 0 var(--s4); }

/* The one place ALL CAPS is allowed, and only with letter-spacing. */
.eyebrow {
  font-size: var(--t-caption); font-weight: var(--w-medium); text-transform: uppercase;
  letter-spacing: 0.07em; color: var(--fg-muted); margin: 0 0 var(--s1);
}

/* --- top bar ------------------------------------------------------------ */

.topbar { background: var(--panel); border-bottom: 1px solid var(--line); }
.topbar .wrap { display: flex; flex-direction: column; gap: var(--s3); padding-top: var(--s3); padding-bottom: var(--s3); }
.brand-row { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--s2) var(--s4); }
.brand { font-size: var(--t-title); font-weight: var(--w-medium); color: var(--fg); text-decoration: none; letter-spacing: -0.01em; }
.who { display: flex; align-items: baseline; gap: var(--s3); font-size: var(--t-small); color: var(--fg-muted); }

/* Two tiers in one row: the objects of the tool at body size, the policy surfaces one step
 * smaller and quieter. The hierarchy is the type, not a heading that explains it. */
/* Keyboard users skip the ~15 tab stops of the header on every page. Visible only on
 * focus — sighted mouse users never see it. */
.skip { position: absolute; left: -9999px; }
.skip:focus-visible {
  position: static; display: inline-block; padding: var(--s1) var(--s2);
  color: var(--accent-text);
}

.nav { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s4); }
.nav a { color: var(--fg); text-decoration: none; }
.nav a:hover { color: var(--accent-text); }
.nav-section { font-size: var(--t-body); }
.nav-policy { font-size: var(--t-small); }
/* .nav a's colour outranked .nav-policy:link, so the intended muting never applied —
 * match the anchor specificity and keep the active-page rule above both. */
.nav a.nav-policy { color: var(--fg-muted); }
.nav a.nav-policy:hover { color: var(--accent-text); }
.nav a[aria-current="page"] { color: var(--accent-text); font-weight: var(--w-medium); }
.nav-divider { align-self: stretch; width: 1px; min-height: var(--s4); background: var(--line); }
@media (max-width: 40rem) {
  /* When the nav wraps, a stretched divider becomes a lone full-height tick. */
  .nav-divider { display: none; }
}

/* A count, not a score: work waiting in a queue. Accent-filled where a human has to act,
 * a plain outline where it is only maintenance. */
.badge {
  display: inline-block; padding: 0 var(--s1); border-radius: var(--r-control);
  background: var(--accent-fill); color: var(--accent-fg);
  font-size: var(--t-caption); font-weight: var(--w-medium); font-variant-numeric: tabular-nums;
}
.badge.quiet { background: transparent; color: var(--fg-muted); border: 1px solid var(--line-strong); }

/* --- callouts ----------------------------------------------------------- */

.notice, .warn, .error, .gate, .card {
  padding: var(--s4); margin: 0 0 var(--s4); max-width: var(--measure);
  border: 1px solid var(--line); border-radius: var(--r-container); background: var(--panel);
}
.notice { background: var(--accent-soft); }
.warn { background: var(--warn-soft); }
.gate { background: var(--warn-soft); }
.error { background: var(--danger-soft); border-color: var(--danger); }
.notice > :last-child, .warn > :last-child, .error > :last-child,
.gate > :last-child, .card > :last-child { margin-bottom: 0; }
.gate h2 { margin-top: 0; }
.card h2 { margin: 0 0 var(--s2); font-size: var(--t-title); }

/* A statement that must not be softened — the residual copies in the erasure report. */
.residual-block { max-width: var(--measure); margin: 0 0 var(--s4); padding: var(--s4); border: 1px solid var(--line-strong); border-radius: var(--r-container); background: var(--panel); }
.residual-block h3 { margin-top: 0; }

/* --- tables ------------------------------------------------------------- */

/* Wide tables scroll inside their own box so the page body never scrolls sideways. */
.scroll {
  overflow-x: auto; margin: 0 0 var(--s4);
  border: 1px solid var(--line); border-radius: var(--r-container); background: var(--panel);
}
table { border-collapse: collapse; width: 100%; }
th, td { padding: var(--s2) var(--s3); text-align: left; vertical-align: top; border-bottom: 1px solid var(--line); }
thead th { font-size: var(--t-small); font-weight: var(--w-medium); color: var(--fg-muted); white-space: nowrap; }
tbody tr:last-child > * { border-bottom: 0; }
tbody tr:hover { background: var(--bg); }
.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.rank { text-align: right; font-family: var(--mono); font-size: var(--t-small); color: var(--fg-muted); font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }
td.detail { font-size: var(--t-small); }
td.detail div { max-width: 44ch; overflow-wrap: anywhere; }
.dense td, .dense th { padding: var(--s1) var(--s3); }
/* Set on the table rather than on the cell, so that everything inside a row — including the
 * monospace columns, which carry no size of their own — lands on the denser scale together. */
table.dense { font-size: var(--t-small); }

/* Empty states say what to do next, so they are prose and not a dash. */
td.empty { padding: var(--s6) var(--s3); color: var(--fg-muted); }
td.empty b { display: block; color: var(--fg); font-size: var(--t-body); margin-bottom: var(--s1); }
.empty-block { max-width: var(--measure); padding: var(--s6) 0; color: var(--fg-muted); }
.empty-block b { display: block; color: var(--fg); font-size: var(--t-body); margin-bottom: var(--s1); }

/* --- forms and controls -------------------------------------------------- */

form { margin: 0 0 var(--s4); }
label { display: block; margin: 0 0 var(--s3); font-size: var(--t-small); color: var(--fg-muted); }
label > input, label > select, label > textarea { display: block; margin-top: var(--s1); }
input[type=text], input[type=email], input[type=search], input[type=password], select, textarea {
  min-height: var(--s8); padding: var(--s1) var(--s2); min-width: 18rem; max-width: 100%;
  font-family: inherit; font-size: var(--t-body); color: var(--fg);
  background: var(--panel); border: 1px solid var(--line-strong); border-radius: var(--r-control);
}

/* Многострочный ввод. Единственное отличие от однострочного — то, что действительно другое:
 * высота задаётся содержимым (rows), поэтому min-height контрола здесь неуместен, а тянуть
 * можно только вниз: горизонтальное растягивание ломает колонку и меру строки. Моноширинный,
 * потому что сюда вставляют СТРУКТУРУ (реестр сотрудников по строкам, столбцы через табуляцию),
 * а в пропорциональном шрифте столбцы не выстраиваются и опечатку в разметке не видно. */
textarea {
  min-height: auto;
  width: 100%;
  resize: vertical;
  font-family: var(--mono);
  font-size: var(--t-small);
  line-height: 1.5;
}
input[readonly] { color: var(--fg-muted); background: var(--bg); }

/* Предпросмотр письма участникам — сырой текст того, что уедет в почту.
 *
 * pre-wrap, а не pre: в письме есть строки длиннее колонки (например, «Исполнители не
 * сопоставлены…»), и <pre> по умолчанию не переносит их вовсе — страница начинает ездить в бок.
 * Правило «широкое содержимое прокручивается внутри своей коробки, а не растягивает страницу»
 * здесь выполняется переносом: письмо — это текст, а не таблица, и терять его правый край нельзя.
 * Переносы строк при этом сохраняются: в текстовом письме они и есть вёрстка.
 *
 * Моноширинный и на панели — чтобы это читалось как «вот ровно те байты, что уйдут», а не как
 * ещё один блок вёрстки страницы, который можно принять за пересказ письма. */
pre.mail-body {
  max-width: var(--measure);
  margin: 0 0 var(--s3);
  padding: var(--s3);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-family: var(--mono);
  font-size: var(--t-small);
  line-height: 1.5;
  color: var(--fg);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-container);
}
/* UUIDs, directory paths and hot prompts are the longest unbroken strings on any page;
 * inside .scroll tables wrapping changes nothing, everywhere else it saves the layout. */
code { overflow-wrap: anywhere; }
input::placeholder { color: var(--fg-muted); opacity: 1; }
label.check { display: flex; align-items: flex-start; gap: var(--s2); font-size: var(--t-body); color: var(--fg); max-width: var(--measure); }
label.check input { margin: var(--s1) 0 0; accent-color: var(--accent-text); }

button {
  min-height: var(--s8); padding: var(--s1) var(--s3);
  font-family: inherit; font-size: var(--t-body); font-weight: var(--w-regular);
  color: var(--fg); background: var(--panel);
  border: 1px solid var(--line-strong); border-radius: var(--r-control); cursor: pointer;
}
button:hover { border-color: var(--fg-muted); }
/* One primary per view. */
button.primary { background: var(--accent-fill); border-color: var(--accent-fill); color: var(--accent-fg); font-weight: var(--w-bold); }
button.primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); }
/* Destructive: unmistakable, and deliberately not a filled slab competing for the click. */
button.danger { color: var(--danger-text); border-color: var(--danger); background: var(--panel); font-weight: var(--w-medium); }
button.danger:hover { background: var(--danger-soft); border-color: var(--danger); }
/* Reads as a link, but it is a real submit in a real form and therefore a real hit target:
 * "Выйти" is the only control in the persistent chrome, and at text height it was an 18px
 * target. The padding is horizontal-visible, vertical-invisible. */
button.link {
  min-height: var(--s8); padding: 0 var(--s1); border: 0; background: none;
  color: var(--accent-text); font-size: var(--t-small);
  text-decoration: underline; text-underline-offset: 2px;
}
form.inline { display: inline; margin: 0; }

.filters { display: flex; flex-wrap: wrap; gap: var(--s3) var(--s4); align-items: flex-end; }
.filters label { margin: 0; }
.actions { display: flex; flex-wrap: wrap; gap: var(--s3); align-items: center; }
.actions form { display: flex; gap: var(--s2); align-items: center; margin: 0; }
.actions input[type=text] { display: inline-block; margin: 0; min-width: 11rem; }

/* Visible focus everywhere. Nothing in this file ever suppresses an outline. */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-control); }

/* Motion only to soften a state change, and only if the reader wants it. */
@media (prefers-reduced-motion: no-preference) {
  a, button, input, select, tbody tr { transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease; }
}

/* --- meta lists, quotes, tags ------------------------------------------- */

dl.meta { display: grid; grid-template-columns: minmax(0, 13rem) minmax(0, 1fr); gap: var(--s2) var(--s4); margin: 0 0 var(--s6); max-width: 60rem; }
dl.meta dt { font-size: var(--t-small); color: var(--fg-muted); }
dl.meta dd { margin: 0; }
@media (max-width: 40rem) {
  dl.meta { grid-template-columns: 1fr; gap: 0; }
  dl.meta dd { margin-bottom: var(--s3); }
}

/* The verbatim citation an approval is judged against. Quiet frame, full-size text: it is
 * evidence, not an aside. */
blockquote { margin: var(--s3) 0; padding-left: var(--s3); border-left: 2px solid var(--line-strong); max-width: var(--measure); }
blockquote p { margin: 0; }
.source-ref { display: block; margin-top: var(--s1); font-family: var(--mono); font-size: var(--t-caption); color: var(--fg-muted); }

.tag {
  display: inline-block; padding: 0 var(--s1); border: 1px solid var(--line-strong);
  border-radius: var(--r-control); font-size: var(--t-caption); color: var(--fg-muted);
  white-space: nowrap; vertical-align: baseline;
}
.tag.hot { background: var(--accent-soft); color: var(--fg); }

ul.plain { list-style: none; margin: 0 0 var(--s4); padding: 0; max-width: var(--measure); }
ul.plain li { padding: var(--s1) 0; }
ul.residual { margin: 0; padding-left: var(--s6); max-width: var(--measure); }
ul.residual li { margin: 0 0 var(--s2); }

/* --- transcript --------------------------------------------------------- */

/* Not a table: long prose in a table cell has no measure. The timestamp sits in a gutter
 * and the speaker label is one size down — both are scaffolding, present but quiet. */
.transcript { list-style: none; margin: 0 0 var(--s4); padding: 0; }
.transcript li { display: grid; grid-template-columns: 3.5rem minmax(0, 1fr); gap: 0 var(--s4); padding: var(--s3) 0; border-top: 1px solid var(--line); }
.transcript .ts { font-family: var(--mono); font-size: var(--t-small); color: var(--fg-muted); font-variant-numeric: tabular-nums; }
.transcript .speaker { font-size: var(--t-small); color: var(--fg-muted); margin: 0 0 var(--s1); }
.transcript .line { margin: 0; max-width: var(--measure); }
.transcript li.empty-block { display: block; border-top: 0; }
/* An unattributed segment is a product decision (ADR-005), so it is marked rather than
 * left blank: the dashed rule makes the absence legible without colour. */
.unattributed { border-bottom: 1px dashed var(--line-strong); }

/* --- states and paging --------------------------------------------------- */

/* The label is always the Russian word for the state; the colour only reinforces it. */
.state { display: inline-block; font-size: var(--t-small); white-space: nowrap; }
.state-failed { color: var(--danger-text); font-weight: var(--w-medium); }
.state-skipped { color: var(--fg-muted); }
.state-ready, .state-delivered, .state-done { color: var(--ok-text); }
/* A per-row consequence worth reading, in the flow rather than in a banner. The word is
 * always present — "Внимание", "Не удалён" — so the colour is reinforcement, not the
 * message. */
.flag { display: block; font-size: var(--t-small); color: var(--warn-text); }
/* A calendar-born title can be a URL; it wraps inside its own cell instead of dragging
 * the status columns past the viewport. */
td.title { max-width: 28rem; overflow-wrap: anywhere; }
.flag.bad { color: var(--danger-text); }
/* The neutral variant has to be explicit: `.flag` is declared after `.muted`, so `class="flag
 * muted"` was silently painting an explanatory line — the reason a meeting was skipped — in
 * the amber that is supposed to mean "внимание", and an amber that appears on ordinary facts
 * stops being read. */
.flag.muted { color: var(--fg-muted); }
.residual-block > :last-child { margin-bottom: 0; }

/* align-items: baseline because two of the three children are now a <button> inside a
   <form> — the pager posts the page number so a transcript read keeps its justification —
   and a flex item that is a form box otherwise sits above the text beside it. */
.pager { display: flex; align-items: baseline; gap: var(--s6);
         margin: var(--s4) 0 0; font-size: var(--t-small); }

.site-footer { border-top: 1px solid var(--line); }
.site-footer .wrap {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3) var(--s6);
  padding-top: var(--s4); padding-bottom: var(--s8);
}
.site-footer p { max-width: var(--measure); margin: 0; font-size: var(--t-small); color: var(--fg-muted); }

/* The corporate mark. Scaled as ONE image — width and height are set together in the 5.425:1
 * ratio the artwork actually has, never independently, which is the failure the guidelines call
 * out by name. `clear space = width / 15` is where the padding below comes from: 141 / 15 ≈ 9px,
 * which rounds to the 8px step of the space scale. */
/* Переключатель цвета: сам знак сервиса, в подвале, прижат вправо. Намеренно тихий — это
 * настройка внешности, а не действие над данными, и она не должна конкурировать с кнопками на
 * странице. Приглушён и оживает при наведении и с клавиатуры; размер знака равен строке текста
 * рядом, поэтому подвал не «пухнет» от его появления. */
.accent-toggle {
  appearance: none;
  margin-left: auto;
  padding: var(--s1);
  border: 1px solid transparent;
  border-radius: var(--r-control);
  background: transparent;
  line-height: 0;
  cursor: pointer;
  opacity: 0.55;
  transition: opacity 120ms ease, border-color 120ms ease;
}

.accent-toggle:hover,
.accent-toggle:focus-visible { opacity: 1; border-color: var(--line); }
.accent-toggle img { display: block; border-radius: 4px; }

/* Какой из двух знаков показать, решает CSS, а не скрипт: знак верен уже в первом кадре,
 * ещё до того, как отработает accent.js. */
.accent-toggle .mark-blue { display: none; }
:root[data-accent="blue"] .accent-toggle .mark-red { display: none; }
:root[data-accent="blue"] .accent-toggle .mark-blue { display: block; }

.appsu-mark { display: block; flex: 0 0 auto; padding: var(--s2) 0; }
.appsu-mark img { display: block; height: auto; max-width: 100%; }
.appsu-mark--title { margin: 0 auto var(--s8); padding: var(--s3) 0; }

/* --- sign-in ------------------------------------------------------------ */

.login { max-width: 27rem; margin: 0 auto; padding: var(--s12) var(--s6); }
.login h1 { margin-bottom: var(--s4); }
.login .notice, .login .warn, .login .error { max-width: none; }

/* --- Download link and numbered steps (ADR-041) ---------------------------- */
/*
 * A download is a GET, so it is an anchor and not a form button — but it is the primary action on
 * its page and should look like one. Reuses button.primary's tokens instead of introducing a second
 * accent: one accent that means "the thing to click" is the whole point of having one.
 */
a.button {
  display: inline-block;
  padding: var(--s2) var(--s4);
  border: 1px solid var(--accent);
  border-radius: var(--r-control);
  background: var(--accent-fill);
  color: var(--accent-fg);
  font-weight: var(--w-medium);
  text-decoration: none;
}

a.button:hover {
  background: var(--accent-strong);
  border-color: var(--accent-strong);
}

/* Steps are read with chrome://extensions open in the next tab, so they get room to be scanned. */
ol.steps {
  margin: var(--s3) 0;
  padding-left: var(--s6);
}

ol.steps li {
  margin: var(--s2) 0;
}

/* --- Get-the-extension link in the top bar (ADR-041) ----------------------- */
/*
 * An outlined link, not a filled button. It sits on every page next to the identity, and a filled
 * accent there would compete with whatever the primary action of that page is — approving an item,
 * saving a term. Outlined reads as available rather than as "do this now".
 */
.get-extension {
  padding: 2px var(--s2);
  border: 1px solid var(--accent);
  border-radius: var(--r-control);
  color: var(--accent-text);
  font-size: var(--t-small);
  text-decoration: none;
  white-space: nowrap;
}

.get-extension:hover {
  background: var(--accent-fill);
  color: var(--accent-fg);
}

/* --- Q&A over a finished meeting (ADR-046) --------------------------------- */
/*
 * The answer keeps its line breaks (pre-line): a clipped answer arrives with a warning
 * paragraph stapled on top, and collapsing the blank line between them would fuse the
 * warning into the answer text it is warning about.
 */
form.ask {
  display: flex;
  /* Wraps on phones: the 18rem input plus the button never fit a 375px row. */
  flex-wrap: wrap;
  gap: var(--s2);
  align-items: flex-end;
  max-width: var(--measure);
}

form.ask label {
  flex: 1;
  margin: 0;
}

.qa-item {
  border-top: 1px solid var(--line);
  padding: var(--s3) 0;
  max-width: var(--measure);
}

.qa-item .qa-question {
  margin: 0 0 var(--s2);
}

.qa-item .qa-answer {
  margin: 0 0 var(--s2);
  white-space: pre-line;
}

form.ask input[type=text] {
  width: 100%;
  min-width: 0;
}

/* Search results (#28). The snippet is the payload; the metadata line is scaffolding. */
.results { display: flex; flex-direction: column; gap: var(--s4); margin-top: var(--s3); }
.result { border-top: 1px solid var(--line); padding-top: var(--s3); }
.result-head { margin: 0 0 var(--s1); }
.snippet { margin: 0; max-width: var(--measure); color: var(--fg); overflow-wrap: anywhere; }
.snippet mark {
  background: var(--warn-soft); color: var(--fg);
  padding: 0 2px; border-radius: 3px; font-weight: var(--w-medium);
}

/* The approvals queue (#29): meeting group headers and the collapsed stale section. */
.queue-meeting { margin: var(--s6) 0 var(--s2); font-size: var(--t-body); }
.queue-meeting a { color: var(--fg); }
.stale-block { margin-top: var(--s6); border-top: 1px solid var(--line); padding-top: var(--s3); }
.stale-block > summary { cursor: pointer; color: var(--fg-muted); font-size: var(--t-small); }
.stale-block[open] > summary { margin-bottom: var(--s2); }
