/*  AXIS Design System – Components
 *  v0.9.0, Requires axis-tokens.css. Every value flows from a --axis-* token.
 *  Opt-in class layer: use these classes, or read the tokens and style your own.
 *
 *  The voice: content is IBM Plex Sans; everything the system says about
 *  itself – labels, table headers, numerals, timestamps, the wordmark – is
 *  IBM Plex Mono. The mono/sans switch is semantic: data versus prose.
 * ------------------------------------------------------------------------- */

/* ═══ Base ══════════════════════════════════════════════════════════════════ */

/* Every sized component owns its box model. The class layer must not depend on
   the consumer having a reset – without this, `height: 36px` plus a 1px border
   renders 38px anywhere Tailwind preflight (or similar) is absent. Scoped to the
   classes rather than `*` so dropping this file into a page changes nothing else. */
.axis, .axis-app, .axis-app *, .axis *,
.axis-btn, .axis-input, .axis-select, .axis-textarea, .axis-card, .axis-kpi,
.axis-chip, .axis-pill, .axis-badge, .axis-tab, .axis-nav-link, .axis-sidebar,
.axis-content, .axis-dialog, .axis-toast, .axis-topbar, .axis-instrument,
.axis-stack, .axis-row, .axis-bar, .axis-cluster, .axis-grid, .axis-section {
  box-sizing: border-box;
}

/* The canvas is a drafting plane: a faint 24px grid with a node at every
   fourth intersection. Printed on paper in the light theme, etched into the
   board in the dark one. Cards are opaque, so content never fights it. */
.axis, .axis-app {
  background-color: var(--axis-canvas);
  background-image:
    radial-gradient(circle, var(--axis-grid-node) 1px, transparent 2px),
    linear-gradient(to right, var(--axis-grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--axis-grid-line-2) 1px, transparent 1px);
  background-size:
    var(--axis-grid-node-step) var(--axis-grid-node-step),
    var(--axis-grid-step) var(--axis-grid-step),
    var(--axis-grid-step) var(--axis-grid-step);
  background-position: var(--axis-space-3) var(--axis-space-3), 0 0, 0 0;
  color: var(--axis-ink);
  font-family: var(--axis-font-sans);
  font-size: var(--axis-text-base);
  line-height: var(--axis-leading);
  /* No global letter-spacing. Tracking is per-role – a global -0.01em landed on
     12px table text, where negative tracking hurts legibility (Cyrillic most). */
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
/* A flat variant for panels that need the app colours without the texture. */
.axis--plain { background-image: none; }

.axis :focus-visible, .axis-app :focus-visible {
  outline: none;
  box-shadow: var(--axis-ring);
  border-radius: var(--axis-radius-xs);
}

/* Selection is an interface surface too. */
.axis ::selection, .axis-app ::selection { background: var(--axis-selection); }

/* The scrollbar is part of the instrument: thin, square, in the line colour. */
.axis, .axis-app { scrollbar-width: thin; scrollbar-color: var(--axis-line-strong) transparent; }
.axis ::-webkit-scrollbar, .axis-app ::-webkit-scrollbar { width: 8px; height: 8px; }
.axis ::-webkit-scrollbar-thumb, .axis-app ::-webkit-scrollbar-thumb {
  background: var(--axis-line-strong);
  border-radius: var(--axis-radius-xs);
}
.axis ::-webkit-scrollbar-track, .axis-app ::-webkit-scrollbar-track { background: transparent; }

/* Numbers, IDs, timestamps – the data face. Zeros are slashed everywhere data
   is data: 0 must never be mistakable for О, in either alphabet. */
.axis-mono, .axis-num {
  font-family: var(--axis-font-mono);
  font-variant-numeric: proportional-nums;
  font-feature-settings: "zero" 1;
}
/* Opt in per-column when a numeric table must align strictly. */
.axis-tnum { font-variant-numeric: tabular-nums; font-feature-settings: "zero" 1; }

/* ═══ Typography ════════════════════════════════════════════════════════════ */

.axis-h1 {
  font-size: var(--axis-text-xl); font-weight: var(--axis-w-semibold);
  letter-spacing: var(--axis-tracking-tight); line-height: var(--axis-leading-tight);
  text-wrap: balance; margin: 0;
}
.axis-h2 {
  font-size: var(--axis-text-lg); font-weight: var(--axis-w-semibold);
  letter-spacing: var(--axis-tracking-tight); line-height: var(--axis-leading-tight); margin: 0;
}
.axis-h3 {
  font-size: var(--axis-text-md); font-weight: var(--axis-w-semibold);
  letter-spacing: var(--axis-tracking-snug); line-height: var(--axis-leading-tight); margin: 0;
}
.axis-lead { font-size: var(--axis-text-sm); color: var(--axis-muted); line-height: var(--axis-leading); margin: 0; }
.axis-muted { color: var(--axis-muted); }
.axis-prose { max-width: var(--axis-measure); }

/* ── Links ────────────────────────────────────────────────────
   Underlined by default: in a console full of coloured status text, colour
   alone is not a reliable affordance for "this is clickable". */
.axis-link, .axis-app a:not(.axis-btn):not(.axis-nav-link):not(.axis-tab):not(.axis-card--link):not([data-sidebar="menu-button"]) {
  color: var(--axis-link);
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--axis-link) 35%, transparent);
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  border-radius: var(--axis-radius-xs);
  transition: text-decoration-color var(--axis-dur-fast) var(--axis-ease),
              color var(--axis-dur-fast) var(--axis-ease);
}
.axis-link:hover, .axis-app a:not(.axis-btn):not(.axis-nav-link):not(.axis-tab):not(.axis-card--link):not([data-sidebar="menu-button"]):hover {
  text-decoration-color: currentColor;
}
/* An inline action inside body copy – reads as a verb, not a destination. */
.axis-link--action { color: var(--axis-brand); font-weight: var(--axis-w-medium); }
/* A link that must not look like one until hovered (dense table cells). */
.axis-link--quiet { color: inherit; text-decoration-color: transparent; }
.axis-link--quiet:hover { color: var(--axis-link); }
a { color: var(--axis-link); }

/* ── Labels – two registers ──────────────────────────────────
   .axis-label is the FORM register: sentence case, sans, for captions tied to
   controls. Cyrillic in caps loses the word shapes a reader scans by; a field
   label is a word, so it stays a word. It carries the caption role of
   ui-foundation §1 (12/400) and is told from the hint under the same control by
   colour, not by a sixth size-and-weight pair: label on --axis-ink-2, hint on
   --axis-muted. */
.axis-label {
  display: block; font-size: var(--axis-text-xs); font-weight: var(--axis-w-regular);
  letter-spacing: var(--axis-tracking-micro);
  line-height: var(--axis-leading-snug); color: var(--axis-ink-2);
}
/* .axis-tele is the TELEMETRY register: mono caps with a wide track, for what
   the system says about itself – section eyebrows, table headers, KPI captions,
   the screen passport. Keep these labels short (one-two words) and rationed:
   at most two bracketed zone marks per screen. Zone brackets are typed by the
   author – `[ эфир ]` – the class only sets the voice. */
.axis-tele {
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-3xs);
  font-weight: var(--axis-w-medium);
  letter-spacing: var(--axis-tracking-label);
  text-transform: uppercase;
  line-height: var(--axis-leading-snug);
  color: var(--axis-muted);
  font-feature-settings: "zero" 1;
}
/* Sans caps stays opt-in for short Latin words. */
.axis-label--caps, .axis-caps { text-transform: uppercase; letter-spacing: var(--axis-tracking-wide); }

/* ═══ Layout primitives ═════════════════════════════════════════════════════
   These exist so a screen never hand-rolls flexbox again. Reach for a
   primitive; do not write inline `display:flex; gap:…`. Spacing defaults to a
   rhythm tier and is overridden by setting --gap on the element. */

.axis-stack   { display: flex; flex-direction: column; gap: var(--gap, var(--axis-gap-group)); min-width: 0; }
.axis-row     { display: flex; flex-direction: row; align-items: center; gap: var(--gap, var(--axis-gap-tight)); min-width: 0; }
.axis-row--top{ align-items: flex-start; }
.axis-row--baseline { align-items: baseline; }
.axis-row--wrap { flex-wrap: wrap; }
/* Pushes everything after it to the far edge – replaces `<span style="flex:1"/>`. */
.axis-spacer  { flex: 1 1 auto; min-width: 0; }
/* Header row: title block left, actions right, wraps safely on narrow screens. */
.axis-bar     { display: flex; align-items: center; justify-content: space-between;
                gap: var(--gap, var(--axis-gap-group)); flex-wrap: wrap; }
/* Loose collection of chips/pills/buttons. */
.axis-cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap, var(--axis-space-2)); }
/* Responsive card grid without a media query. */
.axis-grid    { display: grid; gap: var(--gap, var(--axis-gap-group));
                grid-template-columns: repeat(auto-fit, minmax(var(--col, 240px), 1fr)); }
.axis-section { display: flex; flex-direction: column; gap: var(--axis-gap-section); }
.axis-divider { height: 1px; background: var(--axis-line); border: 0; margin: 0; }
/* In-page anchors: reserve the topbar band so a jumped-to heading lands clear. */
:root:has(.axis-app), :root:has(.axis) { scroll-padding-top: var(--axis-scroll-offset); }
.axis-app [id], .axis [id] { scroll-margin-top: var(--axis-scroll-offset); }

/* ═══ Icons ═════════════════════════════════════════════════════════════════ */

.axis-icon-xs { width: var(--axis-icon-xs); height: var(--axis-icon-xs); flex: 0 0 auto; }
.axis-icon-sm { width: var(--axis-icon-sm); height: var(--axis-icon-sm); flex: 0 0 auto; }
.axis-icon    { width: var(--axis-icon);    height: var(--axis-icon);    flex: 0 0 auto; }
.axis-icon-lg { width: var(--axis-icon-lg); height: var(--axis-icon-lg); flex: 0 0 auto; }

/* ═══ App shell ═════════════════════════════════════════════════════════════ */

/* Прокрутку держит страница, и она одна (ui-foundation §8). Содержимое своей
   прокрутки не заводит: две прокрутки отбирают друг у друга колесо, а пара
   `min-height: 100dvh` на оболочке и `overflow-y: auto` на содержимом наводит
   вторую полосу на документ, стоит содержимому подрасти. Шапка и рельса при
   этом остаются на месте липкостью, а не своим скроллом. */
.axis-app {
  display: grid;
  grid-template-columns: var(--axis-rail-w) minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  min-height: 100dvh;
}
.axis-topbar {
  grid-column: 1 / -1;
  position: sticky; top: 0; z-index: var(--axis-z-sticky);
  display: flex; align-items: center;
  gap: var(--axis-gap-group);
  padding: var(--axis-space-2) var(--axis-space-4);
  background: var(--axis-surface);
  border-bottom: 1px solid var(--axis-line);
}
.axis-sidebar {
  grid-row: 2;
  position: sticky; top: var(--axis-topbar-h); align-self: start;
  max-height: calc(100dvh - var(--axis-topbar-h));
  background: var(--axis-rail-bg);
  border-right: 1px solid var(--axis-line);
  padding: var(--axis-space-3) var(--axis-space-2);
  display: flex; flex-direction: column; gap: var(--axis-space-1);
  overflow-y: auto;
}
.axis-content {
  grid-row: 2;
  padding: var(--axis-content-pad-y) var(--axis-content-pad-x);
  display: flex; flex-direction: column; gap: var(--axis-gap-section);
  min-width: 0;
}
/* Жанр, занимающий всю высоту окна (инбокс, лента с панелями): оболочка встаёт
   ровно в окно и гасит прокрутку документа, а прокрутка переезжает в панели,
   которым она и принадлежит (`docs/patterns/inbox.md`). Владелец по-прежнему
   один: документ при этом не прокручивается вовсе. */
.axis-app--fixed { height: 100dvh; overflow: hidden; }
.axis-app--fixed .axis-content { overflow-y: auto; min-height: 0; }
/* Secondary rail: the page's own list (conversations, campaigns). */
.axis-subrail {
  width: var(--axis-subrail-w); flex: 0 0 auto;
  background: var(--axis-subrail-bg);
  border-right: 1px solid var(--axis-line);
  overflow-y: auto;
  display: flex; flex-direction: column;
}
/* Порог свёртывания рельсы это 1024 (ui-foundation §9): полоса 940-1024 жила
   по правилу, которого в каноне нет. */
@media (max-width: 1023px) {
  .axis-app { grid-template-columns: minmax(0, 1fr); }
  .axis-sidebar { display: none; }
}
/* A screen with no navigation of its own - login, an adapter's settings page.
   Without this the grid keeps the rail column and the content stands where the
   missing .axis-sidebar would be. The frame is centred at --axis-page-w, and the
   passport keeps its place at the bottom of the column. */
.axis-app--norail { grid-template-columns: minmax(0, 1fr); }
.axis-app--norail > .axis-content {
  width: 100%;
  max-width: var(--axis-page-w);
  margin-inline: auto;
  min-height: 0;
}
/* A shell with two rails: the app rail plus the rail of one entity, whose state
   has to stay visible on every page of that entity (docs/ux-foundation.md §4.2).
   Below the threshold the entity rail becomes tabs inside the content, so the
   third column is not carried onto a narrow screen (§4.6). */
.axis-app--subrail { grid-template-columns: var(--axis-rail-w) var(--axis-subrail-w) minmax(0, 1fr); }
.axis-app--subrail > .axis-subrail { grid-row: 2; }
/* Рельса ушла, рельса сущности остаётся: раскладка «список и работа» живёт до
   768 (ui-foundation §9), и колонка скрытой рельсы не остаётся пустой. */
@media (max-width: 1023px) {
  .axis-app--subrail { grid-template-columns: var(--axis-subrail-w) minmax(0, 1fr); }
}
@media (max-width: 767px) {
  .axis-app--subrail { grid-template-columns: minmax(0, 1fr); }
  .axis-app--subrail > .axis-subrail { display: none; }
}

/* ── Wordmark – the living dot ───────────────────────────────
   `axis.` set in mono. The dot is the system health indicator: it holds the
   live colour while the line is up, amber under degradation, red on outage.
   A logo that cannot lie. Markup: <span class="axis-brandmark">axis<i
   class="axis-brandmark-dot"></i></span> (the dot element renders "."). */
.axis-brandmark {
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-md);
  font-weight: var(--axis-w-semibold);
  letter-spacing: var(--axis-tracking-micro);
  color: var(--axis-ink);
  line-height: var(--axis-leading-none);
  user-select: none;
}
.axis-brandmark-dot { font-style: normal; color: var(--axis-live); text-shadow: var(--axis-glow-live); }
.axis-brandmark-dot::before { content: "."; }
.axis-brandmark-dot.is-degraded { color: var(--axis-warn); text-shadow: none; }
.axis-brandmark-dot.is-down     { color: var(--axis-danger); text-shadow: none; }
/* No source of health at all. A page that has no health feed either lights the
   live dot and lies, or drops the mark and loses the wordmark; neither is an
   answer, so absence gets its own state - the dot in the line colour, no glow. */
.axis-brandmark-dot.is-unknown  { color: var(--axis-line-strong); text-shadow: none; }

/* ── Navigation ─────────────────────────────────────────────── */
.axis-nav { display: flex; flex-direction: column; gap: var(--axis-space-1); }
.axis-nav-group { display: flex; flex-direction: column; gap: var(--axis-space-1); }
.axis-nav-grouplabel { padding: var(--axis-space-2) var(--axis-space-2) 0; }
.axis-nav-link {
  display: flex; align-items: center; gap: var(--axis-space-2);
  height: var(--axis-rail-item-h);
  padding: 0 var(--axis-space-2);
  border-radius: var(--axis-rail-item-radius);
  border-left: var(--axis-border-strong) solid transparent;
  color: var(--axis-ink-2);
  font-size: var(--axis-text-sm);
  text-decoration: none;
  transition: background-color var(--axis-dur-fast) var(--axis-ease),
              color var(--axis-dur-fast) var(--axis-ease);
}
.axis-nav-link:hover { background: var(--axis-surface-3); color: var(--axis-ink); }
/* Включённое состояние держится заливкой, полосой и цветом (ux-foundation
   §4.1). Вес при этом не двигается: сменившийся вес читается прибором набора
   как ещё одна пара «размер, вес», и на экране с рельсой, вкладками и формой
   порог пяти ролей §1 становится невыполнимым. */
.axis-nav-link.is-active, .axis-nav-link[aria-current="page"] {
  background: var(--axis-brand-soft);
  border-left-color: var(--axis-brand);
  color: var(--axis-brand);
  text-shadow: var(--axis-glow-brand);
}
/* Unread / pending count. The guest accent's one legal home on the rail. */
.axis-count {
  margin-left: auto;
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-3xs);
  font-weight: var(--axis-w-semibold);
  font-feature-settings: "zero" 1;
  background: var(--axis-accent-soft);
  color: var(--axis-accent-strong);
  border-radius: var(--axis-radius-pill);
  padding: 0 var(--axis-space-2);
  line-height: 16px;
}

/* ═══ Shell over shadcn Sidebar ═════════════════════════════════════════════
   The rail is not written twice. Products stand on shadcn's Sidebar, and this
   layer dresses it: .axis-shell goes on the element shadcn marks
   data-slot="sidebar-wrapper" (SidebarProvider), and every rule below reaches
   shadcn's own data-slot / data-sidebar attributes instead of copying its
   markup. Geometry stays shadcn's - fixed rail, gap column, inset - and the
   system sets the widths through --sidebar-* and the look through the tokens.
   A page with neither React nor Tailwind repeats the same attributes and takes
   the geometry from .axis-app / .axis-sidebar / .axis-content: that is what
   preview/shell.html does, and it is the proof the slots hold all three
   products. Slots, states and the assembly recipe: docs/patterns/shell.md. */

.axis-shell {
  --sidebar:                    var(--axis-rail-bg);
  --sidebar-foreground:         var(--axis-ink);
  --sidebar-primary:            var(--axis-brand-fill);
  --sidebar-primary-foreground: var(--axis-brand-fill-contrast);
  --sidebar-accent:             var(--axis-surface-3);
  --sidebar-accent-foreground:  var(--axis-ink);
  --sidebar-border:             var(--axis-line);
  --sidebar-ring:               var(--axis-brand);
  --sidebar-width:              var(--axis-rail-w);
  --sidebar-width-icon:         var(--axis-rail-w-narrow);
  --sidebar-width-mobile:       var(--axis-rail-w-mobile);
}

/* The rail's own surface, docked and as a panel. */
.axis-shell [data-slot="sidebar-inner"],
.axis-shell [data-slot="sidebar"][data-mobile="true"] {
  background: var(--axis-rail-bg);
  color: var(--axis-ink);
}
.axis-shell [data-slot="sidebar-header"] {
  display: flex; flex-direction: column; gap: var(--axis-space-2);
  padding: var(--axis-space-3) var(--axis-space-2);
  min-width: 0; overflow-x: hidden;
  flex: 0 0 auto;
}
/* Прокрутка у оболочки одна, и она вертикальная (ui-foundation.md §8):
   содержимое рельса никогда не шире самого рельса. */
.axis-shell [data-slot="sidebar-content"] {
  display: flex; flex-direction: column; gap: var(--axis-space-1);
  padding: 0 var(--axis-space-2);
  overflow-y: auto; overflow-x: hidden;
  flex: 1 1 auto; min-width: 0;
}
.axis-shell [data-slot="sidebar-footer"] {
  display: flex; flex-direction: column; gap: var(--axis-space-2);
  padding: var(--axis-space-2);
  border-top: 1px solid var(--axis-line);
  min-width: 0; overflow-x: hidden;
  flex: 0 0 auto;
}
/* Заголовок группы в регистре телеметрии: рельса называет свои группы так же,
   как паспорт называет свои сегменты (brand-guidelines.md §7). */
.axis-shell [data-sidebar="group-label"] {
  display: flex; align-items: center;
  height: var(--axis-control);
  padding: 0 var(--axis-space-2);
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-3xs);
  letter-spacing: var(--axis-tracking-label);
  text-transform: uppercase;
  color: var(--axis-muted);
}
.axis-shell [data-sidebar="separator"] {
  height: 1px; width: auto;
  margin: var(--axis-space-2);
  background: var(--axis-line);
  border: 0;
}
.axis-shell [data-sidebar="menu"] {
  display: flex; flex-direction: column; gap: var(--axis-space-1);
  list-style: none; margin: 0; padding: 0;
  min-width: 0;
}
.axis-shell [data-sidebar="group"] { min-width: 0; }
.axis-shell [data-sidebar="menu-item"] { position: relative; }
.axis-shell [data-sidebar="menu-button"] {
  display: flex; align-items: center; gap: var(--axis-space-2);
  width: 100%;
  height: var(--axis-rail-item-h);
  padding: 0 var(--axis-space-2);
  border: 0;
  border-left: var(--axis-border-strong) solid transparent;
  border-radius: var(--axis-rail-item-radius);
  background: none;
  color: var(--axis-ink-2);
  font-family: var(--axis-font-sans);
  font-size: var(--axis-text-sm);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--axis-dur-fast) var(--axis-ease),
              color var(--axis-dur-fast) var(--axis-ease);
}
/* Значок рядом со словом, а не вместо него; 20px из спрайта
   assets/axis-icons.svg. Подпись не подчёркивается ни в одном состоянии:
   подчёркнутая читается как ссылка в тексте, а пустой квадрат вместо значка
   читается как переключатель. */
.axis-shell [data-sidebar="menu-button"] > svg {
  width: var(--axis-icon); height: var(--axis-icon); flex: 0 0 auto;
}
.axis-shell [data-sidebar="menu-button"],
.axis-shell [data-sidebar="menu-button"]:hover { text-decoration: none; }
.axis-shell [data-sidebar="menu-button"] > span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.axis-shell [data-sidebar="menu-button"]:hover {
  background: var(--axis-surface-3); color: var(--axis-ink);
}
/* Активность читается не одним цветом (docs/ux-foundation.md §4.1): заливка,
   цвет и форма отметки - полоса у левого края. Вес не двигается: сменившийся
   вес читается прибором набора как ещё одна пара «размер, вес»
   (ui-foundation §1). Механика отметки одна на поверхность, поэтому та же
   отметка стоит на .axis-nav-link: страница без shadcn не расходится с рельсой
   продукта. */
.axis-shell [data-sidebar="menu-button"][data-active="true"],
.axis-shell [data-sidebar="menu-button"][aria-current="page"] {
  background: var(--axis-brand-soft);
  border-left-color: var(--axis-brand);
  color: var(--axis-brand);
}
/* Пункт первого уровня под открытой рельсой сущности: приглушённая отметка,
   как крошка, потому что активная отметка на экране одна (§4.3). */
.axis-shell [data-sidebar="menu-button"][data-active="crumb"] {
  background: var(--axis-surface-3);
  border-left-color: var(--axis-line-strong);
  color: var(--axis-ink-2);
}
/* Бейдж пункта: одно число тем же знаком, что счётчик списка за дверью. Янтарь
   гостит на непрочитанном; спокойный тон для числа, по которому не бегут. */
.axis-shell [data-sidebar="menu-badge"] {
  position: absolute; right: var(--axis-space-2); top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-3xs);
  font-weight: var(--axis-w-semibold);
  font-feature-settings: "zero" 1;
  background: var(--axis-accent-soft);
  color: var(--axis-accent-strong);
  border-radius: var(--axis-radius-pill);
  padding: 0 var(--axis-space-2);
  line-height: 16px;
}
.axis-shell [data-sidebar="menu-badge"][data-tone="calm"] {
  background: var(--axis-chip);
  color: var(--axis-muted);
}
.axis-shell [data-sidebar="rail"] { background: transparent; border: 0; }
/* Короткая строка данных в рельсе не переносится: число не разлучается
   со своей единицей, а текстовое междустрочное в узкой колонке читается как
   дыра. Междустрочное берётся ролью «подпись» (ui-foundation.md §1). */
.axis-shell [data-slot="sidebar-header"] > .axis-hint,
.axis-shell [data-slot="sidebar-footer"] > .axis-hint {
  line-height: var(--axis-leading-snug);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Часть шапки и подвала, которая в 64px не влезает, помечается, а не
   обрезается: обрезанное слово читается как поломка. Пара data-collapse
   держит две подписи одной вещи: полное имя и знак. */
.axis-shell [data-collapse="show"] { display: none; }
/* Слоты внутри .axis-sidebar: страница без Tailwind берёт геометрию рамки у
   системы, а раскладку рельса у слотов, поэтому поля отдаются слотам. */
.axis-shell .axis-sidebar:has(> [data-slot="sidebar-inner"]) { padding: 0; }
.axis-shell .axis-sidebar > [data-slot="sidebar-inner"] {
  display: flex; flex-direction: column;
  flex: 1 1 auto; min-height: 0; width: 100%;
}
/* Свёртывание рельсы это смена состояния, а не движение: канон разрешает
   переход по ширине одной заливке полосы (docs/ui-foundation.md §14.2), поэтому
   ширина меняется мгновенно. Двигается только панель узкого экрана, и двигается
   сдвигом; уход быстрее прихода. */
.axis-shell [data-slot="sidebar-gap"],
.axis-shell [data-slot="sidebar-container"] { transition-duration: 0s; }
.axis-shell [data-slot="sidebar"][data-mobile="true"] {
  transition: transform var(--axis-dur-slow) var(--axis-ease);
}
.axis-shell [data-slot="sidebar"][data-mobile="true"][data-state="closed"] {
  transform: translateX(-100%);
  transition-duration: var(--axis-dur-fast);
}

/* Свёрнутая рельса: подпись уезжает в подсказку. Правило живёт только от 768 -
   ниже этого порога экран показывает слова, а не значки (ux-foundation.md
   §4.6), и пункт получает цель касания. */
@media (min-width: 768px) {
  .axis-shell.axis-app:has(> [data-collapsible="icon"]) {
    grid-template-columns: var(--axis-rail-w-narrow) minmax(0, 1fr);
  }
  .axis-shell.axis-app--subrail:has(> [data-collapsible="icon"]) {
    grid-template-columns: var(--axis-rail-w-narrow) var(--axis-subrail-w) minmax(0, 1fr);
  }
  .axis-shell [data-collapsible="icon"] [data-sidebar="menu-button"] > span,
  .axis-shell [data-collapsible="icon"] [data-sidebar="menu-badge"],
  .axis-shell [data-collapsible="icon"] [data-sidebar="group-label"] > span { display: none; }
  .axis-shell [data-collapsible="icon"] [data-sidebar="menu-button"] { justify-content: center; }
  .axis-shell [data-collapsible="icon"] [data-sidebar="group-label"] { justify-content: center; }
  .axis-shell [data-collapsible="icon"] [data-collapse="hide"] { display: none; }
  .axis-shell [data-collapsible="icon"] [data-collapse="show"] { display: inline-flex; }
  .axis-shell [data-collapsible="icon"] [data-slot="sidebar-header"],
  .axis-shell [data-collapsible="icon"] [data-slot="sidebar-footer"] { align-items: center; }
}
@media (max-width: 767px) {
  .axis-shell [data-sidebar="menu-button"] { height: var(--axis-control-lg); }
}

/* ── Пульс: верхняя строка вопросов дня ─────────────────────────────────────
   Постоянное место ответа, который нужен без открытия экрана
   (docs/ux-foundation.md §6): режим, счётчик решения, одна самая горячая
   тревога с рычагом, точка здоровья со словом. Вопросов не больше четырёх;
   тревога без рычага на экран не выпускается и остаётся строкой паспорта. */
.axis-pulse {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--axis-gap-group);
  min-height: var(--axis-control);
  font-size: var(--axis-text-sm);
  color: var(--axis-ink-2);
}
.axis-pulse-alarm {
  display: inline-flex; align-items: center; gap: var(--axis-space-2);
  color: var(--axis-danger);
}
.axis-pulse-alarm--warn { color: var(--axis-warn); }

/* ── Голова второй рельсы: паспорт сущности ─────────────────────────────────
   Рельса сущности берётся там, где состояние сущности обязано быть видно на
   каждой её странице (docs/ux-foundation.md §4.2). Голова несёт возврат к
   списку, имя, слово состояния и ключ, которым ключуются запросы разделов. */
.axis-subrail-head {
  display: flex; flex-direction: column; gap: var(--axis-space-2);
  padding: var(--axis-space-3);
  border-bottom: 1px solid var(--axis-line);
}
/* Имя сущности в голове рельсы не заголовок экрана: заголовок стоит в
   содержимом. Оно берёт пару пункта рельсы, чтобы на экране не заводилась
   шестая роль набора (ui-foundation.md §1). */
.axis-subrail-head > :is(h1, h2, h3) {
  margin: 0;
  font-size: var(--axis-text-sm);
  font-weight: var(--axis-w-semibold);
  line-height: var(--axis-leading-snug);
  color: var(--axis-ink);
}

/* ═══ Buttons ═══════════════════════════════════════════════════════════════
   A control names its result. Hover lifts by 1px, press sits back down – the
   120ms micro-reaction, and the only transform a button ever performs. */

.axis-btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--axis-space-2);
  height: var(--axis-btn-h);
  padding: 0 var(--axis-btn-pad-x);
  border: 1px solid transparent;
  border-radius: var(--axis-btn-radius);
  background: var(--axis-btn-bg);
  color: var(--axis-btn-fg);
  font-family: var(--axis-font-sans);
  font-size: var(--axis-btn-font);
  font-weight: var(--axis-btn-weight);
  line-height: var(--axis-leading-none);
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  text-decoration: none;
  transition: background-color var(--axis-dur-fast) var(--axis-ease),
              border-color var(--axis-dur-fast) var(--axis-ease),
              color var(--axis-dur-fast) var(--axis-ease),
              transform var(--axis-dur-fast) var(--axis-ease);
}
.axis-btn:hover { background: var(--axis-btn-bg-hover); transform: translateY(-1px); }
.axis-btn:active { background: var(--axis-btn-bg-active); transform: translateY(0); transition-duration: var(--axis-dur-instant); }
.axis-btn:disabled, .axis-btn[aria-disabled="true"] {
  background: var(--axis-chip); color: var(--axis-muted);
  border-color: transparent; cursor: not-allowed; transform: none;
}

.axis-btn--secondary {
  background: transparent; color: var(--axis-ink-2);
  border-color: var(--axis-line-strong);
}
.axis-btn--secondary:hover { background: var(--axis-surface-2); color: var(--axis-ink); border-color: var(--axis-line-strong); }
.axis-btn--secondary:active { background: var(--axis-surface-3); }

.axis-btn--ghost { background: transparent; color: var(--axis-ink-2); }
.axis-btn--ghost:hover { background: var(--axis-surface-2); color: var(--axis-ink); }
.axis-btn--ghost:active { background: var(--axis-surface-3); }

/* Destructive intent: outlined at rest, committed on hover. The solid variant
   belongs inside a danger zone only. */
.axis-btn--danger { background: transparent; color: var(--axis-danger); border-color: var(--axis-danger); }
.axis-btn--danger:hover { background: var(--axis-danger-soft); }
.axis-btn--danger:active { background: var(--axis-danger-soft); }
.axis-btn--danger-fill { background: var(--axis-danger); color: var(--axis-danger-contrast); }
.axis-btn--danger-fill:hover { background: var(--axis-danger); }

.axis-btn--sm { height: var(--axis-control-sm); padding: 0 var(--axis-control-pad-sm); }
.axis-btn--lg { height: var(--axis-control-lg); padding: 0 var(--axis-control-pad-lg); font-size: var(--axis-text-sm); }
.axis-btn--icon { width: var(--axis-btn-h); padding: 0; }
.axis-btn--sm.axis-btn--icon { width: var(--axis-control-sm); }

.axis-btn-group { display: inline-flex; }
.axis-btn-group .axis-btn { border-radius: 0; }
.axis-btn-group .axis-btn:first-child { border-radius: var(--axis-btn-radius) 0 0 var(--axis-btn-radius); }
.axis-btn-group .axis-btn:last-child { border-radius: 0 var(--axis-btn-radius) var(--axis-btn-radius) 0; }
.axis-btn-group .axis-btn--secondary + .axis-btn--secondary { margin-left: -1px; }

/* ═══ Forms ═════════════════════════════════════════════════════════════════ */

.axis-field { display: flex; flex-direction: column; gap: var(--axis-space-1); min-width: 0; }
.axis-field-row { display: flex; gap: var(--axis-gap-group); }
.axis-field-row > .axis-field { flex: 1; }

.axis-input, .axis-select, .axis-textarea {
  height: var(--axis-input-h);
  padding: 0 var(--axis-control-pad);
  background: var(--axis-input-bg);
  border: 1px solid var(--axis-input-border);
  border-radius: var(--axis-input-radius);
  color: var(--axis-ink);
  font-family: var(--axis-font-sans);
  font-size: var(--axis-text-base);
  line-height: var(--axis-leading-snug);
  transition: border-color var(--axis-dur-fast) var(--axis-ease);
  min-width: 0; width: 100%;
}
.axis-input::placeholder, .axis-textarea::placeholder { color: var(--axis-muted); }
.axis-input:focus-visible, .axis-select:focus-visible, .axis-textarea:focus-visible {
  border-color: var(--axis-brand);
  box-shadow: var(--axis-ring);
  outline: none;
}
.axis-input[aria-invalid="true"], .axis-textarea[aria-invalid="true"] { border-color: var(--axis-danger); }
.axis-input[aria-invalid="true"]:focus-visible { box-shadow: var(--axis-ring-danger); }
.axis-input:disabled, .axis-select:disabled, .axis-textarea:disabled {
  background: var(--axis-surface-2); color: var(--axis-muted); cursor: not-allowed;
}
/* Data-bearing input (a phone, an ID, a duration) – opt into the data face. */
.axis-input--mono { font-family: var(--axis-font-mono); font-feature-settings: "zero" 1; }

.axis-textarea { height: auto; min-height: calc(var(--axis-input-h) * 2); padding: var(--axis-space-2) var(--axis-control-pad); resize: vertical; }

.axis-select {
  appearance: none;
  background-image: var(--axis-chevron);
  background-repeat: no-repeat;
  background-position: right var(--axis-space-2) center;
  padding-right: var(--axis-space-8);
}

/* Подпись: роль набора ui-foundation §1, 12/400. Подсказка под полем и
   ошибка под полем это одна роль, и обе берут её ступень: 11px заводил
   шестую пару на каждом экране с формой. */
.axis-hint  { font-size: var(--axis-text-xs); color: var(--axis-muted); }
.axis-form-error { font-size: var(--axis-text-xs); color: var(--axis-danger); }

.axis-fieldset { border: 1px solid var(--axis-line); border-radius: var(--axis-radius); padding: var(--axis-space-4); margin: 0; }
.axis-legend { padding: 0 var(--axis-space-2); }
.axis-form-actions { display: flex; gap: var(--axis-space-2); justify-content: flex-end; padding-top: var(--axis-space-2); }

/* Search – an input wearing its icon. */
.axis-search { position: relative; display: flex; align-items: center; min-width: 0; }
.axis-search > svg {
  position: absolute; left: var(--axis-space-2);
  width: var(--axis-icon-sm); height: var(--axis-icon-sm);
  color: var(--axis-muted); pointer-events: none;
}
.axis-search > .axis-input { padding-left: var(--axis-space-8); }
.axis-search > .axis-kbd { position: absolute; right: var(--axis-space-2); }

/* ═══ Choice controls ═══════════════════════════════════════════════════════ */

.axis-choice {
  display: inline-flex; align-items: center; gap: var(--axis-space-2);
  /* The label is the target, and it is the whole control: without a floor the row
     is as tall as a 16px box and its text, well under the 28px every other control
     carries (§11). */
  min-height: var(--axis-control-sm);
  font-size: var(--axis-text-sm); color: var(--axis-ink);
  cursor: pointer; user-select: none;
}
.axis-check, .axis-radio {
  appearance: none; margin: 0; flex: 0 0 auto;
  width: var(--axis-icon-sm); height: var(--axis-icon-sm);
  border: 1px solid var(--axis-line-strong);
  border-radius: var(--axis-radius-xs);
  background: var(--axis-surface);
  cursor: pointer;
  transition: background-color var(--axis-dur-fast) var(--axis-ease),
              border-color var(--axis-dur-fast) var(--axis-ease);
}
.axis-radio { border-radius: var(--axis-radius-pill); }
.axis-check:checked, .axis-radio:checked {
  background: var(--axis-brand-fill);
  border-color: var(--axis-brand-fill);
}
.axis-check:checked {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 13 4 4 10-10'/%3E%3C/svg%3E");
  background-size: 10px 10px;
  background-position: center;
  background-repeat: no-repeat;
}
.axis-radio:checked { box-shadow: inset 0 0 0 3px var(--axis-surface); }

.axis-switch {
  appearance: none; margin: 0; flex: 0 0 auto;
  width: var(--axis-space-8); height: var(--axis-space-5);
  border: 1px solid var(--axis-line-strong);
  border-radius: var(--axis-radius-pill);
  background: var(--axis-surface-3);
  position: relative; cursor: pointer;
  transition: background-color var(--axis-dur) var(--axis-ease),
              border-color var(--axis-dur) var(--axis-ease);
}
.axis-switch::after {
  content: "";
  position: absolute; top: 1px; left: 1px;
  width: var(--axis-icon-sm); height: var(--axis-icon-sm);
  border-radius: var(--axis-radius-pill);
  background: var(--axis-surface);
  box-shadow: var(--axis-shadow-sm);
  transition: transform var(--axis-dur) var(--axis-ease);
}
.axis-switch:checked { background: var(--axis-brand-fill); border-color: var(--axis-brand-fill); }
.axis-switch:checked::after { transform: translateX(var(--axis-space-3)); }

/* ═══ Pills, chips, badges ═══════════════════════════════════════════════════
   The status pill is the outlined capsule: mono word, dot, hairline of its own
   colour, no fill. Capsule at every radius setting – that is its signature.
   Status is never hue alone: dot + word + colour, legible in greyscale. */

.axis-pill {
  display: inline-flex; align-items: center; gap: var(--axis-space-1);
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-2xs);
  font-weight: var(--axis-w-medium);
  font-feature-settings: "zero" 1;
  line-height: var(--axis-leading-snug);
  padding: 0 var(--axis-space-2);
  border: 1px solid currentColor;
  border-radius: var(--axis-radius-pill);
  background: transparent;
  color: var(--axis-muted);
  white-space: nowrap;
}
/* Пилюля, по которой нажимают, это цель касания (docs/ui-foundation.md §12).
   У надписи-пилюли высоты нет вовсе - её держит межстрочное подписи, 16,8 px, -
   и пилюля-ссылка с пилюлей-кнопкой оказываются вдвое ниже порога 28. Растёт
   область нажатия, а не кегль: высота приходит ступенью контрола. */
a.axis-pill, button.axis-pill, [role="button"].axis-pill {
  min-height: var(--axis-control-sm);
}
@media (max-width: 767px) {
  a.axis-pill, button.axis-pill, [role="button"].axis-pill {
    min-height: var(--axis-control-lg);
  }
}
.axis-pill i, .axis-pill-dot {
  width: 6px; height: 6px; flex: 0 0 auto;
  border-radius: var(--axis-radius-pill);
  background: currentColor;
}
.axis-pill--ok     { color: var(--axis-ok); }
.axis-pill--warn   { color: var(--axis-warn); }
.axis-pill--danger { color: var(--axis-danger); }
.axis-pill--brand  { color: var(--axis-brand); }
.axis-pill--accent { color: var(--axis-accent-strong); }
/* The live pill: the one licensed loop in the system. */
.axis-pill--live { color: var(--axis-live); }
.axis-pill--live i, .axis-pill--live .axis-pill-dot { box-shadow: var(--axis-glow-live); animation: axis-breathe var(--axis-dur-loop) var(--axis-ease-loop) infinite; }

/* Soft-filled chip – a neutral tag, not a status. */
.axis-chip {
  display: inline-flex; align-items: center; gap: var(--axis-space-1);
  font-size: var(--axis-text-2xs);
  font-weight: var(--axis-w-medium);
  line-height: var(--axis-leading-snug);
  padding: var(--axis-space-1) var(--axis-space-2);
  border-radius: var(--axis-radius-pill);
  background: var(--axis-chip);
  color: var(--axis-ink-2);
  white-space: nowrap;
}
.axis-chip--accent { background: var(--axis-accent-soft); color: var(--axis-accent-strong); }

/* Numeric badge on a solid fill (notification counters outside the rail). */
.axis-badge {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-3xs);
  font-weight: var(--axis-w-semibold);
  font-feature-settings: "zero" 1;
  min-width: var(--axis-space-4);
  line-height: 16px;
  padding: 0 var(--axis-space-1);
  border-radius: var(--axis-radius-pill);
  background: var(--axis-accent-fill);
  color: var(--axis-accent-contrast);
}

/* Keyboard hint. */
.axis-kbd {
  display: inline-flex; align-items: center;
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-3xs);
  color: var(--axis-muted);
  border: 1px solid var(--axis-line);
  border-radius: var(--axis-radius-xs);
  padding: 0 var(--axis-space-1);
  line-height: 16px;
}

/* ═══ Table ═════════════════════════════════════════════════════════════════
   Compact by default (26px rows); wrap any region in data-density="cozy" or
   "air" to loosen. Headers speak telemetry; numerals are mono and slashed. */

.axis-table-wrap { border: 1px solid var(--axis-line); border-radius: var(--axis-radius); overflow: auto; background: var(--axis-surface); }
.axis-table { width: 100%; border-collapse: collapse; font-size: var(--axis-text-xs); color: var(--axis-ink); }
.axis-table th {
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-3xs);
  font-weight: var(--axis-w-medium);
  letter-spacing: var(--axis-tracking-label);
  text-transform: uppercase;
  text-align: left;
  color: var(--axis-muted);
  padding: var(--axis-space-2) var(--axis-table-pad-x);
  border-bottom: 1px solid var(--axis-line-strong);
  white-space: nowrap;
}
.axis-table td {
  height: var(--axis-table-row-h);
  padding: var(--axis-density-pad-y) var(--axis-table-pad-x);
  border-bottom: 1px solid var(--axis-line);
  line-height: var(--axis-leading-snug);
  color: var(--axis-ink);
}
.axis-table tr:last-child td { border-bottom: 0; }
.axis-table tbody tr { transition: background-color var(--axis-dur-fast) var(--axis-ease); }
.axis-table tbody tr:hover { background: var(--axis-table-hover); }
.axis-table--zebra tbody tr:nth-child(even) { background: var(--axis-table-zebra); }
.axis-table .axis-num, .axis-table .axis-tnum { font-size: var(--axis-text-2xs); }
.axis-td-end { text-align: right; }
/* Sortable header: the caret mask follows currentColor. */
.axis-th-sort {
  display: inline-flex; align-items: center; gap: var(--axis-space-1);
  cursor: pointer; color: inherit; background: none; border: 0; padding: 0;
  font: inherit; letter-spacing: inherit; text-transform: inherit;
}
.axis-th-sort::after {
  content: ""; width: var(--axis-space-3); height: var(--axis-space-3);
  background: currentColor;
  -webkit-mask: var(--axis-caret-mask) center / contain no-repeat;
  mask: var(--axis-caret-mask) center / contain no-repeat;
  opacity: 0; transition: opacity var(--axis-dur-fast) var(--axis-ease), transform var(--axis-dur-fast) var(--axis-ease);
}
.axis-th-sort:hover::after { opacity: .5; }
.axis-th-sort[aria-sort="ascending"]::after { opacity: 1; transform: rotate(180deg); }
.axis-th-sort[aria-sort="descending"]::after { opacity: 1; }

/* Bulk-action bar: floats over a table when rows are selected. */
.axis-bulkbar {
  position: fixed; left: 50%; bottom: var(--axis-space-6);
  transform: translateX(-50%);
  display: flex; align-items: center; gap: var(--axis-gap-tight);
  background: var(--axis-inverse-surface); color: var(--axis-inverse-ink);
  border-radius: var(--axis-radius);
  padding: var(--axis-space-2) var(--axis-space-4);
  box-shadow: var(--axis-shadow-lg);
  z-index: var(--axis-z-toast);
}

/* ═══ Cards & the instrument ════════════════════════════════════════════════ */

.axis-card {
  background: var(--axis-card-bg);
  border: 1px solid var(--axis-card-border);
  border-radius: var(--axis-card-radius);
  box-shadow: var(--axis-card-shadow);
  padding: var(--axis-card-pad);
  min-width: 0;
}
.axis-card--flush { padding: 0; overflow: hidden; }
.axis-card--link { display: block; color: inherit; text-decoration: none;
  transition: border-color var(--axis-dur-fast) var(--axis-ease); }
.axis-card--link:hover { border-color: var(--axis-line-strong); }

/* The instrument: KPI cells fused into one machined block, divided by 1px
   seams. One instrument per screen region – it reads as a device, and two
   devices side by side read as clutter. */
.axis-instrument {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 1px;
  background: var(--axis-instrument-seam);
  border: 1px solid var(--axis-instrument-seam);
  border-radius: var(--axis-radius);
  overflow: hidden;
}
.axis-instrument--wrap { grid-auto-flow: row; grid-template-columns: repeat(auto-fit, minmax(var(--col, 160px), 1fr)); }
.axis-kpi {
  position: relative;
  background: var(--axis-instrument-bg);
  padding: var(--axis-space-2) var(--axis-space-3);
  display: flex; flex-direction: column; gap: var(--axis-space-1);
  min-width: 0;
}
/* The drafting mark: a corner cross, as on a blueprint under assembly. */
.axis-kpi::after {
  content: "+";
  position: absolute; top: 2px; right: var(--axis-space-2);
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-3xs);
  color: color-mix(in srgb, var(--axis-muted) 55%, transparent);
  pointer-events: none;
}
.axis-kpi-value {
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-2xl);
  font-weight: var(--axis-w-medium);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "zero" 1;
  letter-spacing: var(--axis-tracking-tight);
  line-height: var(--axis-leading-tight);
  color: var(--axis-ink);
  text-shadow: var(--axis-glow-brand);
}
.axis-kpi-value--sm { font-size: var(--axis-text-lg); }
.axis-kpi-delta { font-family: var(--axis-font-mono); font-size: var(--axis-text-2xs); font-feature-settings: "zero" 1; }
.axis-kpi-delta.is-up { color: var(--axis-ok); }
.axis-kpi-delta.is-down { color: var(--axis-danger); }

/* ═══ Telemetry components ══════════════════════════════════════════════════ */

/* The live bar: what is on the line right now. */
.axis-live-bar {
  display: flex; align-items: center; gap: var(--axis-space-2);
  background: var(--axis-surface);
  border: 1px solid var(--axis-line);
  border-radius: var(--axis-radius);
  padding: var(--axis-space-1) var(--axis-space-3);
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-2xs);
  font-feature-settings: "zero" 1;
  color: var(--axis-ink-2);
  min-width: 0;
}
.axis-live-bar > span:last-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.axis-live-dot {
  width: 6px; height: 6px; flex: 0 0 auto;
  border-radius: var(--axis-radius-pill);
  background: var(--axis-live);
  box-shadow: var(--axis-glow-live);
  animation: axis-breathe var(--axis-dur-loop) var(--axis-ease-loop) infinite;
}
.axis-live-label { color: var(--axis-live); }

/* Family dot: the coarse axis above a fine one, for states a person cannot
   hold nine of at once. It stands BESIDE the exact word, never instead of it -
   colour alone never carries a state (docs/ux-foundation.md §8). Tones are the
   semantic roles already validated for contrast in both themes, not four new
   colours: whose turn it is is the same question the tones already answer.
     machine - the machine's turn, nothing is asked of the person;
     live    - running and wanting an eye, the tone the health axis already
               uses for "стоит: причина";
     handed  - handed over: the success this product exists for;
     done    - the work has ended, nobody's turn.
   The calling tone --axis-accent is deliberately NOT among them: it is the
   surface's single calling colour, and a static accent dot on every row would
   make the whole list call. */
.axis-state-dot {
  width: 6px; height: 6px; flex: 0 0 auto;
  border-radius: var(--axis-radius-pill);
  background: var(--axis-muted);
  display: inline-block;
}
.axis-state-dot--machine { background: var(--axis-brand); }
.axis-state-dot--live    { background: var(--axis-warn); }
.axis-state-dot--handed  { background: var(--axis-ok); }
.axis-state-dot--done    { background: var(--axis-muted); }

/* The screen passport: revision, node, live counters, clock. Every console is
   a signed mechanism – the operator always sees what they are looking at. */
.axis-passport {
  display: flex; align-items: center; gap: var(--axis-space-2);
  margin-top: auto;
  padding-top: var(--axis-space-2);
  border-top: 1px solid var(--axis-line);
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-3xs);
  letter-spacing: var(--axis-tracking-label);
  text-transform: uppercase;
  font-feature-settings: "zero" 1;
  /* Quiet comes from the 10px caps and the track, not from a wash. Faded to 75%
     the line measured 3.31 on the canvas it actually sits on; the alpha needed to
     clear the bar is 0.91, a wash worth nothing. Two ink steps say the same thing
     and survive any surface the passport lands on. */
  color: var(--axis-muted);
  white-space: nowrap; overflow: hidden;
}
.axis-passport em { font-style: normal; color: var(--axis-ink-2); }
/* Its place is the bottom of the CONTENT column, not a band across the shell:
   margin-top:auto pins it there. A band would run under the rail and cover it,
   and a rail 224px wide cannot hold the four segments without cutting them. */

/* The command line: jump, act, search from the keyboard. Terminal-dark in both
   themes – it is a momentary overlay, like the toast. */
.axis-cmd {
  width: min(560px, calc(100% - var(--axis-space-8)));
  background: var(--axis-cmd-bg);
  color: var(--axis-cmd-ink);
  border-radius: var(--axis-radius-lg);
  box-shadow: var(--axis-shadow-lg);
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-sm);
  overflow: hidden;
}
.axis-cmd-row {
  display: flex; align-items: center; gap: var(--axis-space-2);
  padding: var(--axis-space-3) var(--axis-space-4);
}
.axis-cmd-prompt { color: var(--axis-cmd-prompt); font-weight: var(--axis-w-semibold); user-select: none; }
.axis-cmd-prompt::before { content: "axis\203A"; }
.axis-cmd-input {
  flex: 1; min-width: 0;
  background: transparent; border: 0; outline: none;
  color: inherit; font: inherit;
  caret-color: var(--axis-cmd-prompt);
}
.axis-cmd-list { border-top: 1px solid var(--axis-line); max-height: 320px; overflow-y: auto; padding: var(--axis-space-1); }
.axis-cmd-item {
  display: flex; align-items: center; gap: var(--axis-space-2);
  padding: var(--axis-space-2) var(--axis-space-3);
  border-radius: var(--axis-radius-xs);
  cursor: pointer;
}
.axis-cmd-item:hover, .axis-cmd-item.is-active { background: color-mix(in srgb, var(--axis-cmd-prompt) 16%, transparent); }
.axis-cmd-item .axis-kbd { margin-left: auto; color: inherit; border-color: color-mix(in srgb, var(--axis-cmd-ink) 25%, transparent); }

/* The danger zone: irreversible actions live behind industrial hatching. */
.axis-danger-zone {
  position: relative;
  border: 1px solid var(--axis-line);
  border-radius: var(--axis-radius);
  background: var(--axis-surface);
  padding: var(--axis-space-4);
  padding-top: var(--axis-space-5);
  overflow: hidden;
}
.axis-danger-zone::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: var(--axis-space-1);
  background: repeating-linear-gradient(-45deg,
    var(--axis-danger) 0 6px, transparent 6px 12px);
  opacity: .75;
}

/* Inline callout: a static message that belongs to the page, unlike the toast.
   Statusful, bordered on its own colour, never animated. */
.axis-callout {
  display: flex; gap: var(--axis-space-2); align-items: flex-start;
  border: 1px solid var(--axis-line);
  border-left: var(--axis-border-strong) solid var(--axis-ink-2);
  border-radius: var(--axis-radius);
  background: var(--axis-surface);
  padding: var(--axis-space-3) var(--axis-space-4);
  font-size: var(--axis-text-sm);
  color: var(--axis-ink);
}
.axis-callout--brand  { border-left-color: var(--axis-brand);  background: var(--axis-brand-soft); }
.axis-callout--ok     { border-left-color: var(--axis-ok);     background: var(--axis-ok-soft); }
.axis-callout--warn   { border-left-color: var(--axis-warn);   background: var(--axis-warn-soft); }
.axis-callout--danger { border-left-color: var(--axis-danger); background: var(--axis-danger-soft); }
.axis-callout-title { font-weight: var(--axis-w-semibold); }

/* ═══ Chat ══════════════════════════════════════════════════════════════════
   The hub and the outreach tools are conversation-first; the thread is a
   first-class component, not an app-side improvisation. */

.axis-chat {
  display: flex; flex-direction: column; gap: var(--axis-space-2);
  padding: var(--axis-space-3);
  min-width: 0;
}
.axis-msg {
  max-width: 74%;
  padding: var(--axis-space-2) var(--axis-space-3);
  border: 1px solid var(--axis-line);
  border-radius: var(--axis-bubble-radius);
  font-size: var(--axis-text-sm);
  line-height: var(--axis-leading);
  color: var(--axis-ink);
  min-width: 0; overflow-wrap: break-word;
}
.axis-msg--in {
  align-self: flex-start;
  background: var(--axis-bubble-in-bg);
  border-bottom-left-radius: var(--axis-radius-xs);
}
.axis-msg--out {
  align-self: flex-end;
  background: var(--axis-bubble-out-bg);
  border-color: var(--axis-bubble-out-border);
  border-bottom-right-radius: var(--axis-radius-xs);
}
.axis-msg-time {
  display: block; margin-top: var(--axis-space-1);
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-3xs);
  font-feature-settings: "zero" 1;
  color: var(--axis-muted);
}
/* Day separator: a telemetry label between two hairlines. */
.axis-daysep {
  display: flex; align-items: center; gap: var(--axis-gap-tight);
  padding: var(--axis-space-2) 0;
}
.axis-daysep::before, .axis-daysep::after {
  content: ""; flex: 1; height: 1px; background: var(--axis-line);
}
/* Unread waterline: the guest accent marks where the new begins. */
.axis-unread-sep { display: flex; align-items: center; gap: var(--axis-gap-tight); padding: var(--axis-space-1) 0; color: var(--axis-accent-strong); }
.axis-unread-sep::before, .axis-unread-sep::after {
  content: ""; flex: 1; height: 1px; background: var(--axis-accent);
}
.axis-composer {
  display: flex; gap: var(--axis-space-2); align-items: flex-end;
  padding: var(--axis-space-2) var(--axis-space-3);
  border-top: 1px solid var(--axis-line);
  background: var(--axis-surface);
}
.axis-composer > .axis-input, .axis-composer > .axis-textarea { flex: 1; }

/* ═══ Overlays ══════════════════════════════════════════════════════════════
   Arrivals take --axis-dur-slow, exits --axis-dur-fast: leaving is always
   quicker than arriving. Overlays are the only surfaces that cast shadows. */

.axis-scrim {
  position: fixed; inset: 0;
  background: var(--axis-scrim);
  z-index: var(--axis-z-scrim);
  display: flex; align-items: flex-start; justify-content: center;
  padding: var(--axis-space-16) var(--axis-space-4) var(--axis-space-4);
  overflow-y: auto;
}
.axis-dialog {
  width: min(var(--axis-dialog-w), 100%);
  background: var(--axis-surface);
  border: 1px solid var(--axis-line);
  border-radius: var(--axis-dialog-radius);
  box-shadow: var(--axis-dialog-shadow);
  z-index: var(--axis-z-dialog);
  display: flex; flex-direction: column;
  animation: axis-rise var(--axis-dur-slow) var(--axis-ease);
}
.axis-dialog-head {
  display: flex; align-items: center; gap: var(--axis-gap-tight);
  padding: var(--axis-space-4);
  border-bottom: 1px solid var(--axis-line);
}
.axis-dialog-body { padding: var(--axis-space-4); display: flex; flex-direction: column; gap: var(--axis-gap-group); }
.axis-dialog-foot {
  display: flex; gap: var(--axis-space-2); justify-content: flex-end;
  padding: var(--axis-space-4);
  border-top: 1px solid var(--axis-line);
}

/* Drawer: a side panel for details that keep the page underneath relevant. */
.axis-drawer {
  position: fixed; top: 0; right: 0; bottom: 0;
  width: min(420px, calc(100% - var(--axis-space-10)));
  background: var(--axis-surface);
  border-left: 1px solid var(--axis-line);
  box-shadow: var(--axis-shadow-lg);
  z-index: var(--axis-z-dialog);
  display: flex; flex-direction: column;
  animation: axis-slide-in var(--axis-dur-slow) var(--axis-ease);
}
.axis-drawer-head {
  display: flex; align-items: center; gap: var(--axis-gap-tight);
  padding: var(--axis-space-4);
  border-bottom: 1px solid var(--axis-line);
}
.axis-drawer-body { padding: var(--axis-space-4); overflow-y: auto; flex: 1;
  display: flex; flex-direction: column; gap: var(--axis-gap-group); }

/* Menu / popover. */
.axis-menu {
  min-width: 180px;
  background: var(--axis-overlay);
  border: 1px solid var(--axis-line);
  border-radius: var(--axis-radius);
  box-shadow: var(--axis-shadow-md);
  padding: var(--axis-space-1);
  z-index: var(--axis-z-dropdown);
  animation: axis-rise var(--axis-dur-fast) var(--axis-ease);
}
.axis-menu-item {
  display: flex; align-items: center; gap: var(--axis-space-2);
  width: 100%;
  padding: var(--axis-space-2) var(--axis-space-3);
  border: 0; border-radius: var(--axis-radius-xs);
  background: none; color: var(--axis-ink);
  font-family: var(--axis-font-sans);
  font-size: var(--axis-text-sm);
  text-align: left; text-decoration: none;
  cursor: pointer;
}
.axis-menu-item:hover { background: var(--axis-surface-2); }
.axis-menu-item.is-danger { color: var(--axis-danger); }
.axis-menu-item.is-danger:hover { background: var(--axis-danger-soft); }
.axis-menu-sep { height: 1px; background: var(--axis-line); margin: var(--axis-space-1) 0; border: 0; }
.axis-popover {
  background: var(--axis-overlay);
  border: 1px solid var(--axis-line);
  border-radius: var(--axis-radius);
  box-shadow: var(--axis-shadow-md);
  padding: var(--axis-space-3);
  z-index: var(--axis-z-dropdown);
  max-width: 320px;
  animation: axis-rise var(--axis-dur-fast) var(--axis-ease);
}

/* Toast: momentary, inverse, self-evidently floating. The word matches the
   button that caused it: «Подключить канал» даёт «Канал подключён». */
.axis-toast {
  display: flex; align-items: center; gap: var(--axis-space-2);
  background: var(--axis-inverse-surface);
  color: var(--axis-inverse-ink);
  border-radius: var(--axis-radius);
  box-shadow: var(--axis-shadow-md);
  padding: var(--axis-space-2) var(--axis-space-4);
  font-size: var(--axis-text-sm);
  font-weight: var(--axis-w-medium);
  z-index: var(--axis-z-toast);
  animation: axis-rise var(--axis-dur-slow) var(--axis-ease);
}
.axis-toast.is-leaving { animation: axis-fall var(--axis-dur-fast) var(--axis-ease-out) forwards; }
.axis-toast-ok { color: var(--axis-inverse-ok); font-weight: var(--axis-w-semibold); }
.axis-toast-stack {
  position: fixed; right: var(--axis-space-6); bottom: var(--axis-space-6);
  display: flex; flex-direction: column; gap: var(--axis-space-2);
  z-index: var(--axis-z-toast);
}

/* Tooltip. */
.axis-tip {
  background: var(--axis-inverse-surface);
  color: var(--axis-inverse-ink);
  border-radius: var(--axis-radius-xs);
  box-shadow: var(--axis-shadow-sm);
  padding: var(--axis-space-1) var(--axis-space-2);
  font-size: var(--axis-text-2xs);
  line-height: var(--axis-leading-snug);
  max-width: 260px;
  z-index: var(--axis-z-toast);
}

/* ═══ Navigation extras ═════════════════════════════════════════════════════ */

.axis-tabs {
  display: flex; flex-wrap: wrap;
  gap: var(--axis-space-1);
  border-bottom: 1px solid var(--axis-line);
  min-width: 0;
}
.axis-tab {
  display: inline-flex; align-items: center; gap: var(--axis-space-2);
  padding: var(--axis-space-2) var(--axis-space-3);
  margin-bottom: -1px;
  border: 0; border-bottom: var(--axis-border-strong) solid transparent;
  background: none;
  color: var(--axis-ink-2);
  font-family: var(--axis-font-sans);
  font-size: var(--axis-text-sm);
  font-weight: var(--axis-w-semibold);
  text-decoration: none;
  cursor: pointer;
  transition: color var(--axis-dur-fast) var(--axis-ease),
              border-color var(--axis-dur-fast) var(--axis-ease);
}
.axis-tab:hover { color: var(--axis-ink); }
/* Полоса снизу и цвет, вес не двигается: см. .axis-nav-link.is-active. */
.axis-tab.is-active, .axis-tab[aria-selected="true"] {
  color: var(--axis-brand);
  border-bottom-color: var(--axis-brand);
}

.axis-segmented {
  display: inline-flex;
  border: 1px solid var(--axis-line-strong);
  border-radius: var(--axis-radius-sm);
  overflow: hidden;
  background: var(--axis-surface);
}
.axis-segment {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--axis-control-sm);
  padding: var(--axis-space-1) var(--axis-space-3);
  border: 0;
  background: none;
  color: var(--axis-ink-2);
  font-family: var(--axis-font-sans);
  font-size: var(--axis-text-xs);
  font-weight: var(--axis-w-semibold);
  cursor: pointer;
  transition: background-color var(--axis-dur-fast) var(--axis-ease);
}
.axis-segment + .axis-segment { border-left: 1px solid var(--axis-line); }
/* Заливка и цвет, вес не двигается: см. .axis-nav-link.is-active. */
.axis-segment.is-active, .axis-segment[aria-pressed="true"] {
  background: var(--axis-surface-3);
  color: var(--axis-ink);
}

.axis-crumbs {
  display: flex; align-items: center; gap: var(--axis-space-2);
  font-size: var(--axis-text-sm); color: var(--axis-muted);
  flex-wrap: wrap;
}
.axis-crumbs a { color: var(--axis-muted); text-decoration: none; }
.axis-crumbs a:hover { color: var(--axis-ink); text-decoration: underline; }
.axis-crumb-sep { color: var(--axis-line-strong); user-select: none; }
.axis-crumbs [aria-current="page"] { color: var(--axis-ink); }

.axis-pager {
  display: flex; align-items: center; gap: var(--axis-space-1);
  font-family: var(--axis-font-mono);
  font-size: var(--axis-text-2xs);
  font-feature-settings: "zero" 1;
}
.axis-page {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--axis-control-sm); height: var(--axis-control-sm);
  padding: 0 var(--axis-space-1);
  border: 1px solid transparent;
  border-radius: var(--axis-radius-xs);
  background: none; color: var(--axis-ink-2);
  font: inherit; cursor: pointer; text-decoration: none;
}
.axis-page:hover { background: var(--axis-surface-2); }
/* Рамка и цвет, вес не двигается: см. .axis-nav-link.is-active. */
.axis-page.is-active, .axis-page[aria-current="page"] {
  border-color: var(--axis-brand);
  color: var(--axis-brand);
}

.axis-disclosure > summary {
  display: flex; align-items: center; gap: var(--axis-space-2);
  cursor: pointer; list-style: none;
  font-weight: var(--axis-w-medium);
  padding: var(--axis-space-2) 0;
}
.axis-disclosure > summary::-webkit-details-marker { display: none; }
.axis-disclosure > summary::before {
  content: ""; width: var(--axis-space-3); height: var(--axis-space-3);
  background: currentColor;
  -webkit-mask: var(--axis-caret-mask) center / contain no-repeat;
  mask: var(--axis-caret-mask) center / contain no-repeat;
  transform: rotate(-90deg);
  transition: transform var(--axis-dur-fast) var(--axis-ease);
}
.axis-disclosure[open] > summary::before { transform: rotate(0); }

/* ═══ Feedback & data ═══════════════════════════════════════════════════════ */

/* Skeleton: loading is a live process, so it may breathe – the same licence
   as the live dot, and the same kill switch under reduced motion. */
.axis-skeleton {
  background: var(--axis-surface-3);
  border-radius: var(--axis-radius-xs);
  min-height: var(--axis-space-4);
  animation: axis-breathe var(--axis-dur-loop) var(--axis-ease-loop) infinite;
}
.axis-skeleton--text { height: var(--axis-space-3); }
.axis-skeleton--control { height: var(--axis-control); }

.axis-progress {
  height: 6px;
  background: var(--axis-surface-3);
  border-radius: var(--axis-radius-xs);
  overflow: hidden;
}
.axis-progress-fill {
  height: 100%;
  background: var(--axis-brand-fill);
  border-radius: inherit;
  transition: width var(--axis-dur-slow) var(--axis-ease);
}
.axis-progress--ok .axis-progress-fill { background: var(--axis-ok); }
.axis-progress--danger .axis-progress-fill { background: var(--axis-danger); }

.axis-meter { display: flex; flex-direction: column; gap: var(--axis-space-1); min-width: 0; }
.axis-meter-scale { display: flex; justify-content: space-between; }

.axis-avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--axis-space-8); height: var(--axis-space-8);
  flex: 0 0 auto;
  border-radius: var(--axis-radius-pill);
  border: 1px solid var(--axis-line);
  background: var(--axis-surface-2);
  color: var(--axis-ink-2);
  font-size: var(--axis-text-2xs);
  font-weight: var(--axis-w-semibold);
  overflow: hidden; user-select: none;
}
.axis-avatar--sm { width: var(--axis-space-6); height: var(--axis-space-6); font-size: var(--axis-text-3xs); }
.axis-avatar > img { width: 100%; height: 100%; object-fit: cover; }

/* Empty state: a sentence and the next action, no illustration, no mood. */
.axis-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--axis-space-2);
  padding: var(--axis-space-10) var(--axis-space-4);
  text-align: center;
  color: var(--axis-muted);
  font-size: var(--axis-text-sm);
}

/* Chart helpers: series classes colour any mark through currentColor. */
.axis-series-1 { color: var(--axis-viz-1); }
.axis-series-2 { color: var(--axis-viz-2); }
.axis-series-3 { color: var(--axis-viz-3); }
.axis-series-4 { color: var(--axis-viz-4); }
.axis-series-5 { color: var(--axis-viz-5); }
.axis-series-6 { color: var(--axis-viz-6); }
.axis-chart { color: var(--axis-viz-axis); font-family: var(--axis-font-mono); font-size: var(--axis-text-3xs); font-feature-settings: "zero" 1; }
.axis-chart-grid { stroke: var(--axis-viz-grid); }
.axis-spark { stroke: currentColor; fill: none; stroke-width: var(--axis-border-strong); }
.axis-spark-fill { fill: currentColor; opacity: .12; stroke: none; }
.axis-swatch { width: var(--axis-space-3); height: var(--axis-space-3); border-radius: var(--axis-radius-xs); background: currentColor; flex: 0 0 auto; }

/* ═══ Ambient ═══════════════════════════════════════════════════════════════
   The showcase layer: sign-in, empty workspaces, marketing surfaces. Two
   drifting pools of light over the drafting grid. Never behind working
   tables; dies entirely under reduced motion. */

.axis-ambient {
  position: relative; overflow: hidden; isolation: isolate;
  background-color: var(--axis-canvas);
  background-image:
    linear-gradient(to right, var(--axis-grid-line) 1px, transparent 1px),
    linear-gradient(to bottom, var(--axis-grid-line-2) 1px, transparent 1px);
  background-size: var(--axis-grid-step) var(--axis-grid-step);
}
.axis-ambient::before, .axis-ambient::after {
  content: ""; position: absolute; inset: -40%;
  border-radius: var(--axis-radius-pill);
  filter: blur(48px);
  opacity: .5;
  z-index: -1;
  pointer-events: none;
}
.axis-ambient::before {
  background: radial-gradient(circle at 34% 42%,
    color-mix(in srgb, var(--axis-brand) 42%, transparent) 0%, transparent 55%);
  animation: axis-drift-a var(--axis-dur-ambient) var(--axis-ease-loop) infinite alternate;
}
.axis-ambient::after {
  background: radial-gradient(circle at 68% 62%,
    color-mix(in srgb, var(--axis-brand-strong) 30%, transparent) 0%, transparent 55%);
  animation: axis-drift-b var(--axis-dur-ambient) var(--axis-ease-loop) infinite alternate;
}

/* ═══ Motion ════════════════════════════════════════════════════════════════ */

@keyframes axis-breathe {
  0%, 100% { opacity: .45; transform: scale(.85); }
  50%      { opacity: 1;   transform: scale(1); }
}
@keyframes axis-rise {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes axis-fall {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(6px); }
}
@keyframes axis-slide-in {
  from { transform: translateX(var(--axis-space-6)); opacity: 0; }
  to   { transform: translateX(0); opacity: 1; }
}
@keyframes axis-drift-a {
  from { transform: translate(-4%, -3%) scale(1); }
  to   { transform: translate(5%, 4%) scale(1.08); }
}
@keyframes axis-drift-b {
  from { transform: translate(4%, 3%) scale(1.06); }
  to   { transform: translate(-5%, -4%) scale(1); }
}
/* Entrance utility for consumer-side reveals. */
.axis-enter { animation: axis-rise var(--axis-dur) var(--axis-ease); }

@media (prefers-reduced-motion: reduce) {
  .axis *, .axis-app *, .axis-shell *,
  .axis-live-dot, .axis-pill--live i, .axis-pill--live .axis-pill-dot,
  .axis-skeleton, .axis-ambient::before, .axis-ambient::after,
  .axis-dialog, .axis-drawer, .axis-menu, .axis-popover, .axis-toast, .axis-enter {
    animation: none !important;
    transition: none !important;
  }
}

/* Ниже порога касания цель берёт свой размер (ui-foundation.md §6 и §9):
   значок остаётся мелким, а область нажатия вокруг него 44px. Правило стоит
   на уровне системы: компонент, добирающий цель в продукте, добирает её по-своему. */
@media (max-width: 767px) {
  .axis-btn { height: var(--axis-control-lg); }
  .axis-btn--sm { height: var(--axis-control-lg); }
  .axis-btn--sm.axis-btn--icon { width: var(--axis-control-lg); }
  .axis-segment { min-height: var(--axis-control-lg); }
  a.axis-pill, .axis-pill[role="button"] { min-height: var(--axis-control-lg); }
  .axis-tab { min-height: var(--axis-control-lg); }
}

/* ═══ Utilities ═════════════════════════════════════════════════════════════ */

.axis-grow { flex: 1 1 auto; min-width: 0; }
.axis-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.axis-nowrap { white-space: nowrap; }
.axis-sep-top { border-top: 1px solid var(--axis-line); padding-top: var(--axis-gap-group); }
.axis-t-xs { font-size: var(--axis-text-xs); }
.axis-t-sm { font-size: var(--axis-text-sm); }
.axis-t-2xs { font-size: var(--axis-text-2xs); }
.axis-visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}
