/* app/public/app.css — our additions to the prototype stylesheet. styles.css stays a byte copy of the prototype. */

/* menu items that are not built yet */
.side-link.is-soon{color:var(--muted);opacity:.55;cursor:default}
.side-link.is-soon:hover{background:transparent;color:var(--muted)}
.side-link.is-soon>span:not(.nav-count){white-space:nowrap}                            /* V1: the label never wraps onto two lines */
.nav-soon{color:var(--muted)}
/* V1: in the sidebar the badge is plain small muted text, not a chip - .nav-count's chip width is what breaks the
   longer Russian labels. `.settings-nav .nav-soon` below is unaffected: it has no `.side-link` ancestor to match. */
.side-link .nav-soon{flex:none;font-size:10px;padding:0;border-color:transparent;background:transparent;color:var(--muted)}
@media (min-width:761px) and (max-width:1250px){.side-link .nav-soon{display:none}}    /* V1: no room for label + badge at 190px; the hint moves to the item's title attribute */
.side-link-gap{margin-top:26px}

/* phone: the open menu goes above the page. The prototype stylesheet raises .workspace (z-index 26) over the sidebar (25),
   so a tap on a menu link lands on the page and the page text shows through the menu. The sidebar's shadow still dims the
   page. */
@media (max-width:760px){.mobile-nav-open .sidebar{z-index:27}}
/* The open phone menu (owner, 2026-09-28; src/components/shell/mobile-menu.ts): a tap anywhere beside it - on the page or
   the header - lands on the backdrop, over the page (26, placed after it) and under the menu (27), and closes it; the
   menu scrolls on its own when it is taller than the screen, never handing the scroll on to the page, which is held
   still meanwhile (the class on <html>). The desktop's "Collapse sidebar" has no meaning in a menu that slides in:
   it is gone here, and a sidebar collapsed on a desktop (the cookie is the account's, not the device's) opens as the
   full menu - the prototype's collapsed rules, which know no widths, undone. The menu itself takes the focus when it
   opens (tabindex -1): no ring on it. */
.mobile-nav-backdrop{display:none}
html.mobile-nav-lock,html.mobile-nav-lock body{overflow:hidden}
.sidebar:focus{outline:none}
@media (max-width:760px){
  .mobile-nav-backdrop{display:block;position:fixed;inset:0;z-index:26;background:transparent}
  .sidebar{overflow-y:auto;overscroll-behavior:contain}
  .collapse-button{display:none}
  .sidebar-collapsed .sidebar{width:216px;padding-left:16px;padding-right:16px}
  .sidebar-collapsed .brand{padding:0 8px}
  .sidebar-collapsed nav{margin-top:28px}
  .sidebar-collapsed .side-link{padding:0 12px}
  .sidebar-collapsed .brand>span:last-child,.sidebar-collapsed .side-link>span,.sidebar-collapsed .profile-button>span:not(.avatar),.sidebar-collapsed .profile-button>.icon{display:inline}
  .sidebar-collapsed .demo-note{display:block}
  .sidebar-collapsed .profile-button{justify-content:flex-start}
}

/* The sidebar's bottom (owner, 2026-09-28): the collapse toggle stands on the initials' axis, and neither moves when the
   sidebar collapses. The toggle's icon gets the avatar's 34px box (17px icon, 8.5px each side) and both buttons the same
   4px side padding, so the axis is 16 + 4 + 17 = 37px from the left in the open sidebar; collapsed, both are centred
   in its 74px (12 + 4 + 42 / 2 = 37px). Collapsed, the icon turns round: it now opens the sidebar. */
.profile-button{padding-left:4px;padding-right:4px}
.collapse-button{width:100%;padding-left:4px;padding-right:4px}
.collapse-button>.icon{margin:0 8.5px}
.sidebar-collapsed .collapse-button>.icon{transform:scaleX(-1)}

/* Focus rings (owner, 2026-09-28: "the thick blue frame" around a window's close button and around the tenant list).
   The prototype's ring is 3px of solid accent 3px off every button, link, field and row the keyboard reaches - and a
   browser lights it up after a click too where the focus is moved by the page (a window opening on its first control)
   or where a field is typed in. The windows now take the focus themselves (src/components/Dialog.tsx), and the ring
   left for the keyboard is a thin, softer one; a text field shows its focus by its border and a soft halo instead,
   the tenant list (a bare word in the header) by a thin underline. */
button:focus-visible,a:focus-visible,input:focus-visible,select:focus-visible,tr:focus-visible{outline:2px solid color-mix(in srgb,var(--accent) 55%,transparent);outline-offset:2px}
tr:focus-visible{outline-offset:-2px}
.form-control:focus,.form-select:focus{border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 14%,transparent)}
.form-control:focus-visible,.form-select:focus-visible{outline:none}
.sd-dialog:focus{outline:none}
.tenant-select:focus{outline:none}
.tenant-select:focus-visible{outline:none;box-shadow:inset 0 -2px 0 color-mix(in srgb,var(--accent) 55%,transparent)}

/* the service pages link stands where the prototype has its demo note */
.service-note a{color:inherit;text-decoration:none;display:block}
.service-note a:hover strong{color:var(--accent)}
.service-note small{margin-left:0}

/* the header's avatar is a button that opens the profile window (part 5a spec A2), as in the prototype: no padding of
   its own, the avatar's box is the button's */
button.top-avatar{padding:0}

/* freshness is a button now (spec 2026-09-23 A5), not a link to the sync page - kept the same understated look */
.freshness{text-decoration:none}
.freshness:hover{color:var(--ink)}
.freshness.is-warning{color:var(--orange)}
.freshness .icon.spin{animation:sd-spin 1.2s linear infinite}
@keyframes sd-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.freshness .icon.spin{animation:none}}
/* an executor's and a viewer's badge (part 5b R2): the same look, no button - "sync everything" is not theirs */
.freshness.is-static{cursor:default}
.freshness.is-static:hover{color:var(--muted)}
.freshness.is-static.is-warning:hover{color:var(--orange)}
/* narrow screens (fix wave of part A): the prototype hides the badge at <=760px, which left the owner's ~756px
   window and every phone without it. Here it stays as an icon-only button - the same refresh or warning icon,
   spinning while a sync runs - sized like the header's other icon buttons (`.icon-button`). Its text is gone from
   view but not lost: it names the button (aria-label) and is the first line of its title
   (src/components/shell/Freshness.tsx). Same specificity as the prototype's hiding rule, later in the cascade. */
@media (max-width:760px){
  .freshness{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;gap:0;border-radius:5px;flex-shrink:0}
  .freshness>span{display:none}
  .freshness .icon{width:17px;height:17px}
  .freshness:hover{background:var(--canvas)}
  .freshness.is-static:hover{background:transparent}
  /* the static badge (an executor's, a viewer's) is no button: no aria-label names it, so its text is hidden from view
     only - the pattern of `.visually-hidden` - and a screen reader still reads it (review of part 5b) */
  .freshness.is-static{position:relative}
  .freshness.is-static>span{display:block;position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
  /* while the phone menu is open the prototype pushes the topbar 216px right and its tools already run off the
     screen (a horizontal overflow of its own); the badge sits that out rather than lengthen it */
  .mobile-nav-open .freshness{display:none}
}

/* settings sections are links (the prototype styles buttons) */
.settings-nav a,.settings-nav span[aria-disabled]{padding:12px;color:var(--muted);text-align:left;display:flex;align-items:center;justify-content:space-between;border-radius:6px;font-size:13px;text-decoration:none}
.settings-nav a:hover{color:var(--ink)}
.settings-nav a.active{color:var(--accent);background:var(--accent-soft)}
.settings-nav span[aria-disabled]{opacity:.55;cursor:default}
.settings-nav .nav-soon{font-size:11px}

/* the report dims while the server recomputes */
.kpi-report{transition:opacity .15s}
.kpi-report[aria-busy="true"]{opacity:.55;pointer-events:none}
@media (prefers-reduced-motion:reduce){.kpi-report{transition:none}}

/* the Attention queue dims the same way while the server recomputes it (spec 2026-09-19 §5); the My tasks
   "choose an employee" prompt (fix F5) shares the same rule instead of a second one, since it is the same card in
   every way that matters here - just without a queue to show yet */
.queue-card,.mytasks-pick{transition:opacity .15s}
.queue-card[aria-busy="true"],.mytasks-pick[aria-busy="true"]{opacity:.55;pointer-events:none}
@media (prefers-reduced-motion:reduce){.queue-card,.mytasks-pick{transition:none}}

/* the Tickets catalog explorer dims the same way while the server recomputes it (spec 2026-09-19-tickets-catalog-design §6) */
.ticket-explorer{transition:opacity .15s}
.ticket-explorer[aria-busy="true"]{opacity:.55;pointer-events:none}
@media (prefers-reduced-motion:reduce){.ticket-explorer{transition:none}}
/* the explorer toolbar's "Excel" link (spec 2026-09-23 C2) is a .btn among the toolbar's 15px icons (styles.css
   .queue-controls .icon); Tabler's own .btn .icon min-width would stretch its icon's box to 20px */
.queue-controls .btn{--tblr-btn-icon-size:15px}

/* the Statistics report card dims the same way while the server recomputes it (spec 2026-09-20-statistics-design §5) */
.statistics-report{transition:opacity .15s}
.statistics-report[aria-busy="true"]{opacity:.55;pointer-events:none}
@media (prefers-reduced-motion:reduce){.statistics-report{transition:none}}

/* the Statistics table's own row/total link icon (spec 2026-09-20-statistics-design §2.6): same size as the KPI
   performance tables' branch-ticket-link icon - styles.css scopes that rule to .performance-table only, and the
   statistics-table is a .generic-table instead. */
.statistics-table .branch-ticket-link .icon{width:16px;height:16px;opacity:1}

/* sortable column headers (spec 2026-09-23 A7, src/components/SortHeader.tsx): the look styles.css gives the KPI
   tables' own (`.performance-table thead th button`, which still applies there, with the same values), now for the
   Statistics, Tickets and Attention tables too - a bare button with the label and the sort icon, the sorted column in
   the accent colour. The icon keeps its size where a long label wraps (Statistics' last column). */
.sort-button{border:0;background:none;color:inherit;font:inherit;padding:0;display:flex;align-items:center;gap:4px}
.sort-button .icon{width:12px;height:12px;opacity:.5;flex-shrink:0}
th[aria-sort] .sort-button{color:var(--accent)}
/* the Attention and Tasks queues on a narrow screen (fix wave of part A; Tasks sorts since part B): at <=760px the
   prototype turns the queue table into cards and hides its header row (`.ticket-table thead{display:none}`), and the
   sort buttons with it - the owner's ~756px window among others. The header comes back as a wrapping row of those
   buttons above the cards, only where it has them (`:has(.sort-button)`): a table with plain headers keeps the
   prototype's look.
   "Age" stays in the row although the prototype hides the Age cells here (the `!important` answers the prototype's
   own `.age-col{display:none!important}`); between 761 and 1550px the prototype hides the whole Age column, header
   included, and that is left as it is. The owner cell's phone position (absolute, then static with a bottom margin)
   is a cell's, taken back for the header. */
@media (max-width:760px){
  .ticket-table thead:has(.sort-button){display:block;border-bottom:1px solid var(--line)}
  .ticket-table thead:has(.sort-button) tr{display:flex;flex-wrap:wrap;align-items:center;gap:8px 18px;padding:12px 16px;border:0}
  .ticket-table thead:has(.sort-button) th{display:block;width:auto!important;padding:0;margin:0;border:0;position:static;background:none}
  .ticket-table thead:has(.sort-button) th.age-col{display:block!important}
  .ticket-table thead:has(.sort-button) th.row-arrow{display:none!important}
}

/* the Tasks screen's "view as" performer selector, in the heading (spec 2026-09-20-my-tasks-design §6), and since
   spec 2026-09-23 B4 the Attention screen's own performer FILTER beside it (`.attention-person`) - the prototype
   heading has no such control on either screen, so nothing already fits it: an inline label instead of the stacked
   .kpi-filter-field, and a field width that fits a person's name. The width is fixed by default: some Pyrus names
   are long, and a field left to size itself on content pulls in its widest name's width, which overflowed the
   viewport on a phone. 320px (min 260px) rather than the screen's own text width (spec 2026-09-23 A3: wide enough
   that a long name is rarely cut) - the Attention field's extra "All performers" entry is no longer than a real
   name, so it needs no width of its own. At phone width `.my-heading`/`.attention-heading` (below) let the field flex
   instead - safe only because of its `min-width:0`. Since spec 2026-09-23 A1 the field is a searchable list
   (.search-select below): the width sits on its `.search-select-control`, the box around the button and its panel. */
.my-person,.attention-person{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--muted)}
.my-person .search-select-control,.attention-person .search-select-control{width:320px;min-width:260px}

/* fix P1: `.page-heading` (styles.css) is `display:flex;justify-content:space-between` with no wrap, so the
   selector used to sit squeezed beside the title, wrapping «Задачи» onto two lines and the subtitle onto four.
   `.my-heading` (this screen's own modifier class) lets the heading wrap instead - folding in the `.my-person`
   phone rule this screen briefly had, which fixed the selector's own width but not the still-unwrapped heading
   around it. `.heading-actions` then takes the freed second row, and within it the selector - the wider of its two
   controls since the KPI report button left the heading (spec 2026-09-23 A8) - grows to fill whatever the date
   leaves free, the field itself included (`min-width:0` is what lets a flex item actually shrink to its own
   ellipsis instead of overflowing). `.attention-heading` (spec 2026-09-23 B4) gives the Attention screen's own
   performer filter the identical treatment, for the identical reason - the same rules, just under the two screens'
   own heading classes, so this stays one definition instead of two copies.
   The wrap itself reaches up to 900px (fix wave of part A): between 761 and 900px the 190px sidebar leaves the
   heading too little room beside the 320px picker, and the subtitle squeezed into three lines - the picker now
   takes the second row there too, at its own width; only a phone stretches it across the row. */
@media(max-width:900px){.my-heading,.attention-heading{flex-wrap:wrap}}
@media(max-width:760px){
  .my-heading .heading-actions,.attention-heading .heading-actions{width:100%;justify-content:space-between}
  .my-heading .my-person,.attention-heading .attention-person{flex:1;min-width:0}
  .my-heading .my-person .search-select-control,.attention-heading .attention-person .search-select-control{width:auto;flex:1;min-width:0}
}

/* the ticket card's <details> blocks - description, "How SLA is calculated" and, since spec 2026-09-23 A4, the
   event timeline too - the prototype never had any of these; styled to match the card's own type instead of the
   browser's default marker and spacing. (.timeline's own line needs nothing extra: styles.css already sets
   `.timeline small{display:block}`.) */
.detail-panel details,.full-ticket details{margin:14px 0;font-size:13px}
.detail-panel summary,.full-ticket summary{cursor:pointer;font-weight:500;color:var(--ink)}
.detail-panel details p,.full-ticket details p{color:var(--muted);margin:8px 0 0}
.ticket-description{white-space:pre-wrap}

/* spec 2026-09-23 A4: while a dialog is open (the ticket card, but "any window on top of the page" - every
   <dialog class="sd-dialog"> the app opens with showModal(), not just .detail-panel) the page behind it must not
   scroll on a phone. styles.css bounds .sd-dialog's own height (max-height:90vh, or height/max-height:100vh once
   .detail-panel is added) and gives THAT element `overflow:auto` - .dialog-body has no height or overflow of its
   own - so .sd-dialog, not .dialog-body, is what actually scrolls, and so is where `overscroll-behavior` belongs:
   it stops a scroll gesture that reaches the dialog's own top/bottom edge from chaining to whatever is behind it.
   `html:has(dialog[open])` belts that by removing the document's own scroll entirely while any dialog is open, so
   there is nothing left behind it to chain into. `:has()` ships in Safari >= 15.4 and Chrome >= 105; both engines
   have shipped `overscroll-behavior` for longer than that. No `touch-action` or JS: showModal() already makes the
   rest of the document non-interactive (no click or tap reaches it), which is most of why CSS alone should be
   enough on iOS too - worth confirming on a real phone after deploy, same as this list's other device-only items. */
html:has(dialog[open]){overflow:hidden}
.sd-dialog{overscroll-behavior:contain}
/* the ticket card's side panel is as tall as the VISIBLE viewport (fix wave of part A): on iOS `100vh` is the height
   with the address bar hidden, so while the bar shows the panel's bottom - the end of the card - sits below the
   screen and cannot be scrolled to. `dvh` follows the bar; the `vh` lines stay as the fallback for a browser without
   it (the prototype's own values, styles.css). */
.detail-panel{height:100vh;height:100dvh;max-height:100vh;max-height:100dvh}
/* «Открыть в Pyrus» in the ticket's headings (the owner, 2026-09-30; src/components/ticket/PyrusLink.tsx): in sight
   without scrolling, beside the number. The side panel's heading: the number and its chips on the left - wrapping onto
   a second line rather than pushing the buttons off - the link and the close button on the right. Its short caption,
   «Pyrus», only where the full one would not fit beside the number (a phone). */
.dialog-heading-tools{display:flex;align-items:center;gap:8px;flex:none}
.detail-panel .dialog-heading{gap:12px}
.detail-panel .dialog-heading h2{display:flex;flex-wrap:wrap;align-items:center;gap:6px;min-width:0;margin:0}
.pyrus-link{white-space:nowrap}
.pyrus-link-short{display:none}
@media(max-width:560px){
  .detail-panel .dialog-heading{padding:14px 16px}
  .detail-panel .pyrus-link-full{display:none}
  .detail-panel .pyrus-link-short{display:inline}
}
/* The full page's heading: its two buttons side by side, never one under the other beside a long title. On a phone the
   prototype shrinks heading buttons to a bare icon; here the two keep their captions on a row of their own under the
   number and the title - the whole of «Открыть в Pyrus» in sight. */
.ticket-heading .heading-actions{flex:none;gap:8px}
@media(max-width:760px){
  .ticket-heading{flex-wrap:wrap;gap:12px}
  .ticket-heading .heading-actions{width:100%;gap:8px}
  .ticket-heading .heading-actions .btn{font-size:var(--tblr-btn-font-size);width:auto;padding:var(--tblr-btn-padding-y) var(--tblr-btn-padding-x);gap:7px}
  .ticket-heading .heading-actions .btn .icon{margin:0 calc(var(--tblr-btn-padding-x)/ 2) 0 calc(var(--tblr-btn-padding-x)/ -4)}
}

/* the extra Attention button, "No answer" (docs/07 §7; fourth of five since 2026-09-29, before "On pause"). The prototype's own attention row has four
   buttons and styles.css pins `.attention-metrics` to four columns; five is the prototype's DEFAULT
   (`.status-metrics`), which the prototype's five-button My tasks row (`.task-metrics`) used - so this only takes the
   four-column override back off.
   A media query adds no specificity, so every width is settled by source order inside this file: the plain rule
   beats styles.css everywhere, and the blocks below beat the plain rule at their own widths. Scoping the plain rule
   to `min-width:761px` instead would leave the widths between 760 and 761 (reachable by browser zoom) to the
   prototype's four-column rule. */
.status-metrics.attention-metrics{grid-template-columns:repeat(5,minmax(0,1fr))}
/* 600-760px: the five buttons stay in ONE row (owner's decision 2026-09-21 - his browser window is about 756px,
   half of a 1512px laptop screen, and the last button alone on a row of its own reads as a different thing). The
   prototype's phone rules make the cards too large for five columns there, so this band tightens them: less
   padding, a smaller label and value, and the icon dropped - the prototype drops it itself between 761 and 1050px,
   for the same lack of room. The labels then take two lines and the cards keep equal heights, because grid items
   stretch and `.metric-bottom` is pushed down by its own `margin-top:auto` (styles.css). */
@media(min-width:600px) and (max-width:760px){
  .status-metrics.attention-metrics{gap:8px}
  .status-metrics.attention-metrics .metric-card,
  .status-metrics.attention-metrics .metric-card:last-child{padding:11px 10px 12px;gap:8px}
  .status-metrics.attention-metrics .metric-label{font-size:11px;line-height:1.35}
  .status-metrics.attention-metrics .metric-label .icon{display:none}
  .status-metrics.attention-metrics .metric-bottom strong{font-size:24px}
}
/* below 600px the prototype's phone layout stands: two, two, and the odd fifth card across the full width, as the
   prototype's five-button My tasks row had it - styles.css gives every `.status-metrics .metric-card:last-child`
   that `grid-column:1/-1` and only the four-button attention row cancels it. */
@media(max-width:599px){
  .status-metrics.attention-metrics{grid-template-columns:repeat(2,minmax(0,1fr))}
  .status-metrics.attention-metrics .metric-card:last-child{grid-column:1/-1}
}

/* the Tasks screen's three buttons (spec 2026-09-23 B1: "To do (mine)", "To do (my group)", "Waiting" - the
   prototype's row had five): the same cards, three to a row at every width. The default five columns would leave two
   empty slots, and the prototype's phone layout (two, then the last card across the full width as a strip of its own)
   would set "Waiting" apart as a different kind of thing - the reason Attention keeps its five in one row at 756px
   (owner's decision 2026-09-21). The plain rule beats styles.css's two-column phone rule by specificity. */
.status-metrics.task-metrics{grid-template-columns:repeat(3,minmax(0,1fr))}
/* <=760px: styles.css makes the LAST card of any row that full-width strip (`.metric-card:last-child`: across the
   grid, a row inside, less padding, a smaller value, no icon; `.task-metrics` already undoes the row). Here it stays
   one card of three, exactly like its two neighbours. */
@media(max-width:760px){
  .status-metrics.task-metrics .metric-card:last-child{grid-column:auto;padding:15px 13px}
  .status-metrics.task-metrics .metric-card:last-child .metric-bottom strong{font-size:32px}
  .status-metrics.task-metrics .metric-card:last-child .metric-label .icon{display:block}
}
/* below 600px three cards share a phone's width (about 110px each at 375px): the tightening Attention's five cards
   get between 600 and 760px - less padding, a smaller label and value, no icon. The labels take two lines and the
   cards keep equal heights (grid items stretch; `.metric-bottom` sits at the bottom by its own `margin-top:auto`). */
@media(max-width:599px){
  .status-metrics.task-metrics{gap:8px}
  .status-metrics.task-metrics .metric-card,
  .status-metrics.task-metrics .metric-card:last-child{padding:11px 10px 12px;gap:8px}
  .status-metrics.task-metrics .metric-label{font-size:12px;line-height:1.35}
  .status-metrics.task-metrics .metric-label .icon,
  .status-metrics.task-metrics .metric-card:last-child .metric-label .icon{display:none}
  .status-metrics.task-metrics .metric-bottom strong,
  .status-metrics.task-metrics .metric-card:last-child .metric-bottom strong{font-size:24px}
}

/* "No response" gets a colour of its own (owner's decision 2026-09-21). The prototype paints it the same red as
   "breached" (`.status-chip.noresponse`, `.sla-track.noresponse span`, `.sla-time.noresponse`) and left the two
   states indistinguishable on the screen. Violet is far enough from the red, the orange and the accent blue to
   read at a glance. Both tones are picked to sit beside the existing red/orange pairs in contrast - light:
   ~5.4:1 on white, where the red is ~4.6:1; dark: ~6.6:1 on the surface, where the red is ~6.1:1 - and the dark
   theme is declared the way styles.css declares it, on `[data-bs-theme=dark]`. */
:root{--violet:#7d4fc7;--violet-soft:#f3eeff}
[data-bs-theme=dark]{--violet:#b79cf5;--violet-soft:#332a4d}
.status-chip.noresponse{color:var(--violet);background:var(--violet-soft)}
.sla-track.noresponse span{background:var(--violet)}
.sla-time.noresponse{color:var(--violet)}
.metric-card.noresponse strong,.metric-card.noresponse .icon{color:var(--violet)}
.metric-card.noresponse .metric-underline{background:var(--violet);opacity:.6}

/* the "message without a reply" flag: under the ticket title in a queue row, and under the heading on the card
   (docs/07 §7). Same size and rhythm as the row's own `.personal-status` line, in the colour the product uses for
   "somebody is waiting". */
.unanswered-flag{font-size:11px;color:var(--orange);margin:7px 0 0;font-weight:500}

/* Every status chip of a queue row (2026-09-28, src/components/ticket/StatusChip.tsx `StatusChips`): side by side in
   their fixed order, each in its state's own colour (styles.css; "No response" violet above, "Paused" the plain grey
   chip), wrapping onto a second line where the SLA column is narrow - on a phone too. The unanswered message of a
   closed row is a chip now, in the orange its flag has always had; a chip never shares a row with "At risk" (that one
   is always open, this one always closed). The row's "Due" line under the bar keeps the prototype's `.pyrus-due` look
   but may wrap: "Срок: на паузе, осталось 5 ч" is longer than a date. */
.status-chips{display:flex;flex-wrap:wrap;gap:4px}
.status-chip.unanswered{color:var(--orange);background:var(--orange-soft)}
.sla-due{white-space:normal}

/* the "Technical service" tag at the end of the ticket card's service line (spec 2026-09-23 C4): the catalog's own
   status badge (`.neutral-badge`, styles.css), set off from the text before it; `middle` keeps its 11px box from
   pushing the line taller than the text around it. Fix wave 2026-09-23 C item 4: when the card has neither a service
   nor a priority the tag is the only thing on the line (TicketSections.tsx then adds `.is-solo`) and gets no left
   margin - a plain sibling selector cannot key off "the text before it is empty", since that text is a bare string,
   never an element, so the tag is `.muted`'s only child ELEMENT (and would match `:first-child`/`:only-child`) in
   both cases alike; `.is-solo` is the one bit the component adds to tell them apart. */
.technical-mark{margin-left:8px;vertical-align:middle;white-space:nowrap}
.technical-mark.is-solo{margin-left:0}

/* the ticket's current Pyrus status in a queue row's meta line, after the service name (owner's decision
   2026-09-21): a small muted label, quieter than the service and never translated - it is Pyrus's own word.
   `.service-name` (styles.css) is the neighbour whose muted tone it matches; unlike it, this one is never cut with
   an ellipsis - «Pending User Response» half-shown would be worse than not shown at all.
   `.ticket-meta` is a single-line flex row in the prototype, so a fourth item would widen the table's own
   min-content instead of giving way. Not a narrow viewport band, as first measured (760-1050 px): `styles.css`
   caps the table's own first column at `max-width:400px` (`.ticket-table td:first-child`), so once a long service
   name and a long status together outgrow that fixed width, the meta line needs two lines AT ANY WINDOW WIDTH.
   Letting it wrap puts the status on its own second line there instead of forcing a horizontal PAGE scroll
   (measured: 898 px of content in an 865 px window), and changes nothing at any width where it already fits. */
.ticket-meta{flex-wrap:wrap}
.pyrus-status{color:var(--muted);white-space:nowrap}

/* the tenant a queue row, a "since yesterday" block or a ticket card belongs to, on the screens of every tenant (spec
   2026-09-23 D5; QueueTable.tsx, DigestCard.tsx, TicketDrawer.tsx): the catalog's own badge (`.neutral-badge`,
   styles.css) in the accent's tone and the size of the row's priority chip - a label, not one more status. `middle`
   keeps it on the line of the heading text beside it. */
.tenant-tag{color:var(--accent);background:var(--accent-soft);border-color:transparent;padding:1px 6px;font-size:10px;font-weight:500;line-height:1.5;white-space:nowrap;vertical-align:middle}

/* the searchable filter lists (spec 2026-09-23 A1, src/components/SearchSelect.tsx): the filters of KPI,
   Statistics and Tickets, and the Tasks performer picker.
   The closed field is the same `.form-select` as the native select it replaced, only a <button> now - and a button
   centres its text and wraps it, where a select starts it at the left and cuts it off - so just those two are taken
   back. Its caption is a <label> now, where it was a <span>: it gets the spacing styles.css gives
   `.kpi-filter-field>span`. A field with a help text (`help`) puts the caption and the prototype's help icon in one
   row, `.search-select-caption`, which takes that spacing over. */
.search-select-control{position:relative;min-width:0}
.search-select-toggle{text-align:start}
.search-select-value{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.search-select-toggle[aria-expanded="true"]{border-color:var(--accent)}
.kpi-filter-field.search-select>label{display:block;margin-bottom:6px}
.search-select-caption{display:flex;align-items:center;gap:6px;margin-bottom:6px}
/* its help opens to the right of the icon, not centred on it: a caption starts at its field's left edge, which on a
   phone is the card's own, so a centred text would run off the screen */
.search-select-caption .help-tooltip>span{left:-10px;transform:none;max-width:calc(100vw - 48px)}
/* The open panel: right under the field, at least as wide as the field, at most 28rem or the viewport less a 16px
   gutter on each side - the page's own phone gutter, PANEL_GUTTER in src/lib/search-select.ts, which also moves the
   panel left when it would cross the right gutter - so it never widens the page. The entries wrap rather than widen
   it. Above the cards and the sticky table columns (z-index 1-2), under the sidebar (25) and the help tooltips (30).
   The prototype's own tokens throughout, so the dark theme needs only a deeper shadow. */
.search-select-panel{position:absolute;top:calc(100% + 4px);left:0;z-index:20;min-width:100%;width:max-content;max-width:max(100%,min(28rem,calc(100vw - 32px)));background:var(--surface);color:var(--ink);border:1px solid var(--line);border-radius:8px;box-shadow:0 10px 30px #1828401f;font-size:13px;line-height:1.4;overflow:hidden}
[data-bs-theme=dark] .search-select-panel{box-shadow:0 10px 30px #0009}
.search-select-search{display:flex;align-items:center;gap:6px;padding:8px 10px;border-bottom:1px solid var(--line)}
.search-select-search:focus-within{border-bottom-color:var(--accent)}
.search-select-search .icon{width:15px;height:15px;color:var(--muted)}
.search-select-search input{flex:1;width:0;min-width:0;border:0;outline:none;padding:2px 0;background:transparent;color:var(--ink);font-size:13px}
.search-select-search input::placeholder{color:var(--muted);opacity:1}
/* iOS zooms the page into a text box whose text is smaller than 16px; on a touch screen the search box is that size */
@media (pointer:coarse){.search-select-search input{font-size:16px}}
/* position:relative makes the list its entries' offsetParent: the component scrolls a highlighted entry into view by
   its offsetTop, which must count from the list, not from the panel above it */
.search-select-list{position:relative;list-style:none;margin:0;padding:4px;max-height:min(300px,45vh);overflow-y:auto}
.search-select-list>li{padding:7px 10px;border-radius:5px;cursor:pointer;overflow-wrap:anywhere}
.search-select-list>li.active{background:var(--accent-soft)}
.search-select-list>li[aria-selected="true"]{color:var(--accent);font-weight:600}
/* "All …" stays on top whatever is typed; a thin line keeps it apart from the matches below it */
.search-select-list>li.search-select-all{position:relative;margin-bottom:9px}
.search-select-list>li.search-select-all::after{content:'';position:absolute;left:10px;right:10px;bottom:-5px;border-top:1px solid var(--line)}
.search-select-empty{margin:0;padding:2px 14px 10px;color:var(--muted)}
.search-select-empty:empty{padding:0}

/* The Tickets period row (spec 2026-09-23 C1): KPI's own row (`.report-controls.kpi-period-row` in styles.css) with
   KPI's own control (src/components/PeriodControl.tsx), the dates it resolved to under it, and "Include tickets" on
   the right with its caption level with the control's. It replaces the prototype's `.ticket-period-filters` grid of
   two date fields and that list. Two rules of the Tickets card would make the control differ from KPI's, so they are
   taken back here: `.ticket-filter-card .form-select` (13px, full width) over the year select, and styles.css scoping
   its phone rules for the segments to `.kpi-filter-card`. The one difference left is the year list's width: KPI's
   102px, or its widest entry - "All years" / «Все годы», which 102px would cut. Below 760px each part takes the whole
   row, as KPI's tools do. */
.ticket-period-row{align-items:flex-start}
.ticket-period-row .period-dates{margin-top:10px}
.ticket-period-row .ticket-basis{flex:0 1 320px;min-width:220px}
.ticket-filter-card .kpi-period-tools .kpi-report-year{width:auto;min-width:102px;padding-right:36px;font-size:.875rem}
@media(max-width:760px){.ticket-period-row>*,.ticket-period-row .ticket-basis{flex:1 1 100%;min-width:0}.ticket-filter-card .kpi-period-tools .kpi-report-year{width:100%;min-width:0}}
@media(max-width:700px){.ticket-filter-card .period-segments{gap:0}.ticket-filter-card .period-segments button{padding:7px 12px}}
@media(max-width:380px){.ticket-filter-card .period-segments button{padding:7px 9px}}
/* The Tickets filters (the owner, 2026-09-30): no "Additional filters" disclosure and no "People" / "Data" groups any
   more - every filter in one grid under the period row, as many columns as fit (five at 1100 px with the sidebar, two on
   a phone), so the whole set is in sight in a few rows. A caption that wraps (the longer Russian ones) keeps its field
   level with its neighbours': the fields sit on the row's bottom line. */
.ticket-filter-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:12px 14px;align-items:end;padding:18px 22px}
@media(max-width:760px){.ticket-filter-grid{grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:12px;padding:16px}}
/* narrow fields, so less room kept around the value: the chevron closer to the edge, the text starting nearer it */
.ticket-filter-card .ticket-filter-grid .search-select-toggle{padding-left:10px;padding-right:28px;background-position:right 8px center}

/* The People screen (spec 2026-09-23 D2, D3, D4; src/components/people/*). The prototype's peoplePage() is one card
   with a plain table; here the merge suggestions come first, then the employee table with its search and two filters,
   and the employee card is the ticket card's side panel. Built from the prototype's own parts - card, card-heading,
   queue-toolbar/search-field, generic-table, person/avatar, neutral-badge, status-chip - and its tokens, so the dark
   theme needs nothing of its own. A card dims while its change or its navigation is on the way, like the queues. */
.people-suggestions,.people-directory{margin-bottom:22px}
.people-suggestions,.people-directory,.people-card-panel .dialog-body>div{transition:opacity .15s}
.people-suggestions[aria-busy="true"],.people-directory[aria-busy="true"],.people-card-panel .dialog-body>div[aria-busy="true"]{opacity:.55;pointer-events:none}
@media (prefers-reduced-motion:reduce){.people-suggestions,.people-directory,.people-card-panel .dialog-body>div{transition:none}}
.people-suggestions h2 .number-badge,.people-directory h2 .number-badge{margin-left:8px}
/* the outcome of the last change: a line of its own, no room at all while there is none */
.people-status{margin:0 20px 12px;font-size:13px}
.people-status:empty{display:none}
.people-status.is-ok{color:var(--green)}
.people-status.is-error{color:var(--red)}
.people-card-panel .people-status{margin:0 0 12px}

/* a suggestion: its reason on top, then the two employees side by side and the two buttons */
.people-suggestions-none{margin:0;padding:0 20px 20px;color:var(--muted);font-size:13px}
.people-suggestion-list{list-style:none;margin:0;padding:0}
.people-suggestion{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px 16px;padding:14px 20px;border-top:1px solid var(--line)}
.people-reason{grid-column:1/-1;justify-self:start}
.people-reason.is-similar{color:var(--orange);background:var(--orange-soft);border-color:transparent}
.people-pair{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.people-side{border:1px solid var(--line);border-radius:8px;padding:10px 12px;min-width:0}
.people-side-name{display:block;font-weight:600;font-size:14px;margin-bottom:6px;overflow-wrap:anywhere}
.people-side-accounts{list-style:none;margin:0;padding:0;display:grid;gap:6px;font-size:12px}
.people-side-accounts>li{display:flex;flex-wrap:wrap;align-items:center;gap:4px 8px;color:var(--muted)}
.people-side-accounts>li.is-evidence{color:var(--ink)}
.people-account-name{font-weight:500}
.people-email{overflow-wrap:anywhere}
.people-suggestion-actions{align-self:center}
.people-suggestions-more{padding:12px 20px;border-top:1px solid var(--line)}

/* the table's search and filters: the catalog's toolbar, with "Tenant", "State", "Team", "Pyrus roles" and "Only
   merged" on the right - the three of 2026-09-25 narrower than "Tenant", their values being short */
.people-toolbar .search-field{flex:1 1 260px;max-width:450px}
.people-toolbar .search-field input{font-size:14px;padding:2px 0;min-height:24px;box-shadow:none}
.people-filters{display:flex;align-items:center;flex-wrap:wrap;gap:10px 18px}
.people-tenant,.people-filter{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--muted)}
.people-tenant .search-select-control{width:190px}
.people-filter .search-select-control{width:150px}
.people-merged{display:flex;align-items:center;gap:7px;margin:0;padding:0;min-height:0;font-size:13px;white-space:nowrap}
.people-merged .form-check-input{float:none;margin:0}
.people-table .person{white-space:normal}
.people-table .person small{display:block}
.people-open{font-size:13px;font-weight:500;text-align:start}
/* a cell's tenants, teams and e-mails never break inside: a narrow window scrolls the table sideways (.table-responsive)
   rather than squeezing an address into a column a few letters wide, or "UAE · Ashon" onto two lines */
.people-badges{display:inline-flex;gap:4px}
.people-badges .neutral-badge{white-space:nowrap}
.people-email-list{list-style:none;margin:0;padding:0;font-size:12px;color:var(--muted);white-space:nowrap}
.people-tickets{font-variant-numeric:tabular-nums}

/* the employee card: accounts, then e-mails, then the field to add one */
.people-accounts,.people-emails{list-style:none;margin:0;padding:0}
.people-accounts>li,.people-emails>li{padding:12px 0;border-bottom:1px solid var(--line)}
.people-account-head,.people-email-head{display:flex;align-items:center;flex-wrap:wrap;gap:6px 8px}
.people-account-head strong{font-weight:600;overflow-wrap:anywhere}
.people-detach,.people-remove{margin-left:auto}
.people-account-facts{display:flex;flex-wrap:wrap;gap:4px 14px;margin-top:6px;font-size:12px;color:var(--muted)}
.people-account-facts>*{overflow-wrap:anywhere}
/* "Merge with…": the searchable list of the other employees and its button, set apart in a box of its own - it joins
   two employees for good, whatever the program suggested */
.people-merge-with{margin-top:16px;padding:12px 14px;border:1px solid var(--line);border-radius:8px}
.people-merge-with-row{display:flex;align-items:flex-end;flex-wrap:wrap;gap:8px}
.people-merge-with-field{flex:1 1 240px;min-width:0}
.people-merge-with-field>label{display:block;margin-bottom:6px;font-size:13px;font-weight:500}
.people-merge-with>p{font-size:12px;margin:8px 0 0}
.people-email-head .people-email{font-weight:500}
.people-email-tenants{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}
.people-no-tenant{display:inline-flex;align-items:center;gap:5px;font-size:12px;color:var(--orange)}
.people-no-tenant .icon{width:14px;height:14px;flex-shrink:0}
.people-domains-note{font-size:12px;margin:10px 0 0}
.people-email-form{margin-top:18px}
.people-email-row{display:flex;gap:8px}
.people-email-row .form-control{flex:1;min-width:0}
/* iOS zooms the page into a text box whose text is smaller than 16px */
@media (pointer:coarse){.people-email-row .form-control{font-size:16px}}

/* <=760px: the prototype's phone gutters (15px), the two employees of a suggestion one under the other, the buttons
   under them; the search, each filter's list and "Only merged" each take a row of their own */
@media(max-width:760px){
  .people-suggestion{grid-template-columns:minmax(0,1fr);padding:14px 15px}
  .people-pair{grid-template-columns:minmax(0,1fr)}
  .people-suggestions-none,.people-suggestions-more{padding-left:15px;padding-right:15px}
  .people-status{margin-left:15px;margin-right:15px}
  .people-toolbar .search-field{flex-basis:100%;max-width:none}
  .people-filters{width:100%}
  .people-tenant,.people-filter{flex:1 1 100%;min-width:0}
  .people-tenant .search-select-control,.people-filter .search-select-control{width:auto;flex:1;min-width:0}
  .people-filters .search-select>label{flex:0 0 76px}
}

/* The team editor in People (spec 2026-09-24 T6-T9; the owner's 2026-09-30: "Teams" - a list and one team open beside
   it, no tenant choice of its own): the prototype's `.page-tabs`, `.team-totals` and `.workload-row` (styles.css), plus
   what the prototype's read-only cards never needed - the list of teams (a column of buttons, the one open marked as
   the menu marks its item), the team's editing controls (a remove button per member, "Add member", "Rename" in place,
   "Delete") and the employee card's "Pyrus roles" and "Team" rows. Tokens only, so both themes follow. */
.people-intro{margin:0 0 18px;font-size:13px;color:var(--muted)}
.people-teams{transition:opacity .15s}
.people-teams[aria-busy="true"],.people-team[aria-busy="true"]{opacity:.55;pointer-events:none}
@media (prefers-reduced-motion:reduce){.people-teams{transition:none}}
/* "Create team": its refusal above the fields, the form dimmed while the server answers */
.people-create-team .people-status{margin:0 0 12px}
.people-create-team form[aria-busy="true"]{opacity:.55;pointer-events:none}
.people-create-team .form-hint{margin:10px 0 0}
/* the list and the team open: side by side from 901px, stacked below - the list first */
.people-teams-layout{display:grid;grid-template-columns:minmax(260px,320px) minmax(0,1fr);gap:20px;align-items:start;margin-bottom:22px}
.people-teams-layout.is-empty{grid-template-columns:minmax(0,1fr)}
.people-teams-layout.is-empty .people-team-detail{display:none}
.people-teams-list .card-heading{flex-wrap:wrap;align-items:flex-start}
.people-teams-list .card-heading>div{min-width:0}
.people-teams-list .card-heading h2{display:flex;align-items:center}
.people-teams-list .card-heading .btn{white-space:nowrap}
/* the heading takes the focus when the last team is deleted: marked only for a keyboard */
#people-teams-heading:focus{outline:none}
#people-teams-heading:focus-visible{outline:2px solid color-mix(in srgb,var(--accent) 55%,transparent);outline-offset:2px}
.people-teams-empty{margin:0 20px 20px;padding:18px 20px;border:1px dashed var(--line);border-radius:8px;color:var(--muted);font-size:13px}
.people-teams-search{padding:0 20px 12px}
.people-teams-search .search-field{max-width:none}
.people-teams-search .search-field input{font-size:14px;padding:2px 0;min-height:24px;box-shadow:none}
.people-teams-none{margin:0;padding:4px 20px 20px;font-size:13px}
.people-teams-items{list-style:none;margin:0;padding:0 10px 10px}
.people-teams-item{display:grid;gap:2px;width:100%;text-align:start;border:0;border-radius:6px;background:transparent;color:var(--ink);padding:9px 10px;margin:1px 0}
.people-teams-item:hover{background:var(--canvas)}
.people-teams-item.active{background:var(--accent-soft)}
.people-teams-item.active .people-teams-item-name{color:var(--accent)}
.people-teams-item:focus-visible{outline:2px solid color-mix(in srgb,var(--accent) 55%,transparent);outline-offset:-2px}
.people-teams-item-name{font-weight:600;overflow-wrap:anywhere}
.people-teams-item-facts{display:flex;flex-wrap:wrap;gap:0 12px;font-size:12px;color:var(--muted)}
.people-teams-item-facts .is-breached{color:var(--red)}
@media (min-width:901px){.people-teams-items{max-height:calc(100vh - 290px);min-height:120px;overflow-y:auto}}
@media (max-width:900px){.people-teams-layout{grid-template-columns:minmax(0,1fr)}}
/* the team open */
.people-team-detail{min-width:0;scroll-margin-top:80px}
.people-team:focus{outline:none}
.people-team:focus-visible{outline:2px solid color-mix(in srgb,var(--accent) 55%,transparent);outline-offset:2px}
.people-team .card-heading{flex-wrap:wrap}
.people-team-title{display:flex;align-items:center;flex-wrap:wrap;gap:4px 8px;min-width:0}
.people-team-title h2{margin:0;overflow-wrap:anywhere}
/* "N people" beside a long name: the name wraps, the badge keeps its size and its one line */
.people-team-title .number-badge{white-space:nowrap;flex-shrink:0;margin-left:0}
.people-team-actions{display:flex;flex-wrap:wrap;gap:8px;margin-left:auto}
.people-team .people-status{margin:0 0 12px}
.team-totals strong.is-breached{color:var(--red)}
.people-team-members{font-size:13px;font-weight:600;margin:0 0 12px;padding-top:16px;border-top:1px solid var(--line)}
.people-team-none{margin:0 0 16px}
/* a member: the name may wrap next to its "Inactive" chip; the bar takes what is left, then the count and the remove button */
.people-team .workload-row{margin-bottom:14px}
.people-team .workload-row .person{flex:0 1 48%;min-width:0;white-space:normal}
.people-team .workload-row .person .avatar{flex-shrink:0}
.people-member-name{display:flex;flex-wrap:wrap;align-items:center;gap:2px 6px;min-width:0}
.people-member-name .people-open{font-size:13px;font-weight:500;text-align:start;overflow-wrap:anywhere}
.people-team .workload-track{min-width:24px}
.people-team .workload-row>strong{min-width:20px;text-align:right;font-variant-numeric:tabular-nums}
.people-team-remove{width:24px;height:24px;flex-shrink:0}
.people-team-remove .icon{width:13px;height:13px}
.people-team-add{display:flex;align-items:flex-end;gap:8px;margin:0 0 18px}
.people-team-add-field{flex:1 1 auto;min-width:0}
.people-team-add-field>label{display:block;margin-bottom:6px;font-size:12px;font-weight:500}
/* spec 2026-09-24 T13: an open count split by tenant ("Ashon 5 · FertiStream 2"), each number a link into its tenant's
   catalog - on a line of its own: under the total's label, and under a member's name, so the bars stay one column */
.people-team-tenants{display:block;font-size:12px;font-weight:400;color:var(--muted);white-space:normal;margin-top:3px}
.people-team-tenants>span{white-space:nowrap}
.people-member-name .people-team-tenants{flex-basis:100%;margin-top:0;font-size:11px}
/* "Rename": the field and "Save" / "Cancel" beside it, on a row of their own when the heading is narrow */
.people-team-rename{display:flex;align-items:center;flex-wrap:wrap;gap:6px;flex:1;min-width:0}
.people-team-rename .form-control{flex:1 1 220px;min-width:0}
@media (pointer:coarse){.people-team-rename .form-control{font-size:16px}}
@media(max-width:760px){.people-teams-search{padding:0 15px 12px}.people-teams-items{padding:0 5px 8px}.people-teams-empty{margin:0 15px 15px}.people-teams-none{padding:4px 15px 15px}.team-totals{gap:28px}}
/* the employee card: an account's "Pyrus roles" and "Team", a caption and its value on one row */
.people-account-row{display:flex;align-items:center;flex-wrap:wrap;gap:4px 10px;margin-top:8px;font-size:12px}
.people-account-label,.people-account-row>label{flex:0 0 90px;color:var(--muted)}
.people-account-roles{flex:1;min-width:0;overflow-wrap:anywhere}
.people-account-team .search-select-control{flex:1 1 200px;min-width:0;max-width:280px}

/* Settings → Tenants: one tenant's mail domains (spec 2026-09-23 D4; src/components/settings/MailDomains.tsx) - a
   column of its own in the tenants table: chips with a remove button, a field to add one, and the domains its own
   people's e-mails suggest, as clickable chips with their counts. Built from the People card's own e-mail list and
   `.neutral-badge`, so nothing here needs a color of its own besides the status line's ok/error (`.people-status`). */
.tenant-domains{min-width:220px}
.tenant-alias{min-width:200px}
.tenant-domains-hint{font-size:11px;margin:0 0 8px}
.tenant-domains-status{margin:0 0 8px;font-size:12px}
.tenant-domains-status:empty{display:none}
.tenant-domains-status.is-ok{color:var(--green)}
.tenant-domains-status.is-error{color:var(--red)}
.tenant-domain-chips{list-style:none;margin:0 0 10px;padding:0;display:flex;flex-wrap:wrap;gap:6px}
.tenant-domain-chip{display:inline-flex;align-items:center;gap:4px;color:var(--muted);background:var(--canvas);border:1px solid var(--line);border-radius:4px;padding:3px 4px 3px 8px;font-size:11px}
.tenant-domain-remove{width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;border:0;border-radius:4px;color:var(--muted);background:transparent;flex-shrink:0}
.tenant-domain-remove:hover{color:var(--ink);background:var(--surface)}
.tenant-domain-remove .icon{width:11px;height:11px}
.tenant-domain-add .form-label{font-size:11px;margin-bottom:4px}
.tenant-domain-add-row{display:flex;gap:6px}
.tenant-domain-add-row .form-control{flex:1;min-width:0;font-size:12px;min-height:30px;padding:4px 8px}
.tenant-domain-add-row .btn{font-size:12px;min-height:30px;padding:4px 9px}
@media (pointer:coarse){.tenant-domain-add-row .form-control{font-size:16px}}
.tenant-domain-suggestions{margin-top:10px;font-size:11px}
.tenant-domain-suggestions>.muted{display:block;margin-bottom:5px}
.tenant-domain-suggestion-list{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
.tenant-domain-suggestion{border:1px dashed var(--line);border-radius:4px;background:transparent;color:var(--accent);padding:3px 7px;font-size:11px}

/* fix wave of part D, m3: text present for touch and screen-reader users (a "one-tenant screen" menu item's reason,
   src/components/shell/Sidebar.tsx) but not painted - unlike the visible "soon" badge, four such hints in a row
   would be clutter. The standard clip-to-nothing technique, not display:none/visibility:hidden, which assistive
   tech skips too. */
.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.tenant-domain-suggestion:hover{background:var(--accent-soft)}

/* The sign-in's pages (part 5a spec A2, A3; src/components/sign-in/*): the prototype's `.auth-page` and `.auth-card`
   (styles.css), without its demo parts. What they lacked: the links under the card are links here, not buttons; a
   form's refusal sits over its fields (Tabler's alert); the first run groups its fields in two sets; the password's
   rule is a hint under its field. */
.auth-links a{font-size:12px}
.auth-card .alert{margin-bottom:20px;font-size:13px}
.auth-card .form-hint{display:block;margin-top:6px;font-size:11px;font-weight:400}
.auth-fieldset{border:0;margin:0 0 6px;padding:0;min-width:0}
.auth-fieldset>legend{float:none;width:auto;font-size:13px;font-weight:600;margin:0 0 14px;padding:0}
/* the language switch sits in the card's top right corner (owner, 2026-09-28), level with the card's padding and above
   its title (30px of padding and the title's 18px margin leave 48px, 41px on a phone), in the look of the header's
   switch with a light frame of its own - on the card it is no longer beside the header's other tools */
.auth-frame{position:relative}
.auth-tools{position:absolute;top:14px;right:14px;z-index:1}
.auth-tools .language-button{display:inline-flex;align-items:center;justify-content:center;min-width:36px;height:28px;padding:0 9px;border:1px solid var(--line);border-radius:6px;color:var(--muted);background:var(--surface)}
.auth-tools .language-button:hover{color:var(--ink);background:var(--canvas)}
@media (max-width:760px){.auth-tools{top:10px;right:10px}}
/* iOS zooms the page into a text box whose text is smaller than 16px */
@media (pointer:coarse){.auth-card .form-control,.auth-card .form-select{font-size:16px}}

/* the red button of a question that takes something away ("Block", "Reject" - the prototype's `btn btn-danger`,
   which styles.css leaves as a plain button): Tabler's own look is overridden there by the prototype's `.btn` */
.btn-danger{background:var(--red);color:#fff;border-color:var(--red)}
.btn-danger:hover{background:var(--red);color:#fff;border-color:var(--red);filter:brightness(.92)}


/* The Access section (part 5a spec A4; src/components/access/*): the prototype's accessPage() card with its
   generic-table and `.account-actions` (styles.css), plus what it did not have - the requests awaiting approval, the
   search over the table, the section's status line and the windows' lines. Tokens only, so both themes follow. */
.access-status{margin:0 0 16px;font-size:13px}
.access-status:empty{display:none}
.access-status.is-ok{color:var(--green)}
.access-status.is-error{color:var(--red)}
.access-dialog .access-status{margin:0 0 12px}
.access-dialog form[aria-busy="true"]{opacity:.55;pointer-events:none}
.access-dialog .form-hint{margin:10px 0 0}
.access-dialog-email{margin:-6px 0 16px;font-size:13px}
.access-requests,.access-accounts{margin-bottom:22px;transition:opacity .15s}
.access-accounts[aria-busy="true"]{opacity:.55;pointer-events:none}
@media (prefers-reduced-motion:reduce){.access-requests,.access-accounts{transition:none}}
.access-requests h2 .number-badge,.access-accounts h2 .number-badge{margin-left:8px}
/* People's "Access" tab (the owner, 2026-09-30): "Change history" and "Create account" in the accounts card's heading -
   under the heading on a phone */
.access-accounts .card-heading{flex-wrap:wrap}
.access-heading-actions{display:flex;flex-wrap:wrap;gap:8px;margin-left:auto}
.access-heading-actions .btn{white-space:nowrap}
/* the heading takes the focus after an approval or a rejection of an account the table shows no row of: marked only
   for a keyboard, as the team editor's headings */
#access-accounts-title:focus{outline:none}
#access-accounts-title:focus-visible{outline:2px solid color-mix(in srgb,var(--accent) 55%,transparent);outline-offset:2px}
.access-request-list{list-style:none;margin:0;padding:0}
.access-request-list>li{display:grid;gap:8px;padding:14px 20px;border-top:1px solid var(--line)}
.access-request-who strong{font-weight:600;overflow-wrap:anywhere}
.access-request-who small{display:block;font-size:12px;color:var(--muted);overflow-wrap:anywhere}
.access-request-facts{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:4px 14px;margin:0;font-size:13px}
.access-request-facts dt{font-weight:500;color:var(--muted)}
.access-request-facts dd{margin:0;white-space:pre-wrap;overflow-wrap:anywhere}
.access-request-list small.muted{font-size:12px}
.access-toolbar .search-field{flex:1 1 260px;max-width:450px}
.access-toolbar .search-field input{font-size:14px;padding:2px 0;min-height:24px;box-shadow:none}
.access-table td>.muted{font-size:12px}
.access-table .account-actions{white-space:nowrap}
.access-link .form-control{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}
.access-history pre{max-height:260px;overflow:auto}
/* the roles of an account (part 5b spec R5): the administrator's mark, then one list per tenant - the tenant's name
   beside its list; a warning line (an executor without an employee) in the orange of a warning, as on the page's line */
.access-status.is-warn{color:var(--orange)}
.access-grant{border:0;margin:0;padding:0;min-width:0}
.access-grant>legend,.form-grid .access-grant>legend{float:none;width:auto;padding:0;margin:0 0 6px;font-size:inherit}
.access-grant .form-check{margin:4px 0 10px}
.access-grant .form-check-label .muted{font-size:12px}
.access-tenant-roles{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:8px 14px;align-items:center}
.access-tenant-role{display:contents}
.access-tenant-role>span{font-size:13px;overflow-wrap:anywhere}
.access-grant .access-warning{color:var(--orange)}
/* "Create account" (the owner, 2026-09-24): who it is for - an employee of People or typed by hand - as the period's
   segmented switch, its two halves the dialog's width; a warning under a field (an employee without an e-mail) orange */
.access-create-mode{margin:0 0 16px}
.access-create-mode button{flex:1 1 0;min-width:0}
.access-dialog .form-hint.access-warning{color:var(--orange)}
/* "Edit" of an account without an employee: «Присылать сюда» of its sign-in address (the owner, 2026-09-29: the
   letters are opt-in), below the form - the address and the switch on one line, as a People card's mail rows */
.access-mail{margin-top:18px;padding-top:14px;border-top:1px solid var(--line)}
.access-mail>h3{margin:0 0 8px}
.access-mail-row{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:6px 14px}
.access-mail-row .people-email{font-size:13px;min-width:0}
.access-dialog .access-mail .form-hint{margin:6px 0 0}
.access-dialog .access-mail .access-status{margin:8px 0 0}
.access-dialog .access-mail-note{margin:16px 0 0}
@media(max-width:760px){
  .access-request-list>li{padding-left:15px;padding-right:15px}
  .access-request-facts{grid-template-columns:minmax(0,1fr)}
  .access-toolbar .search-field{flex-basis:100%;max-width:none}
  .access-tenant-roles{grid-template-columns:minmax(0,1fr);gap:4px}
  .access-tenant-role>select{margin-bottom:6px}
}

/* Settings → Calculation rules and Synchronization (part 5c spec S2, S5; src/components/settings/RulesForm.tsx,
   SyncSettingsForm.tsx): the prototype's `.number-setting` row gets the one-line hint under its label that its
   `.setting-toggle` row has, and a line for a refused value or a warning. On a phone the field goes under the label. */
.number-setting>label{flex:1;min-width:0;margin:0;cursor:default}
.number-setting>label strong{font-weight:500;font-size:14px;display:block}
.number-setting>label small{color:var(--muted);font-size:12px;display:block;margin-top:5px}
.number-setting>label small.setting-error{color:var(--red)}
.number-setting>label small.setting-warning{color:var(--orange);display:flex;gap:5px;align-items:flex-start}
.number-setting>label small.setting-warning .icon{width:14px;height:14px;flex-shrink:0;margin-top:1px}
.number-setting .input-group{align-self:center}
.settings-form>.alert{margin-bottom:10px}
@media(max-width:560px){.number-setting{flex-direction:column;align-items:stretch;gap:10px}.number-setting .input-group{width:100%;align-self:stretch}.number-setting>label strong{font-size:13px}.number-setting>label small{font-size:11px}}
/* A button of Settings busy with a change says so without being disabled - a disabled one would drop the keyboard
   focus (review of part 5c): the click is ignored, the look is a disabled one's. */
.sync-buttons [aria-disabled="true"],.calendar-holidays [aria-disabled="true"],.sla-matrix [aria-disabled="true"],
.notify-test [aria-disabled="true"],.notify-recipients [aria-disabled="true"]{opacity:.55;cursor:progress}
.notify-mail-retry[aria-busy="false"] [aria-disabled="true"]{cursor:default}
/* Synchronization: the queue buttons' status line (like the Tenants page's), and each form's status and run log. */
.sync-buttons-hint{font-size:12px;margin:8px 0 0}
.sync-buttons-status{margin:8px 0 0;font-size:12px}
.sync-buttons-status:empty{display:none}
.sync-buttons-status.is-ok{color:var(--green)}
.sync-buttons-status.is-error{color:var(--red)}
/* Synchronization, restructured (the owner's item 10 of 2026-09-30; src/app/[tenant]/settings/sync/page.tsx): each
   form's state first - a tile with its result chip and a few facts, problems only when there are some - then the
   tenant's buttons, then its settings folded under «Параметры» with the saved values in one line. Under the cards one
   run log: the filters, a compact table, the pager; on a phone each run folds into two lines. */
.sync-forms{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:12px;margin-bottom:16px}
.sync-form-state{border:1px solid var(--line);border-radius:6px;padding:12px 14px;min-width:0}
.sync-form-title{display:flex;gap:10px;align-items:flex-start;justify-content:space-between;margin-bottom:6px}
.sync-form-title>h3{font-size:14px;font-weight:600;margin:0;min-width:0;overflow-wrap:anywhere}
.sync-state{display:inline-flex;align-items:center;font-size:12px;line-height:1.5;font-weight:500;padding:1px 7px;border-radius:4px;white-space:nowrap;background:var(--canvas);color:var(--muted)}
.sync-state.is-ok{color:var(--green);background:var(--green-soft)}
.sync-state.is-error{color:var(--red);background:var(--red-soft)}
.sync-state.is-running{color:var(--accent);background:var(--accent-soft)}
.sync-facts{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:6px 14px;margin:0;font-size:12px}
.sync-facts>div{min-width:0}
.sync-facts dt{font-weight:400;color:var(--muted)}
.sync-facts dd{margin:0;color:var(--ink);font-weight:500;overflow-wrap:anywhere}
.sync-facts>.is-bad dd{color:var(--red)}
.sync-facts .sync-fact-note{display:block;font-weight:400;color:var(--muted)}
.sync-last-error{margin:8px 0 0;font-size:12px;color:var(--red);overflow-wrap:anywhere}
.sync-last-error strong{font-weight:500}
.sync-buttons .help-tooltip>span{left:auto;right:-8px;transform:none;max-width:calc(100vw - 48px)}
.sync-params{margin-top:16px;border-top:1px solid var(--line);padding-top:12px}
.sync-params>summary{cursor:pointer;display:flex;flex-wrap:wrap;gap:4px 10px;align-items:baseline;list-style:none}
.sync-params>summary::-webkit-details-marker{display:none}
.sync-params>summary::before{content:"";width:7px;height:7px;border-right:1.5px solid var(--muted);border-bottom:1.5px solid var(--muted);transform:rotate(-45deg);align-self:center;margin-right:2px;transition:transform .15s}
.sync-params[open]>summary::before{transform:rotate(45deg)}
.sync-params>summary strong{font-weight:500;color:var(--accent)}
.sync-params>summary span{font-size:12px}
.sync-params>summary:focus-visible{outline:2px solid color-mix(in srgb,var(--accent) 55%,transparent);outline-offset:2px;border-radius:4px}
.sync-params>.settings-form{margin-top:8px}
.sync-log-filters{display:flex;flex-wrap:wrap;gap:10px 18px;align-items:center;padding:14px 18px;border-bottom:1px solid var(--line)}
.sync-log-scope{width:min(100%,340px)}
.sync-log-errors{margin:0;font-size:13px}
.sync-log-none{margin:0;padding:16px 18px}
.sync-runs{margin:0}
.sync-runs td{padding:9px 12px;white-space:nowrap;font-size:12px}
.sync-runs tr.has-error>td{border-bottom:0}
.sync-runs td.sync-run-error{padding-top:0;white-space:normal;color:var(--red);font-size:11px;overflow-wrap:anywhere}
@media(max-width:760px){
  .sync-runs thead{display:none}
  .sync-runs,.sync-runs tbody{display:block}
  .sync-runs tr{display:flex;flex-wrap:wrap;gap:2px 10px;padding:10px 16px;border-bottom:1px solid var(--line)}
  .sync-runs td{border:0;padding:0;white-space:normal}
  .sync-runs td.sync-run-form{order:1;flex:1 1 0;font-weight:500;font-size:13px;min-width:0;overflow-wrap:anywhere}
  .sync-runs td.sync-run-result{order:2;min-width:0;flex:0 1 auto}
  .sync-runs tr.has-error{border-bottom:0;padding-bottom:2px}
  .sync-runs tr.sync-run-error-row{padding-top:0}
  .sync-runs tr::before{content:"";order:3;flex-basis:100%;height:0}
  .sync-runs td.sync-run-started,.sync-runs td.sync-run-kind,.sync-runs td.sync-run-tickets,.sync-runs td.sync-run-duration{order:4;color:var(--muted)}
  .sync-log-footer{flex-wrap:wrap;gap:8px}
}
@media(max-width:420px){.sync-facts{grid-template-columns:1fr 1fr}}
/* "Change history" (part 5c spec S1; src/components/settings/SettingsHistory.tsx): the prototype's dialog of
   `.history-entry` blocks, wider for the JSON, with the section filter on top and the changes as short lines. */
.sd-dialog.settings-history{width:min(720px,calc(100vw - 32px));max-width:720px}
.settings-history-filter{display:flex;align-items:center;gap:10px;margin-bottom:18px;font-size:12px;color:var(--muted)}
.settings-history-filter .form-select{width:auto;min-width:200px}
.history-entry>strong{font-weight:500}
.history-entry>p{margin:4px 0 0;overflow-wrap:anywhere}
.history-changes{margin:8px 0 0;padding-left:18px;font-size:12px}
.history-changes li{overflow-wrap:anywhere}
.history-changes code{font-size:11px}
.history-entry details{margin-top:8px;font-size:12px}
.history-entry summary{cursor:pointer;color:var(--accent)}
.history-entry pre{max-height:320px;overflow:auto;margin:8px 0 0}   /* Tabler's own dark block, as in the prototype */

/* Settings → Calendars (part 5c spec S3; src/components/settings/CalendarSettingsForm.tsx, CalendarHolidays.tsx): the
   prototype's `.calendar-controls`, `.time-pair`, `.weekdays` and `.calendar-mini`, with a line for a refused value, the
   weekday names above the grid and the leading blanks of its first week, holidays marked red (a day off stays muted,
   today the prototype's accent), and the holidays of a year with a remove button and a field pair to add one. */
.setting-lead{font-size:12px;margin:0 0 18px}
.calendar-settings .calendar-controls>label{display:block;margin:0}
.calendar-settings .calendar-controls>label>.form-select{margin-top:7px}
.calendar-hours>span{display:block;font-size:12px;color:var(--muted)}
.calendar-hours .time-pair{margin-top:7px}
.calendar-settings small.setting-error,.rule-editor .setting-error{display:block;color:var(--red);font-size:12px;margin-top:5px}
.calendar-weekdays{border:0;margin:22px 0 0;padding:0;min-width:0}
.calendar-weekdays>legend{float:none;width:auto;font-size:12px;color:var(--muted);margin:0 0 7px;padding:0}
.calendar-weekdays .weekdays{margin:0;flex-wrap:wrap}
.calendar-weekdays .weekdays label{position:relative;margin:0}
.calendar-holidays{margin-top:28px}
.calendar-weekday-names{margin-bottom:5px}
.calendar-weekday-names>span{height:auto;font-size:10px;color:var(--muted)}
.calendar-days .holiday{background:var(--red-soft);color:var(--red);font-weight:600}
.calendar-days .today.holiday{background:var(--accent);color:#fff}
.calendar-legend{display:flex;flex-wrap:wrap;gap:6px 14px;margin-top:12px;font-size:11px;color:var(--muted)}
.calendar-legend i{display:inline-block;width:10px;height:10px;border-radius:3px;margin-right:5px;vertical-align:-1px}
.calendar-legend .is-holiday{background:var(--red-soft);border:1px solid var(--red)}
.calendar-legend .is-off{background:transparent;border:1px solid var(--muted)}
.calendar-legend .is-today{background:var(--accent)}
.calendar-year{flex-wrap:wrap;row-gap:8px}
.calendar-year h3{font-size:14px;margin:0;white-space:nowrap}
.calendar-year>div{margin-left:auto;display:flex;gap:5px;flex-wrap:wrap;justify-content:flex-end}
.calendar-year .btn-icon,.calendar-mini .btn-icon{width:30px;min-height:30px}
.calendar-status,.sla-status{margin:0 0 8px;font-size:12px}
.calendar-status:empty,.sla-status:empty{display:none}
.calendar-status.is-ok,.sla-status.is-ok{color:var(--green)}
.calendar-status.is-error,.sla-status.is-error{color:var(--red)}
.holiday-list{list-style:none;margin:0;padding:0}
.holiday-list>li>span:first-child{overflow-wrap:anywhere}
.holiday-when{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.holiday-when .icon-button{width:28px;height:28px}
.holiday-when .icon-button .icon{width:16px;height:16px}
.holiday-add{display:grid;grid-template-columns:170px minmax(0,1fr) auto;gap:10px;align-items:end;margin-top:16px}
.holiday-add label{font-size:12px;color:var(--muted);margin:0}
.holiday-add label .form-control{margin-top:5px}
.holiday-add .holiday-add-error{grid-column:1 / -1;margin:0;color:var(--red);font-size:12px}
.sd-dialog.holiday-copy{width:min(720px,calc(100vw - 32px));max-width:720px}
.holiday-copy-list{list-style:none;padding:0;margin:14px 0 0;display:grid;gap:10px}
.holiday-copy-list>li{display:grid;grid-template-columns:auto 160px minmax(0,1fr);gap:6px 10px;align-items:center;padding-bottom:10px;border-bottom:1px solid var(--line)}
.holiday-copy-list>li>small{grid-column:2 / -1;font-size:11px}
.holiday-copy-list .form-check{margin:0;padding:0;min-height:0;display:flex;gap:6px;align-items:center}
.holiday-copy-list .form-check .form-check-input{float:none;margin:0}
@media(max-width:560px){
  .holiday-add{grid-template-columns:minmax(0,1fr)}
  .holiday-copy-list>li{grid-template-columns:auto minmax(0,1fr)}
  .holiday-copy-list>li>input[type=text],.holiday-copy-list>li>small{grid-column:1 / -1}
}

/* Settings → SLA matrices (part 5c spec S4; src/components/settings/SlaMatrix.tsx, SlaRuleEditor.tsx): the prototype's
   `.rules-table` with the order and its arrows in the first cell (the up arrow is the down one turned), the name above
   the condition tags, the norm's `.inline-input` wide enough for 10000; "No SLA" as a callout with a warning's edge; the
   rule editor's conditions a row each - attribute, check, value(s), remove - and "one of" as chips. */
.rules-table td{vertical-align:middle}
.rules-table td.rule-order{width:1%;white-space:nowrap}
.rule-order>span{display:inline-block;min-width:18px;text-align:right;margin-right:4px}
.rule-order .icon-button,.rule-actions .icon-button{width:28px;height:28px}
.rule-order .icon-button .icon,.rule-actions .icon-button .icon{width:16px;height:16px}
.rule-order .icon-button:disabled{opacity:.35}
.rule-up .icon{transform:rotate(180deg)}
.rule-what{min-width:220px}
.rule-what>strong{display:block;font-weight:500;margin-bottom:6px}
.rule-conditions-list{display:flex;flex-wrap:wrap;gap:6px}
.rule-conditions-list .condition-tag{line-height:1.4;overflow-wrap:anywhere}
.rules-table .inline-input{width:66px}
.rule-hours,.rule-frt,.rule-matches{white-space:nowrap}
.rule-actions{white-space:nowrap;text-align:right}
.sla-no-policy{border-left:3px solid var(--orange)}
.sla-no-policy>.icon{color:var(--orange)}
.sd-dialog.sla-rule-dialog{width:min(780px,calc(100vw - 32px));max-width:780px}
.rule-editor .form-grid{grid-template-columns:minmax(0,1fr) 200px;margin-bottom:20px}
.rule-editor .form-label>.form-control{margin-top:5px}
.rule-conditions{border:0;padding:0;margin:0;min-width:0}
.rule-conditions>legend{float:none;width:auto;font-size:13px;margin:0 0 10px;padding:0}
.rule-condition{display:grid;grid-template-columns:236px 136px minmax(0,1fr) 32px;gap:8px;align-items:start;margin-bottom:10px}
.rule-condition-yes{align-self:center;color:var(--muted);font-size:13px}
.rule-condition-error{grid-column:1 / -1;margin-top:0!important}
.rule-values-hint{font-size:11px;margin:8px 0 0}
.rule-value-chips{list-style:none;margin:0 0 6px;padding:0;display:flex;flex-wrap:wrap;gap:6px}
.rule-value-chips>li{display:inline-flex;align-items:center;gap:4px;background:var(--canvas);border:1px solid var(--line);border-radius:5px;padding:2px 4px 2px 8px;font-size:12px;overflow-wrap:anywhere}
.rule-value-remove{border:0;background:transparent;color:var(--muted);padding:0;display:inline-flex}
.rule-value-remove .icon{width:13px;height:13px}
.rule-value-add{display:flex;gap:6px}
.rule-value-add .btn{white-space:nowrap}
.sd-dialog.sla-matches-dialog{width:min(640px,calc(100vw - 32px));max-width:640px}
/* A norm the server refused, said under its field (review of part 5c). */
.rules-table .inline-input.is-invalid{border-color:var(--red)}
.rule-hours .rule-hours-error{display:block;white-space:normal;color:var(--red);font-size:12px;margin-top:4px;min-width:180px;max-width:240px}
.sla-matches-tenant h3{font-size:13px;margin:14px 0 8px}
.sla-ticket-list{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:6px 14px;font-size:13px}
@media(max-width:640px){
  .rule-editor .form-grid{grid-template-columns:minmax(0,1fr)}
  .rule-condition{grid-template-columns:minmax(0,1fr) 32px}
  .rule-condition>:not(.icon-button){grid-column:1}
  .rule-condition>.icon-button{grid-column:2;grid-row:1}
}

/* Settings → Forms (part 5c spec S6; src/app/[tenant]/settings/forms/page.tsx, src/components/settings/FormSettingsForm.tsx):
   the warnings of what the classes leave out, the form's facts as `.split-line` rows, the calendar and the matrix side by
   side (the calendars' `.calendar-controls`), the class tables - a select a row, the tickets on the right - and the field
   map folded under its summary line, open when a field is not found in Pyrus. */
/* several cards of one section (a form each; a tenant each on Synchronization) stand apart */
.settings-layout .setting-card+.setting-card{margin-top:22px}
.form-warnings ul{margin:6px 0;padding-left:18px}
.form-warnings small{display:block}
.form-facts{margin:0 0 8px}
.form-settings .calendar-controls{margin:18px 0 6px}
.form-settings .calendar-controls>label{display:block;margin:0}
.form-settings .calendar-controls .form-select{margin-top:7px}
.form-settings small.setting-error{display:block;color:var(--red);font-size:12px;margin-top:5px}
.form-classes{margin-top:26px}
.form-classes>h3{font-size:14px;font-weight:600;margin:0 0 4px}
.form-classes>p{font-size:12px;margin:0 0 10px}
.form-class-errors{margin:0 0 8px}
.form-class-table td{padding:10px 12px}
.form-class-table td:first-child small{display:block;margin-top:3px}
.form-class-table .form-select{min-width:230px}
.form-class-tickets{text-align:right;white-space:nowrap;width:1%}
.form-fields{margin-top:24px;font-size:13px}
.form-fields>summary{cursor:pointer;color:var(--accent);font-weight:500}
.form-fields>summary.text-danger{color:var(--red)}
.form-fields>p{font-size:12px;margin:8px 0 0}
.form-field-table td{padding:10px 12px}
.form-field-ok{display:inline-flex;align-items:center;gap:5px;color:var(--green)}
.form-field-ok .icon{width:14px;height:14px}
.form-field-missing strong{display:block;color:var(--red);font-weight:600}
.form-field-missing small{color:var(--muted);font-size:11px}
@media(max-width:560px){.form-class-table .form-select{min-width:0}.form-class-table td{padding:8px}}

/* The profile window (the owner 2026-09-28: tabs «Общие» / «Уведомления», one style; src/components/shell/
   ProfileDialog.tsx, TelegramBlock.tsx). The prototype's `.page-tabs` across the top of the body, edge to edge; the
   prototype's `.profile-intro`; then sections, each a small caps title over rows - a label (and a hint under it) at
   the left, its value, badge, select, switch or one button at the right, a hairline between rows. Three text sizes
   only: 13 px a row, 12 px a hint, 11 px a section's title. Tokens only, so both themes follow. */
.sd-dialog.profile-dialog{max-width:500px}
.profile-dialog .dialog-body{padding:0 24px 24px}
.profile-dialog .dialog-body>:first-child:not(.profile-tabs){margin-top:24px}
.profile-tabs{margin:0 -24px 22px;padding:14px 24px 0}
.profile-panel[hidden]{display:none}
.profile-dialog .profile-intro{margin-bottom:22px}
.profile-dialog .profile-intro .avatar{width:44px;height:44px;border-radius:10px;font-size:14px;flex-shrink:0}
.profile-dialog .profile-intro>div{min-width:0}
.profile-dialog .profile-intro h3{font-size:16px;font-weight:600;line-height:1.3}
.profile-dialog .profile-intro p{font-size:13px;margin:2px 0 0;overflow-wrap:anywhere}
.profile-section{margin:0 0 22px}
.profile-section:last-child{margin-bottom:0}
.profile-section-title{font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--muted);margin:0 0 4px;line-height:1.4}
.profile-hint{font-size:12px;line-height:1.45;color:var(--muted);margin:0 0 6px}
.profile-empty{font-size:13px;margin:8px 0 0}
.profile-roles,.profile-toggles{list-style:none;margin:0;padding:0}
.profile-row,.profile-toggle{display:flex;align-items:center;justify-content:space-between;gap:14px;min-height:44px;margin:0;padding:8px 0;border-bottom:1px solid var(--line);font-size:13px;font-weight:400;color:var(--ink)}
.profile-section>.profile-row:last-child,.profile-roles>li:last-child,.profile-toggles>li:last-child>.profile-toggle{border-bottom:0}
.profile-row-text{display:flex;flex-direction:column;gap:2px;min-width:0}
.profile-row-text>small{font-size:12px;line-height:1.4;color:var(--muted)}
.profile-row>.btn,.profile-row>.neutral-badge{flex-shrink:0}
.profile-row>.form-select{width:auto;min-width:130px;flex-shrink:0}
.profile-toggle{cursor:pointer}
.profile-toggle .form-check{margin:0;padding:0;min-height:0;flex-shrink:0}
.profile-toggle .form-check-input{float:none;margin:0;width:34px;height:20px;cursor:pointer}
.profile-toggle .form-check-input:disabled{opacity:.6;cursor:default}
.profile-group{margin-top:10px}
.profile-group-title{font-size:12px;font-weight:600;color:var(--ink);margin:0;padding-top:4px}
.profile-status{display:inline-flex;align-items:center;gap:8px;font-weight:500}
.profile-status::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--muted);flex-shrink:0}
.profile-status.is-ok::before{background:var(--green)}
.profile-status.is-error{color:var(--red)}
.profile-status.is-error::before{background:var(--red)}
.profile-actions{display:flex;justify-content:flex-end;padding-top:6px;border-top:1px solid var(--line);margin-top:4px}
.profile-actions>.btn{margin-top:14px}
.profile-dialog .alert{font-size:13px}
.profile-telegram[aria-busy="true"]{opacity:.7}
.profile-telegram [aria-disabled="true"]{cursor:progress}
.telegram-status{margin:4px 0 8px;font-size:12px;line-height:1.45}
.telegram-status.is-ok{color:var(--green)}
.telegram-status.is-error{color:var(--red)}
@media (max-width:560px){
  .profile-dialog .dialog-body{padding:0 16px 20px}
  .profile-dialog .dialog-body>:first-child:not(.profile-tabs){margin-top:16px}
  .profile-tabs{margin:0 -16px 18px;padding:12px 16px 0}
  .profile-row{flex-wrap:wrap;row-gap:8px}
  .profile-row>.form-select{min-width:0;flex:1 1 140px}
}
.people-telegram{margin-top:18px}
.people-telegram>p{font-size:13px;margin:0 0 10px}
/* Part 6b: the card's letters switch (a switch and its words, in the actions' row) and the profile's channel switch as a
   section's last row. */
.people-mail-switch{display:inline-flex;align-items:center;gap:8px;margin:0;font-size:13px;cursor:pointer}
.people-mail-switch .form-check{margin:0;padding:0;min-height:0}
.people-mail-switch .form-check-input{float:none;margin:0;width:34px;height:20px;cursor:pointer}
.profile-section>.profile-toggle:last-child{border-bottom:0}
.connect-link{margin-top:12px}
.connect-link-row{display:flex;gap:8px;align-items:center}
.connect-link-row>.form-control{flex:1;min-width:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}
.connect-link .form-hint{font-size:12px;color:var(--muted);margin:6px 0 0}
.connect-link .people-status{margin:6px 0 0}
/* Settings → Notifications (src/app/[tenant]/settings/notifications): the bot's badge in its colour, the rules table
   (an event per row - not the SLA matrix's narrow first column), the quiet hours beside their zone, the test button */
.integration-status .neutral-badge.is-ok{color:var(--green);border-color:var(--green)}
.integration-status .neutral-badge.is-error{color:var(--red);border-color:var(--red)}
.integration-status>div>p+p{margin-top:2px}
/* The Mail card's facts (2026-09-29): what the worker signs in with, apart from the state, smaller; a long login wraps */
.integration-status .mail-login{margin-top:6px;padding-top:6px;border-top:1px solid var(--line);font-size:12px;color:var(--muted);overflow-wrap:anywhere}
.integration-status .mail-login p+p{margin-top:2px}
/* The tables' scroll box holds what is absolutely positioned inside (a header's `.visually-hidden` text): without it
   that text sits where the header would be - past the card when the table scrolls - and widens the page itself. */
.notify-scroll{position:relative}
/* Settings → Notifications in tabs (the owner, 2026-09-30, item 3). «Каналы»: a card per channel - its state (the
   prototype's `.integration-status`), a line of what it is for, its master switch (the prototype's `.setting-toggle`
   between two rules) with its answer under it, its test send; the quiet hours' card. */
.notify-channel-card .setting-lead{margin:0 0 6px}
.notify-channel-switch{margin-top:10px}
.notify-channel-switch .setting-toggle{padding:14px 0;margin:0;border-top:1px solid var(--line)}
.notify-channel-switch .setting-toggle .form-check-input{cursor:pointer}
.notify-quiet-form .setting-toggle{padding-top:0}
.notify-quiet-form .calendar-controls{margin:0 0 6px}
.notify-quiet-form .calendar-controls>label{display:block;margin:0}
.notify-quiet-form .calendar-controls .form-select{margin-top:7px}
.notify-quiet-form small.setting-error{display:block;color:var(--red);font-size:12px;margin-top:5px}
/* ── The mail's letters and copies (the owner, 2026-10-01) ──────────────────────────────────────────────────────────
   «Каналы»: «Сохранять копии писем в „Отправленных“» under the mail's master switch - the same row (.setting-toggle),
   one rule between the two; its hint is the whole explanation, so the switch stays at the top beside it.
   «Получатели и журнал» → «Письма»: the filters in a row (on a phone one under another, each the card's width), then
   the table - four columns that fit the card of a desktop window (721 px at 1280) without a sideways scroll: the moment
   (two lines when the card is narrow), the letter (its kind, its subject, what it is about), the addresses (each on
   its own line; a long one breaks), the outcome with the moment it was sent. Why a letter waits or did not go is a
   line of its own under its row, the table's width (as .sync-run-error). Narrower than its columns' least widths
   (620 px) the table scrolls inside its box (.table-responsive, .notify-scroll) - the page never does. */
.mail-copies-switch{margin-top:0}
.mail-copies-switch .setting-toggle{align-items:flex-start;border-top:0}
.mail-letters-filters{display:flex;flex-wrap:wrap;gap:10px;margin:0 0 14px}
.mail-letters-filters label{margin:0;min-width:0;flex:0 1 auto}
.mail-letters-filters .form-select{width:230px;max-width:100%}
.mail-letters-filters .mail-letters-search{flex:1 1 180px}
.mail-letters-filters .form-control{width:100%}
.mail-letters[aria-busy="true"] .mail-letters-table{opacity:.6}
.mail-letters-table{margin:0;min-width:620px}
.mail-letters-table thead th{padding:11px 8px;white-space:nowrap}
.mail-letters-table td{padding:10px 8px;vertical-align:top;font-size:13px}
.mail-letters-table td small{display:block;font-size:11px;color:var(--muted);margin-top:3px}
.mail-letters-table .mail-letter-time{width:1%;min-width:116px;color:var(--muted)}
.mail-letters-table .mail-letter-kind{min-width:170px}
.mail-letters-table .mail-letter-kind strong{display:block;font-weight:500}
.mail-letters-table .mail-letter-subject{display:block;font-size:12px;color:var(--muted);overflow-wrap:anywhere;margin-top:2px}
.mail-letters-table .mail-letter-to{min-width:150px}
.mail-letters-table .mail-letter-to span{display:block;overflow-wrap:anywhere}
.mail-letters-table .mail-letter-to small{overflow-wrap:anywhere}
.mail-letters-table .mail-letter-outcome{width:1%;min-width:120px}
.mail-letters-table tr.has-reason>td{border-bottom:0;padding-bottom:4px}
.mail-letters-table td.mail-letter-reason{padding-top:0;font-size:12px;color:var(--muted);overflow-wrap:anywhere}
.mail-letters-table td.mail-letter-reason.is-failed,.mail-letters-table td.mail-letter-reason.is-expired{color:var(--red)}
.mail-letters-more{margin-top:14px}
.mail-letters-more [aria-disabled="true"]{opacity:.55;cursor:progress}
.mail-letters-bound{margin:14px 0 0}
.mail-letters-none{margin:0}
@media (max-width:560px){
  .mail-letters-filters{flex-direction:column}
  .mail-letters-filters .form-select{width:100%}
  .mail-letters-filters .mail-letters-search{flex:0 0 auto}
}
@media (pointer:coarse){.mail-letters-filters .form-control,.mail-letters-filters .form-select{font-size:16px}}
/* ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────── */
/* «События»: the events' list at the left, the chosen one's form at the right, in one bordered box (642 px inside the
   card at 1100, the sidebar open: a 230 px list, the form the rest). Each line of the list - a dot of its state (on -
   green, off - an empty ring, nothing would go - orange, a value to fix - red), the name and its summary; the chosen one
   white with the accent's bar. The form: when it happens, its switch, whom and by which channels as pill checkboxes,
   the delay and the repeat side by side while they fit. An event switched off greys its fields (they keep their
   values). The card narrower than 560 px (a phone) stacks the list over the form; nothing scrolls sideways. */
.notify-events-form{container-type:inline-size}
.notify-md{display:grid;grid-template-columns:230px minmax(0,1fr);border:1px solid var(--line);border-radius:8px;background:var(--surface)}
.notify-md-list{display:flex;flex-direction:column;gap:2px;padding:6px;background:var(--canvas);border-right:1px solid var(--line);border-radius:8px 0 0 8px}
.notify-md-item{display:flex;gap:10px;align-items:flex-start;width:100%;padding:9px 10px;border:0;border-radius:6px;background:transparent;color:var(--ink);text-align:left}
.notify-md-item:hover{background:var(--surface)}
.notify-md-item:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.notify-md-item[aria-selected="true"]{background:var(--surface);box-shadow:inset 3px 0 0 var(--accent),0 1px 2px #0d234014}
.notify-md-text{min-width:0}
.notify-md-item strong{display:block;font-weight:500;font-size:13px;line-height:18px}
.notify-md-item[aria-selected="true"] strong{color:var(--accent)}
.notify-md-item small{display:block;margin-top:2px;font-size:11.5px;line-height:1.35;color:var(--muted)}
.notify-md-dot{flex:0 0 8px;width:8px;height:8px;margin-top:5px;border-radius:50%;background:var(--green)}
.notify-md-item[data-state="off"] .notify-md-dot{background:transparent;box-shadow:inset 0 0 0 1.5px var(--muted)}
.notify-md-item[data-state="off"] strong{color:var(--muted)}
.notify-md-item[data-state="empty"] .notify-md-dot{background:var(--orange)}
.notify-md-item[data-state="error"] .notify-md-dot{background:var(--red)}
.notify-md-detail{min-width:0;padding:16px 18px}
.notify-md-panel[hidden]{display:none}
.notify-md-head h3{margin:0 0 3px;font-size:15px}
.notify-md-head p{margin:0;font-size:12px;line-height:1.4}
.notify-md-enabled{padding:12px 0;margin:0}
.notify-md-group{min-width:0;margin:14px 0 0;padding:0;border:0}
.notify-md-group legend{display:flex;align-items:center;gap:6px;float:none;width:auto;margin:0 0 7px;padding:0;font-size:12px;font-weight:600;color:var(--muted);line-height:1.3}
.notify-audiences{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px}
.notify-audience{display:inline-flex;align-items:center;gap:7px;margin:0;padding:4px 11px 4px 8px;border:1px solid var(--line);border-radius:999px;font-size:12px;line-height:18px;cursor:pointer;background:var(--surface);color:var(--ink)}
.notify-audience .form-check-input{margin:0;float:none;width:14px;height:14px;cursor:pointer}
.notify-audience:has(.form-check-input:checked){border-color:var(--accent);background:var(--accent-soft)}
.notify-channel-off{font-size:11px;color:var(--orange)}
.notify-md-note{display:block;margin-top:7px;font-size:11.5px;line-height:1.4}
.notify-md-timing{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px 18px;margin-top:16px}
.notify-md-amount{display:flex;flex-direction:column;gap:5px;min-width:0}
.notify-md-amount-label{display:flex;align-items:center;gap:4px;font-size:12px;color:var(--muted);line-height:1.3}
.notify-md-amount-label label{margin:0}
.notify-md-amount .input-group{width:100%;max-width:210px;flex-wrap:nowrap}
.notify-md-amount .input-group .form-select{flex:0 0 84px;width:84px;padding-inline-end:26px;background-position:right 8px center}
.notify-md-amount .form-control{text-align:right}
.notify-md-panel:has(.notify-enabled:not(:checked)) .notify-md-fields{opacity:.45}
.notify-md-warning{margin:14px 0 0;padding:8px 10px;border-radius:6px;background:var(--orange-soft);color:var(--orange);font-size:12px;line-height:1.4}
.notify-events-form small.setting-error{display:block;color:var(--red);font-size:12px}
.notify-md-lead{margin:12px 0 0}
@container (max-width:560px){
  .notify-md{grid-template-columns:minmax(0,1fr)}
  .notify-md-list{border-right:0;border-bottom:1px solid var(--line);border-radius:8px 8px 0 0}
  .notify-md-detail{padding:14px 12px;scroll-margin-top:12px}
}
.notify-test{margin-top:20px}
/* Templates v2 (the owner, 2026-09-30, item 3: «сделай единый редактор в поле зрения, без прокрутки»): the event and
   the channel in one row (the card's heading); under it the editor and its live preview side by side once the card is
   680 px wide (a container query: the settings' own menu takes part of the screen) - at 1280 x 800 both whole in the
   window as the tab opens. Narrower, the two stack and a sticky switch shows one
   of them (`data-view`). Placeholders are marked in the fields themselves (HighlightField: a transparent field over a
   backdrop with the same text and box, the marks behind the glyphs). Nothing scrolls sideways: the preview wraps. */
.tpl-card-title{display:flex;align-items:center;gap:6px}
.tpl-card-title .help-tooltip>span{width:min(320px,calc(100vw - 48px));transform:translateX(-30%)}
.tpl-top{display:flex;flex-wrap:wrap;align-items:center;gap:8px 18px;margin:0 0 14px}
/* the templates' card: its heading is the row of the event, the channel, the state, the way back and the help, with the
   saving's status at its end (wrapping under them when the card is narrow) - one row less above the editor */
.settings-card-heading.tpl-heading{align-items:center;gap:8px 16px;padding:14px 20px}
.tpl-heading .tpl-top{margin:0;flex:1 1 auto;min-width:0;gap:8px 14px}
.tpl-heading>.autosave-status{margin-left:auto}
.tpl-top .help-tooltip>span{left:auto;right:-8px;transform:none;width:min(320px,calc(100vw - 96px))}
.tpl-pick{display:flex;align-items:center;gap:8px;margin:0;font-size:13px;min-width:0}
.tpl-pick>span{color:var(--muted)}
.tpl-pick .form-select{width:240px;max-width:100%;text-overflow:ellipsis}
.tpl-top .neutral-badge.is-ok{color:var(--green);border-color:var(--green)}
.tpl-top .neutral-badge.is-unsaved{color:var(--orange);border-color:var(--orange);background:var(--orange-soft)}
.tpl-reset{padding:0 2px;min-height:0;font-size:12px;display:inline-flex;align-items:center;gap:4px;border:0;background:transparent;box-shadow:none;color:var(--accent)}
.tpl-reset .icon{width:14px;height:14px}
.tpl-switch{display:inline-flex;flex-wrap:wrap;gap:3px;padding:3px;border:1px solid var(--line);border-radius:7px;background:var(--surface);max-width:100%}
.tpl-switch button{border:0;background:transparent;color:var(--muted);padding:4px 10px;border-radius:4px;font-size:12px;white-space:nowrap}
.tpl-switch button.is-on{background:var(--accent-soft);color:var(--accent);font-weight:600}
.tpl-switch button:focus-visible{outline-offset:-2px}
.tpl-switch-one{font-size:13px}
.tpl-page,.tpl-container{container:tpl/inline-size}
.tpl-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:14px 20px;align-items:start}
.tpl-view-toggle{position:sticky;top:0;z-index:3;padding:6px 0;background:var(--surface)}
.tpl-layout[data-view=edit] .tpl-preview-col,.tpl-layout[data-view=preview] .tpl-edit-col{display:none}
.tpl-editor{display:flex;flex-direction:column;gap:10px;min-width:0}
.tpl-part{display:flex;flex-direction:column;gap:4px;min-width:0}
.tpl-part-label{margin:0;font-weight:500;font-size:13px}
.tpl-part small{font-size:12px;line-height:1.4}
.tpl-toolbar{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.tpl-toolbar .btn{min-height:30px;font-size:12px;padding:4px 9px;gap:5px}
.tpl-toolbar .icon{width:15px;height:15px}
.tpl-editor small.setting-error,.mailing-editor .tpl-editor small.setting-error{display:block;color:var(--red);font-size:12px;margin:0}
/* the field over its marks: the same font, box and wrapping on both */
.tpl-hl{position:relative;border-radius:6px;background:var(--surface)}
.tpl-hl-back,.tpl-hl-input{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12.5px;line-height:1.55;letter-spacing:0;padding:7px 11px;border:1px solid transparent;tab-size:4}
.tpl-hl-back{position:absolute;inset:0;overflow:hidden;color:transparent;pointer-events:none;border-radius:6px}
.tpl-hl-text{white-space:pre;overflow-wrap:normal}
.tpl-hl.is-multi .tpl-hl-text{white-space:pre-wrap;overflow-wrap:anywhere}
.tpl-hl-input{position:relative;display:block;width:100%;background:transparent!important;border-color:var(--line);color:var(--ink)}
textarea.tpl-hl-input{resize:vertical;overflow-wrap:anywhere;min-height:180px}
input.tpl-hl-input{min-height:0;height:auto}
.tpl-hl.is-multi .tpl-hl-back,textarea.tpl-hl-input{scrollbar-gutter:stable}
.tpl-mark{padding:0;margin:0;border-radius:3px;color:transparent;background:var(--accent-soft);box-shadow:0 0 0 1px var(--accent-soft)}
.tpl-mark.is-list{background:var(--green-soft);box-shadow:0 0 0 1px var(--green-soft)}
.tpl-mark.is-bad{background:var(--red-soft);box-shadow:0 0 0 1px var(--red)}
/* the insert menu */
.tpl-menu{position:relative}
.tpl-menu-panel{position:absolute;z-index:40;top:calc(100% + 4px);left:0;width:min(400px,calc(100vw - 48px));padding:8px;border:1px solid var(--line);border-radius:8px;background:var(--surface);box-shadow:0 10px 30px #0d23401f;display:flex;flex-direction:column;gap:6px}
.tpl-menu-for{font-size:11px}
.tpl-menu-list{max-height:320px;overflow-y:auto;overscroll-behavior:contain}
.tpl-menu-heading{padding:6px 6px 2px;font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
.tpl-menu-option{display:grid;grid-template-columns:150px minmax(0,1fr);gap:0 10px;padding:6px;border-radius:5px;cursor:pointer;font-size:12.5px;line-height:1.35}
.tpl-menu-option code{grid-row:span 2;align-self:start;justify-self:start;font-size:12px;color:var(--accent);background:var(--accent-soft);padding:1px 5px;border-radius:4px;white-space:nowrap}
.tpl-menu-option small{grid-column:2;font-size:11px;overflow-wrap:anywhere}
.tpl-menu-option.is-active{background:var(--canvas);outline:1px solid var(--accent)}
.tpl-menu-option.is-unfit{cursor:default;opacity:.55}
.tpl-menu-text{min-width:0;overflow-wrap:anywhere}
.tpl-menu-none{padding:8px 6px;font-size:12px}
/* the preview */
.tpl-preview-col{display:flex;flex-direction:column;gap:8px;min-width:0;padding:12px;border:1px solid var(--line);border-radius:8px;background:var(--canvas)}
.tpl-preview-head{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px}
.tpl-preview-head h3{margin:0;font-size:13px}
.tpl-preview-title{display:flex;align-items:center;gap:5px}
.tpl-preview-title .help-tooltip>span{transform:translateX(-30%)}
/* the switches flow with the heading: «1 ticket / several» beside it in a 300 px column */
.tpl-page .tpl-preview-switches{display:contents}
.tpl-preview-switches{display:flex;flex-wrap:wrap;gap:6px;min-width:0}
.tpl-preview-switches .tpl-switch{padding:2px}
.tpl-preview-switches .tpl-switch button{padding:3px 8px;font-size:11.5px}
.tpl-preview-body{display:flex;flex-direction:column;gap:8px;min-width:0;max-height:430px;overflow-y:auto}
.tpl-preview-col>small{font-size:12px}
.tpl-bubble{align-self:flex-start;max-width:100%;padding:9px 12px;border-radius:12px 12px 12px 4px;border:1px solid var(--line);background:var(--surface);font-size:13px;line-height:1.45;overflow-wrap:anywhere}
.tpl-bubble-line{min-height:1em}
.tpl-letter{display:flex;flex-direction:column;gap:6px;min-width:0}
.tpl-letter-head{display:flex;flex-direction:column;gap:2px;margin:0;font-size:12.5px;overflow-wrap:anywhere}
.tpl-letter-frame{display:block;width:100%;height:340px;border:1px solid var(--line);border-radius:6px;background:#fff}
/* the rows' window */
.sd-dialog.tpl-rows-dialog{max-width:760px}
.tpl-rows{list-style:none;margin:0 0 14px;padding:0;display:flex;flex-direction:column;gap:6px}
/* the heading row and each field row are grids of the same tracks - the label's and the buttons' of fixed widths, so
   the flexible ones split the same width in every row and each heading stands over its column */
.tpl-rows-head,.tpl-row{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,1.3fr) 112px 100px;gap:8px 10px;align-items:center}
.tpl-rows.is-mail .tpl-rows-head,.tpl-rows.is-mail .tpl-row{grid-template-columns:minmax(0,.9fr) minmax(0,1fr) 104px minmax(0,1.25fr) 100px}
.tpl-rows-head{font-size:11px;color:var(--muted);padding:0 0 2px}
.tpl-row{padding:4px 0;border-top:1px solid var(--line)}
.tpl-rows .form-control,.tpl-rows .form-select{min-height:32px;padding-top:4px;padding-bottom:4px}
.tpl-row-name{font-size:13px;overflow-wrap:anywhere}
.tpl-row-heading,.tpl-row-where{margin:0;min-width:0}
.tpl-row-label{margin:0;display:flex;align-items:center;gap:6px;padding:0;min-height:0}
.tpl-row-label .form-check-input{margin:0;float:none}
.tpl-row-caption{display:none;font-size:12px}
.tpl-row-actions{display:flex;gap:2px}
.tpl-row-actions .icon{width:16px;height:16px}
.tpl-row-actions .is-up{transform:rotate(180deg)}
.tpl-rows-add{display:flex;align-items:center;gap:10px;margin:0 0 14px;font-size:13px}
.tpl-rows-add .form-select{width:auto;min-width:220px;max-width:100%}
.tpl-rows-sample{display:flex;flex-direction:column;gap:6px;font-size:12px;margin-top:12px}
.tpl-rows-sample+.tpl-rows-sample{margin-top:10px}
.tpl-chat-line{white-space:pre-wrap;min-height:1em}
/* {TABLE} of a letter: the headings over the sample tickets, as the letter's table (it scrolls inside itself when
   wider than the window, never the page) */
.tpl-rows-table-wrap{max-width:100%;overflow-x:auto}
.tpl-rows-table{border-collapse:collapse;font-size:12.5px;background:var(--surface)}
.tpl-rows-table th,.tpl-rows-table td{border:1px solid var(--line);padding:4px 8px;text-align:left;vertical-align:top;overflow-wrap:break-word}
.tpl-rows-table th{background:var(--canvas);font-weight:600}
.tpl-chat{padding:9px 12px;border-radius:8px;border:1px solid var(--line);background:var(--canvas);font-size:13px;line-height:1.45;overflow-wrap:anywhere}
@container tpl (min-width:680px){
  .tpl-layout{grid-template-columns:minmax(0,1.25fr) minmax(0,1fr)}
  .tpl-layout.is-digest{grid-template-columns:minmax(0,1fr) minmax(0,1.15fr)}
  .tpl-view-toggle{display:none}
  .tpl-layout[data-view] .tpl-preview-col,.tpl-layout[data-view] .tpl-edit-col{display:flex}
  .tpl-layout[data-view] .tpl-edit-col{display:block}
  .tpl-preview-col{position:sticky;top:12px}
  /* the templates of the notifications: the editor and the letter sized to the window, so both are whole in it as the
     tab opens at 1280 x 800 and 1366 x 768 (the page's heading, tabs and the card's row take ~390 px above them); the
     letter scrolls inside its frame, a Telegram message inside the preview */
  .tpl-page .tpl-letter-frame{height:clamp(180px,calc(100vh - 587px),560px)}
  .tpl-page .tpl-preview-body{max-height:clamp(220px,calc(100vh - 470px),720px)}
}
/* in the editor's heading the ⓘ may land anywhere once the row wraps (from ~760 px down - at the left edge too, where
   a help opening leftwards would run off the window): its help opens under the heading, card-wide */
@media (max-width:800px){
  .tpl-heading{position:relative}
  .tpl-heading .help-tooltip{position:static}
  .tpl-heading .help-tooltip>span{top:calc(100% - 6px);bottom:auto;left:16px;right:16px;width:auto;max-width:none;transform:none}
}
@media (max-width:600px){
  /* the help of the templates' card: from the title's left edge, as wide as the screen allows - never past its edge */
  .tpl-card-title{position:relative}
  .tpl-card-title .help-tooltip{position:static}
  .tpl-card-title .help-tooltip>span{left:0;right:auto;transform:none;width:min(320px,calc(100vw - 64px))}
  .tpl-rows-head{display:none}
  .tpl-row,.tpl-rows.is-mail .tpl-row{grid-template-columns:minmax(0,1fr) auto}
  .tpl-row-name{grid-column:1/-1;font-weight:500}
  .tpl-row-heading{grid-column:1}
  .tpl-row-label{grid-column:1/-1}
  .tpl-row-caption{display:inline}
  .tpl-row-where{grid-column:1}
  .tpl-row-actions{grid-column:2;grid-row:2}
  .tpl-pick{flex-wrap:wrap}
  .tpl-pick .form-select{min-width:0;width:100%}
}
/* The recipients and the journal: tight cells, like the Synchronization run log's (.sync-runs); the page never scrolls
   sideways (.notify-scroll). The recipients by both channels (the owner, 2026-10-01): a person a row - the name, the
   Telegram chat, the letters' addresses - each chat and each address a line with its button at the right; the cells
   start at the top, so a person with three addresses still reads from his name. Under the addresses, past a line of
   its own (it is the person's, not the last address's): when he last got an event letter. Above the table: a line per
   channel that sends nothing now (orange, as `.notify-channel-off`), then the totals and the period's segmented switch
   as the filter, wrapping under the totals on a phone.
   The card is narrow not only on a phone: beside the Settings menu its box is 295 px at a 768 px screen, 551 px at
   1024 and 627 px at 1100 - narrower than at 700, where the menu goes above. So what a narrow box needs follows the
   box, not the screen: the list's box and the journal's scroll box are size containers (`notify-box`). Under 700 px
   of it each button of the list goes under its text - the three columns then read down to 520 px, the table's least
   width. In a box narrower still (a phone, a tablet upright: 307 and 295 px) a sideways scroll would leave the
   letters - what the list is for - off the screen behind the Telegram column, with nothing to say they are there. So
   there a person's three cells stand one under another, as the import's table does on a phone (`.import-table`): the
   name, then each channel under its column's name (the cell's `data-label`; the header row is kept for a screen
   reader only), each button beside its text again - nothing of the list scrolls sideways. */
.notify-recipients-box,.notify-journal-box{container:notify-box/inline-size}
.notify-recipients thead th,.notify-journal thead th{padding:11px 10px;white-space:normal}
.notify-recipients td,.notify-journal td{padding:10px}
.notify-recipients{min-width:520px}
.notify-recipients td{vertical-align:top}
.notify-recipients td small{display:block;font-size:11px;color:var(--muted);margin-top:3px;overflow-wrap:anywhere}
.notify-recipients td small.text-danger{color:var(--red)}
.notify-recipients .notify-who-cell{width:24%;overflow-wrap:anywhere}
.notify-recipients .notify-who-cell strong{font-weight:500}
.notify-recipients .notify-chat-cell{width:36%}
.notify-recipients .notify-none{font-size:12px;color:var(--muted)}
.notify-chat,.notify-letters>li{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.notify-chat+.notify-chat,.notify-letters>li+li{margin-top:8px;padding-top:8px;border-top:1px solid var(--line)}
.notify-chat-text,.notify-letter-text{min-width:0}
.notify-chat-text>small:first-child{margin-top:0}
.notify-chat-name{display:block;overflow-wrap:anywhere}
.notify-chat .btn,.notify-letters .btn{flex:0 0 auto;white-space:nowrap}
.notify-letters{list-style:none;margin:0;padding:0}
.notify-recipients .notify-last-letter{margin-top:8px;padding-top:8px;border-top:1px solid var(--line)}
.notify-recipients-note{margin:0 0 8px;font-size:12px;line-height:1.4;color:var(--orange)}
.notify-recipients-bar{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px 16px}
.notify-recipients-totals{margin:0;font-size:13px}
.notify-recipients-filter{flex:0 0 auto}
.notify-recipients-filter button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
@media (max-width:560px){.notify-recipients-filter{width:100%}.notify-recipients-filter button{flex:1 1 0}}
/* The journal's «Кому» (the owner, 2026-10-01): a button in a last narrow column - its caret turns when the row under
   it is open - and that row across the table, on the canvas: a recipient a line - the person, the channel (a letter
   with its addresses), the round, how it went (green - taken, orange - waiting, red - not delivered, muted - no longer
   true), when. In a box under 700 px (`notify-box` above: a phone, or the card beside the Settings menu up to about
   1170 px of the screen) the line folds - the person and the channel a line each, then the round and the outcome -
   and the button's column stays at the box's right edge while the table scrolls under it, so «Кому» is always in
   reach; its shadow only under 620 px, where the table is surely wider than its box (it cannot be narrower than
   about 600 px), never beside a table that fits. */
.notify-journal td:first-child{white-space:nowrap}
.notify-journal td.notify-journal-open{width:1%;white-space:nowrap;text-align:right}
.notify-journal-toggle::after{content:"";display:inline-block;margin-left:6px;border:4px solid transparent;border-top-color:currentColor;border-bottom-width:0;vertical-align:middle;transition:transform .15s}
.notify-journal-toggle[aria-expanded="true"]::after{transform:rotate(180deg)}
.notify-journal-toggle:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.notify-journal .notify-journal-who>td{padding:4px 10px 8px;background:var(--canvas);white-space:normal}
.notify-who{list-style:none;margin:0;padding:0;font-size:12px;line-height:1.4}
.notify-who>li{display:grid;grid-template-columns:minmax(0,1.3fr) minmax(0,2.2fr) minmax(0,1fr) minmax(0,1fr) 160px;gap:2px 14px;align-items:baseline;padding:6px 0}
.notify-who>li+li{border-top:1px solid var(--line)}
.notify-who-name,.notify-who-channel{overflow-wrap:anywhere}
.notify-who-round{color:var(--muted)}
.notify-who-outcome.is-sent{color:var(--green)}
.notify-who-outcome.is-waiting{color:var(--orange)}
.notify-who-outcome.is-failed{color:var(--red)}
.notify-who-outcome.is-obsolete{color:var(--muted)}
.notify-who-at{color:var(--muted);white-space:nowrap;text-align:right}
@media (prefers-reduced-motion:reduce){.notify-journal-toggle::after{transition:none}}
@container notify-box (max-width:699px){
  .notify-chat,.notify-letters>li{flex-direction:column;justify-content:flex-start;gap:6px}
  .notify-who>li{grid-template-columns:auto minmax(0,1fr)}
  .notify-who-name,.notify-who-channel,.notify-who-at{grid-column:1/-1}
  .notify-who-at{text-align:left}
  .notify-journal td.notify-journal-open{position:sticky;right:0;background:var(--surface)}
}
@container notify-box (max-width:619px){
  .notify-journal td.notify-journal-open{box-shadow:-8px 0 8px -8px #0d234026}
}
@container notify-box (max-width:519px){
  .notify-recipients thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
  .notify-recipients,.notify-recipients tbody,.notify-recipients tr,.notify-recipients td{display:block;width:auto;min-width:0}
  .notify-recipients tr{padding:10px 0;border-bottom:1px solid var(--line)}
  .notify-recipients td,.notify-recipients .notify-who-cell,.notify-recipients .notify-chat-cell{width:auto;padding:5px 10px;border-bottom:0}
  .notify-recipients td[data-label]::before{content:attr(data-label);display:block;margin-bottom:4px;font-size:11px;font-weight:600;color:var(--muted)}
  .notify-chat,.notify-letters>li{flex-direction:row;justify-content:space-between;gap:10px}
}
@media(max-width:560px){.connect-link-row{flex-wrap:wrap}}

/* At 760px and below the prototype shrinks a page heading's buttons to their icon (`.heading-actions .btn{font-size:0;
   width:36px}`), but Tabler's `.btn .icon` keeps its uneven side margins (-1/4 and +1/2 of the button's padding), so the
   icon stood off centre - the Tickets "Columns" button's three lines among them (owner, 2026-09-28). */
@media (max-width:760px){.heading-actions .btn{justify-content:center}.heading-actions .btn .icon{margin:0}}
/* The prototype's shrink reaches every `.btn` under `.heading-actions`, and a window (dialog.sd-dialog) opened from a
   heading button sits in the heading's markup (SettingsHistory, PdfButton), so its buttons shrank too: Settings' "Show
   more" to an empty 36 px square, the PDF window's "Download PDF" to a bare icon. A window's buttons keep their size
   and label: Tabler's padding and icon margins, the prototype's gap, their own width. */
@media (max-width:760px){.heading-actions .sd-dialog .btn{font-size:var(--tblr-btn-font-size);width:auto;padding:var(--tblr-btn-padding-y) var(--tblr-btn-padding-x);gap:7px}.heading-actions .sd-dialog .btn .icon{margin:0 calc(var(--tblr-btn-padding-x)/ 2) 0 calc(var(--tblr-btn-padding-x)/ -4)}}

/* Part 6b spec M3а: the Telegram link by mail - the card's lines. */
.people-telegram-mailed{color:var(--muted)}
/* the profile's addresses (part 6b spec M5): each with what it gets and «Присылать сюда»; one no letter reaches, grey */
.profile-addresses-hint{margin-top:4px}
.profile-address{overflow-wrap:anywhere}
.profile-address-switch{display:flex;align-items:center;gap:8px;flex-shrink:0}
.profile-address-switch>small{font-size:12px;color:var(--muted);white-space:nowrap}
/* on a phone «Присылать сюда» is said once in the hint above the list - each address gets the row's width (its review
   finding: addresses broken mid-word); the word stays for a screen reader */
@media (max-width:480px){.profile-address-switch>small{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}}
/* whether an address is on and who switched it on (the owner, 2026-09-29: opt-in) */
.profile-address-state{font-size:12px;color:var(--muted)}
.profile-address-state.is-on{color:var(--green)}
.profile-mail-optin{margin-top:0}
/* People's card: every address of the employee and whether it receives letters (part 6b spec M5), read-only */
.people-mail-addresses{list-style:none;margin:0 0 8px;padding:0}
.people-mail-addresses>li{display:flex;flex-direction:column;gap:2px;padding:6px 0;border-bottom:1px solid var(--line);min-width:0}
.people-mail-addresses>li:last-child{border-bottom:0}
.people-mail-addresses .people-email{overflow-wrap:anywhere}
.people-mail-addresses>li[data-receives="no"] .people-email{color:var(--muted)}
.people-mail-scope{font-size:12px}
/* an administrator's «Присылать сюда» at the right of each address (the owner, 2026-09-29) */
.people-mail-address-head{display:flex;align-items:center;justify-content:space-between;gap:8px;min-width:0}
.people-mail-address-head .people-email{min-width:0}
.people-mail-address-head .people-mail-switch{flex-shrink:0;font-size:12px;color:var(--muted)}

/* «Сводки» (spec 2026-09-29 G1, G6). The two tabs of Settings → Notifications are links (each a page): the prototype's
   `.page-tabs` drawn for `<a>` as it draws its buttons. */
.notify-page-tabs a{padding:0 2px 13px;border-bottom:2px solid transparent;color:var(--muted);text-decoration:none;display:flex;gap:8px;align-items:center}
.notify-page-tabs a.active{color:var(--accent);border-color:var(--accent)}
.notify-page-tabs a:focus-visible{outline-offset:-2px;border-radius:4px}
@media (max-width:760px){.notify-page-tabs a{font-size:12px;white-space:nowrap}}
/* five tabs: in a narrow window the row scrolls by itself, never the page */
@media (max-width:1099px){.notify-page-tabs{overflow-x:auto;overflow-y:hidden;scrollbar-width:thin}.notify-page-tabs a{white-space:nowrap}}
.digests-card .card-heading,.mailing-card .card-heading,.mailing-check-card .card-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}
.mailing-back{display:inline-block;font-size:12px;color:var(--muted);margin-bottom:4px;text-decoration:none}
.mailing-back:hover{color:var(--accent)}
.digests-table td small{display:block;font-size:11px;color:var(--muted);margin-top:4px}
/* The list fits the card of a window from 1100 px (627 px inside it) with no sideways scroll: tight cells, and the three
   actions one under another in a narrow last column (a delete error under them, as wide as they are). Only on a phone
   (760 px and less) the tables keep a readable width and scroll inside their card instead of squeezing. */
.digests-table thead th,.digests-table td{padding:12px 10px}
.digests-table td:nth-child(2){width:32%}
.digests-table td:last-child{width:1%}
.mailing-actions{flex-direction:column;flex-wrap:nowrap;align-items:stretch;gap:6px}
.mailing-actions .btn{justify-content:center}
.mailing-actions .setting-error{display:block;max-width:120px;color:var(--red);font-size:12px;overflow-wrap:anywhere}
.mailing-journal thead th,.mailing-journal td{padding:10px}
@media (max-width:760px){
  .digests-table{min-width:640px}
  .mailing-recipients{min-width:520px}
  .mailing-journal{min-width:560px}
}
.alert.mailing-shared{display:block}
.mailing-shared>strong{display:block}
.mailing-shared ul{margin:6px 0 4px;padding-left:18px;overflow-wrap:anywhere}
.mailing-shared small{display:block;font-size:12px}
/* the editor: sections one under the other; a section's fields side by side while they fit, one under another on a phone */
.mailing-editor small.setting-error{display:block;color:var(--red);font-size:12px;margin-top:5px}
.mailing-editor .form-label{display:flex;flex-direction:column;gap:6px;font-size:13px;min-width:0}
.mailing-editor .form-label[hidden]{display:none}
.mailing-editor small.muted{font-size:12px;line-height:1.4}
.mailing-row{display:flex;flex-wrap:wrap;gap:16px 28px;align-items:flex-start;margin-bottom:8px}
.mailing-name{flex:1 1 280px}
.mailing-switch{display:flex;gap:10px;align-items:flex-start;flex:1 1 240px;margin-top:22px}
.mailing-switch small{display:block;margin-top:3px}
.mailing-section{border:0;border-top:1px solid var(--line);margin:18px 0 0;padding:16px 0 0;min-width:0}
.mailing-section>legend{float:none;width:auto;font-size:14px;font-weight:600;margin:0 0 10px;padding:0}
.mailing-statuses{display:flex;flex-direction:column;gap:6px;margin-bottom:14px}
.mailing-checks{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:4px 16px;margin-top:4px}
.mailing-checks .form-check{margin:0;min-width:0;overflow-wrap:anywhere}
.mailing-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px 18px;margin-bottom:10px}
.mailing-mode{margin-top:14px;max-width:520px}
/* the letters as they go: a white sheet in a frame (sandboxed - the letter's own HTML), its subject and addresses above */
.mailing-letter{margin:14px 0 0;min-width:0}
.mailing-letter h4{font-size:13px;margin:0 0 6px}
.mailing-letter-head{display:flex;flex-wrap:wrap;gap:4px 16px;font-size:12px;color:var(--muted);margin:6px 0;overflow-wrap:anywhere}
.mailing-letter-frame{display:block;width:100%;height:360px;border:1px solid var(--line);border-radius:6px;background:#fff}
details.mailing-letter{border:1px solid var(--line);border-radius:6px;padding:10px 12px}
details.mailing-letter>summary{cursor:pointer;font-size:13px;overflow-wrap:anywhere}
details.mailing-letter>summary small{display:block;font-size:12px;color:var(--muted);margin-top:3px}
/* the check */
.mailing-check h3{font-size:14px;margin:22px 0 10px}
.mailing-totals{display:flex;flex-wrap:wrap;gap:12px 36px;margin:0 0 6px}
.mailing-totals>div{display:flex;flex-direction:column}
.mailing-totals dt{font-size:12px;font-weight:400;color:var(--muted)}
.mailing-totals dd{font-size:26px;font-weight:500;margin:0}
.mailing-totals>div[data-gaps]:not([data-gaps="0"]) dd{color:var(--red)}
.mailing-by-kind{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:6px 22px;font-size:13px}
.mailing-recipients td{overflow-wrap:anywhere}
.mailing-gaps{list-style:none;padding:0;margin:0}
.mailing-gaps>li{padding:10px 0;border-bottom:1px solid var(--line);font-size:13px}
.mailing-gaps>li:last-child{border-bottom:0}
.mailing-gaps>li>small{display:block;font-size:12px;color:var(--muted);margin-top:4px;overflow-wrap:anywhere}
.mailing-gaps .number-badge{margin-left:8px}
.mailing-gap-tickets{margin:6px 0 0;padding-left:18px;font-size:12px}
.mailing-send{margin:22px 0 6px;padding:16px 0 0;border-top:1px solid var(--line)}
.mailing-send>small{display:block;font-size:12px;margin-top:8px}
.mailing-send-status{min-height:1.4em;margin:8px 0 0;font-size:13px}
.mailing-send-status.is-ok{color:var(--green)}
.mailing-send-status.is-error{color:var(--red)}
.mailing-letters{display:flex;flex-direction:column;gap:10px}
/* the journal: each letter a line with its delivery */
.mailing-journal td>small{display:block;font-size:11px;color:var(--muted);margin-top:4px}
.mailing-journal-letters{list-style:none;padding:0;margin:0}
.mailing-journal-letters>li{padding:4px 0;font-size:12px;overflow-wrap:anywhere}
.mailing-journal-letters>li>small{display:block;color:var(--muted)}
.mailing-journal-letters .neutral-badge{margin-top:3px}
.mailing-journal-letters .neutral-badge.is-ok,.mailing-journal td>.neutral-badge.is-ok{color:var(--green);border-color:var(--green)}
.mailing-journal-letters .neutral-badge.is-error,.mailing-journal td>.neutral-badge.is-error{color:var(--red);border-color:var(--red)}
.mailing-journal td>.neutral-badge{margin-bottom:4px}
.mailing-journal-planned{display:block;font-size:12px;color:var(--muted)}

/* Settings save in the background, no "Save" (the owner, 2026-09-30; src/lib/autosave.ts): the one status line beside a
   card's heading (src/components/settings/AutosaveStatus.tsx, SettingsCard.tsx) - quiet grey before a change, a small
   spinner while saving, green "Saved" with its note, red "Not saved: …". On a phone it drops under the heading. */
.settings-card-heading{align-items:flex-start;flex-wrap:wrap}
.autosave-status{margin:0;display:flex;flex-direction:column;align-items:flex-end;gap:2px;font-size:12px;line-height:1.4;color:var(--muted);max-width:min(100%,380px);text-align:right;min-height:20px}
.autosave-line{display:inline-flex;align-items:center;gap:6px}
.autosave-status .icon{width:16px;height:16px}
.autosave-status small{display:block;font-size:12px;color:var(--muted)}
.autosave-status small.is-warn{color:var(--orange)}
.autosave-status.is-saved .autosave-line{color:var(--green)}
.autosave-status.is-error .autosave-line{color:var(--red)}
.autosave-spinner{flex-shrink:0;width:12px;height:12px;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:autosave-spin .8s linear infinite}
@keyframes autosave-spin{to{transform:rotate(360deg)}}
@media (prefers-reduced-motion:reduce){.autosave-spinner{animation:none}}
@media (max-width:600px){.autosave-status{align-items:flex-start;text-align:left;max-width:100%;flex-basis:100%}}
.sla-rule-dialog .sla-editor-status{margin-right:auto;display:flex;align-items:center}
/* A refusal in a long card (a form, a matrix, a year of holidays) stays in sight (review of 2026-09-30): while the
   card's heading is scrolled out of the window its line floats at the bottom, red on the page's surface; a click brings
   the heading back (SettingsCard.tsx). */
.autosave-float{position:fixed;left:50%;bottom:16px;transform:translateX(-50%);z-index:100;display:inline-flex;align-items:center;gap:8px;max-width:calc(100vw - 32px);padding:10px 14px;border:1px solid var(--red);border-radius:8px;background:var(--surface);color:var(--red);font:inherit;font-size:13px;line-height:1.4;text-align:left;box-shadow:0 8px 35px #0002;cursor:pointer}
.autosave-float .icon{flex-shrink:0;width:16px;height:16px}
/* Settings → Notifications save in the background too (the owner, 2026-09-30, item 5): a digest's heading holds the way
   back and the name, the status line and «Проверить и отправить» - the line beside the button. */
.mailing-card .settings-card-heading>.autosave-status{margin-left:auto}
.sync-log-footer [aria-disabled="true"]{opacity:.55;cursor:default}
.tenant-alias .setting-error{display:block;color:var(--red);font-size:12px;margin-top:4px}
/* Settings → Forms: the form picker above the chosen form's card (the owner's item 12 of 2026-09-30;
   src/components/settings/FormPicker.tsx) - the caption and the list you can type into, as wide as a long form name. */
.forms-picker{margin:0 0 16px}
.forms-picker .search-select>label{display:block;font-size:12px;color:var(--muted);margin-bottom:5px}
.forms-picker-field{width:min(100%,460px)}
/* The KPI of the "All tenants" mode (spec 2026-09-23 D6, src/components/kpi/KpiAllScreen.tsx): every tenant's report in a
   block of its own, one under the other, parted by a rule; its heading names the tenant (a tag) and ends with "Open this
   tenant". The style switch and the PDF sit together in the page heading. */
.kpi-tenant-block{border-top:1px solid var(--line);margin-top:30px;padding-top:4px}
.kpi-all .kpi-tenant-block:first-of-type{border-top:0;margin-top:0;padding-top:0}
.kpi-tenant-block .kpi-indicator-heading h2{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.kpi-tenant-block .kpi-indicator-heading .tenant-tag{font-size:12px;padding:2px 8px}
.kpi-tenant-open{flex-shrink:0;white-space:nowrap}
.kpi-all-heading-tools{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
/* The heading holds two controls here (the style switch and PDF): it wraps as Tasks' does (`.my-heading` above), the
   controls taking a row of their own below the title on a narrow screen. */
@media(max-width:900px){.kpi-all-heading{flex-wrap:wrap}}
@media(max-width:760px){.kpi-tenant-open{margin-left:auto}.kpi-all-heading .heading-actions{width:100%;justify-content:space-between}}
/* People → "Import e-mails" (the owner, 2026-10-01; src/components/people/EmailImport.tsx): the file step, the preview -
   the totals in a row of tiles, a row per person of the file with whom it is and what happens to each address - and the
   result. Colors are the tokens: green - will be added, orange - not found or a choice to make, red - a conflict. On a
   phone the table turns into cards (each cell under its own caption), so no address is cut and nothing scrolls sideways. */
.people-import-link{flex-shrink:0;white-space:nowrap}
.import-heading{flex-wrap:wrap}
.import-heading .btn{flex-shrink:0;white-space:nowrap}
.import-card{margin-bottom:22px;transition:opacity .15s}
.import-card[aria-busy="true"]{opacity:.55;pointer-events:none}
@media (prefers-reduced-motion:reduce){.import-card{transition:none}}
.import-how{margin:0 0 18px;font-size:13px;max-width:860px}
.import-source{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 20px;margin-bottom:18px;align-items:start}
.import-source .form-label{font-size:13px;font-weight:500}
.import-source textarea{font-size:13px;min-height:132px}
.import-card .alert{font-size:13px;margin-bottom:14px}
.import-card .form-hint{font-size:12px;color:var(--muted);margin:12px 0 0}
.import-hint{font-size:12px;color:var(--muted)}
small.import-hint{display:block;margin-top:4px}
.import-totals{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:10px;margin:0;padding:4px 20px 16px}
.import-totals>div{border:1px solid var(--line);border-radius:8px;padding:10px 12px;min-width:0}
.import-totals dt{font-size:12px;font-weight:400;color:var(--muted);overflow-wrap:anywhere}
.import-totals dd{margin:2px 0 0;font-size:22px;font-weight:600;font-variant-numeric:tabular-nums;line-height:1.2}
.import-totals .is-add dd{color:var(--green)}
.import-totals .is-conflict dd{color:var(--red)}
.import-totals .is-missing dd{color:var(--orange)}
.import-skipped{margin:0;padding:0 20px 12px;font-size:12px;color:var(--muted)}
.import-table{margin:0}
.import-table td{vertical-align:top;padding:14px 20px}
.import-table .import-name{font-weight:500;overflow-wrap:anywhere;min-width:150px;width:18%}
.import-table .import-person{min-width:220px;width:32%}
.import-table .import-person>strong{font-weight:500;overflow-wrap:anywhere}
.import-missing{color:var(--orange);background:var(--orange-soft);border-color:transparent}
.import-choice{border:0;margin:0;padding:0;min-width:0;display:grid;gap:6px}
.import-choice legend{float:none;width:auto;margin:0 0 2px;padding:0;font-size:12px;font-weight:500;color:var(--orange)}
.import-option{display:flex;align-items:flex-start;gap:8px;margin:0;font-size:13px;cursor:pointer}
.import-option .form-check-input{float:none;flex-shrink:0;margin:2px 0 0}
.import-option>span{min-width:0;overflow-wrap:anywhere}
.import-addresses{list-style:none;margin:0;padding:0;display:grid;gap:6px}
.import-address{display:flex;flex-wrap:wrap;align-items:center;gap:3px 8px;font-size:13px}
.import-address .people-email{font-weight:500}
.import-note{font-size:12px;color:var(--muted);overflow-wrap:anywhere}
.import-add{color:var(--green);background:var(--green-soft);border-color:transparent;margin-left:0}
.import-address.is-present .people-email,.import-address.is-idle .people-email,.import-address.is-invalid .people-email{font-weight:400;color:var(--muted)}
.import-address.is-conflict .import-note,.import-address.is-repeated .import-note,.import-reason.is-conflict,.import-reason.is-repeated,.import-reason.is-failed{color:var(--red)}
.import-address.is-invalid .people-email{text-decoration:line-through}
.import-reason{font-size:12px;color:var(--muted)}
.import-reason.is-not-found,.import-reason.is-stale,.import-reason.is-skipped,.import-reason.is-unsent{color:var(--orange)}
.import-chosen{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;margin:8px 0 0}
.import-chosen .btn{flex:0 0 auto}
.import-footer{border-top:1px solid var(--line)}
.import-table tbody tr:last-child td{border-bottom:0}
.import-letters{margin:0 0 14px;font-size:12px;color:var(--muted);max-width:860px}
.import-subtitle{margin:18px 0 8px;font-size:14px;font-weight:600}
.import-done{list-style:none;margin:0;padding:0}
.import-done>li{display:flex;flex-wrap:wrap;align-items:center;gap:3px 10px;padding:9px 0;border-bottom:1px solid var(--line);font-size:13px}
.import-done>li>a{font-weight:500}
.import-done .neutral-badge{margin-left:0}
.import-skipped-table td{padding-left:0}
.import-skipped-table th:first-child{padding-left:0}
.import-result-actions{margin-top:20px}
@media(max-width:760px){
  .import-source{grid-template-columns:minmax(0,1fr)}
  .import-totals{grid-template-columns:repeat(2,minmax(0,1fr));padding:4px 15px 14px}
  .import-skipped{padding-left:15px;padding-right:15px}
  .import-table thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
  .import-table,.import-table tbody,.import-table tr,.import-table td{display:block;width:auto;min-width:0}
  .import-table tr{padding:12px 15px;border-bottom:1px solid var(--line)}
  .import-table tbody tr:last-child{border-bottom:0}
  .import-table td,.import-table .import-name,.import-table .import-person{padding:0 0 8px;border-bottom:0;min-width:0;width:auto}
  .import-table td:last-child{padding-bottom:0}
  .import-table td[data-label]::before{content:attr(data-label);display:block;font-size:11px;color:var(--muted);font-weight:400;margin-bottom:2px}
  .import-skipped-table tr{padding-left:0;padding-right:0}
  .import-card .button-row .btn{flex:1 1 auto}
}
@media (pointer:coarse){.import-source textarea,.import-source input{font-size:16px}}
