/*
 * select.css — Ops UI Library: SelectField
 * Uses CSS variables from index.html for automatic dark/light theme support
 */

/* ── Trigger (replaces <select>) ─────────────────────────── */

.sf-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    padding: 8px 10px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    cursor: pointer;
    outline: none;
    transition: border-color 0.15s;
    user-select: none;
    box-sizing: border-box;
}

.sf-trigger:hover {
    border-color: var(--text-2);
}

.sf-trigger:focus {
    border-color: var(--accent);
}

.sf-label {
    font-size: 14px;
    color: var(--text-1);
    flex: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sf-arrow {
    font-size: 11px;
    color: var(--text-2);
    flex-shrink: 0;
    margin-left: 8px;
    transition: transform 0.15s ease;
    display: inline-block;
}

.sf-arrow--open {
    transform: rotate(180deg);
}

/* ── Dropdown ─────────────────────────────────────────────── */

.sf-dropdown {
    position: absolute;
    z-index: 9500;
    background: var(--bg-2);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.15);
    overflow-y: auto;
    padding: 4px 0;
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity 0.15s ease, transform 0.15s ease;

    /* Custom scrollbar */
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

.sf-dropdown::-webkit-scrollbar {
    width: 4px;
}
.sf-dropdown::-webkit-scrollbar-track {
    background: transparent;
}
.sf-dropdown::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 2px;
}

.sf-dropdown--visible {
    opacity: 1;
    transform: translateY(0);
}

/* ── Items ────────────────────────────────────────────────── */

.sf-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 12px;
    height: 38px;
    cursor: pointer;
    transition: background 0.1s;
}

.sf-item:hover {
    background: var(--sidebar-active);
}

.sf-item--active {
    color: var(--tab-active-text);
}

.sf-item--active:hover {
    background: var(--tab-active-bg);
}

.sf-item-check {
    font-size: 12px;
    width: 14px;
    flex-shrink: 0;
    color: var(--accent);
    text-align: center;
}

.sf-item-text {
    font-size: 14px;
    color: inherit;
}

.sf-item--active .sf-item-text {
    font-weight: 600;
}

/*
 * price.css — Ops UI Library: PriceField
 * Uses CSS variables from index.html for automatic dark/light theme support
 */

.pf-wrap {
    display: flex;
    gap: 8px;
    align-items: flex-start;
}

.pf-amount {
    flex: 2;
    min-width: 0;
}

.pf-currency-wrap {
    flex: 1;
    min-width: 0;
    position: relative;
}

.pf-currency-wrap .sf-trigger {
    width: 100%;
    box-sizing: border-box;
}

/*
 * datepicker.css — Ops UI Library: DatePicker
 * Uses CSS variables from index.html for automatic dark/light theme support
 */

/* ── Wrapper ──────────────────────────────────────────────── */

.dp-wrap {
    position: absolute;
    z-index: 9000;
    background: var(--bg-2);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35), 0 2px 8px rgba(0, 0, 0, 0.2);
    overflow: hidden;
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity 0.15s ease, transform 0.15s ease;
    user-select: none;
}

.dp-wrap.dp-visible {
    opacity: 1;
    transform: translateY(0);
}

/* ── Header ───────────────────────────────────────────────── */

.dp-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 12px 8px;
    border-bottom: 1px solid var(--border);
}

.dp-nav-btn {
    background: transparent;
    border: none;
    color: var(--text-2);
    font-size: 16px;
    cursor: pointer;
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    transition: background 0.12s, color 0.12s;
    flex-shrink: 0;
}
.dp-nav-btn:hover {
    background: var(--sidebar-active);
    color: var(--text-1);
}

.dp-title-wrap {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
    flex: 1;
}

.dp-title-month,
.dp-title-year {
    font-size: 13px;
    font-weight: 700;
    color: var(--text-1);
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 6px;
    transition: background 0.12s;
}
.dp-title-month:hover,
.dp-title-year:hover {
    background: var(--sidebar-active);
}

/* ── Body — fixed size, always days ──────────────────────── */

.dp-body {
    min-height: 264px;
    display: flex;
    flex-direction: column;
}

/* ── Day grid ─────────────────────────────────────────────── */

.dp-grid {
    padding: 8px;
    flex: 1;
}

.dp-weekdays {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    margin-bottom: 4px;
}

.dp-weekday {
    text-align: center;
    font-size: 10px;
    font-weight: 700;
    color: var(--text-2);
    padding: 4px 0;
    text-transform: uppercase;
    letter-spacing: 0.3px;
}

.dp-days {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
}

.dp-day {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    aspect-ratio: 1;
    min-width: 32px;
    min-height: 32px;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-1);
    border-radius: 8px;
    cursor: pointer;
    border: 1px solid transparent;
    transition: background 0.1s, color 0.1s, border-color 0.1s;
    background: transparent;
}
.dp-day:hover {
    background: var(--sidebar-active);
    color: var(--text-1);
}
.dp-day--other-month {
    color: var(--text-2);
    opacity: 0.4;
}
.dp-day--today {
    border-color: var(--accent);
    color: var(--tab-active-text);
}
.dp-day--selected {
    background: var(--accent);
    color: #fff;
    border-color: var(--accent);
    font-weight: 700;
}
.dp-day--selected:hover {
    background: var(--accent);
    opacity: 0.9;
}

/* ── Popup overlay ────────────────────────────────────────── */

.dp-popup-overlay {
    position: absolute;
    z-index: 9010;
    pointer-events: auto;
}

.dp-popup-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    border-radius: 12px;
    cursor: default;
}

.dp-popup {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    background: var(--bg-2);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.3);
    overflow: hidden;
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.dp-popup-overlay--visible .dp-popup {
    opacity: 1;
    transform: translateY(0);
}

/* ── Popup nav ────────────────────────────────────────────── */

.dp-popup-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px 12px 8px;
    border-bottom: 1px solid var(--border);
}

.dp-popup-nav-label {
    font-size: 13px;
    font-weight: 700;
    color: var(--text-1);
    flex: 1;
    text-align: center;
}

/* ── Popup body ───────────────────────────────────────────── */

.dp-popup-body {
    padding: 8px;
}

/* ── Month grid (inside popup) ────────────────────────────── */

.dp-months {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
}

.dp-month {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 14px 4px;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-1);
    border-radius: 8px;
    cursor: pointer;
    border: 1px solid transparent;
    transition: background 0.1s;
}
.dp-month:hover {
    background: var(--sidebar-active);
}
.dp-month--today {
    border-color: var(--accent);
    color: var(--tab-active-text);
    font-weight: 700;
}
.dp-month--selected {
    background: var(--accent);
    color: #fff;
    border-color: var(--accent);
    font-weight: 700;
}
.dp-month--selected:hover {
    opacity: 0.9;
}

/* ── Year grid (inside popup) ─────────────────────────────── */

.dp-years {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 4px;
}

.dp-year {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 10px 4px;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-1);
    border-radius: 8px;
    cursor: pointer;
    border: 1px solid transparent;
    transition: background 0.1s;
}
.dp-year:hover {
    background: var(--sidebar-active);
}
.dp-year--today {
    border-color: var(--accent);
    color: var(--tab-active-text);
    font-weight: 700;
}
.dp-year--selected {
    background: var(--accent);
    color: #fff;
    border-color: var(--accent);
}
.dp-year--selected:hover {
    opacity: 0.9;
}
.dp-year--other {
    opacity: 0.35;
}

/*
 * file-upload.css — Ops UI Library: FileUpload
 */

.fu-container {
    display: flex;
    flex-direction: column;
}

/* ── Empty state ──────────────────────────────────────────── */

.fu-empty {
    display: flex;
    align-items: center;
    gap: 10px;
}

.fu-btn-upload {
    display: inline-flex;
    align-items: center;
    padding: 7px 14px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg);
    color: var(--text-1);
    font-size: 13px;
    font-family: inherit;
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
    user-select: none;
    white-space: nowrap;
}

.fu-btn-upload:hover {
    border-color: var(--accent);
    background: var(--sidebar-active);
}

.fu-hint {
    font-size: 12px;
    color: var(--text-2);
}

/* ── Selected state ───────────────────────────────────────── */

.fu-selected {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg);
}

.fu-icon {
    font-size: 14px;
    flex-shrink: 0;
}

.fu-filename {
    flex: 1;
    font-size: 13px;
    color: var(--text-1);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.fu-btn-download {
    flex-shrink: 0;
    background: none;
    border: 1px solid var(--accent);
    border-radius: 6px;
    padding: 3px 10px;
    font-size: 12px;
    font-family: inherit;
    color: var(--accent);
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
    white-space: nowrap;
}

.fu-btn-download:hover {
    background: var(--sidebar-active);
}

.fu-btn-replace,
.fu-btn-delete {
    flex-shrink: 0;
    background: none;
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 3px 10px;
    font-size: 12px;
    font-family: inherit;
    color: var(--text-2);
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
    white-space: nowrap;
}

.fu-btn-replace:hover {
    color: var(--text-1);
    border-color: var(--accent);
}

.fu-btn-delete:hover {
    color: #ef4444;
    border-color: #ef4444;
    background: rgba(239, 68, 68, 0.06);
}

/* ── Inline error (size limit, etc.) ─────────────────────── */

.fu-error {
    margin-top: 6px;
    font-size: 12px;
    color: #ef4444;
}

/* ── SearchBox — live text search input for filter bars ───────────────── */

.search-box {
  position: relative;
  display: inline-flex;
  align-items: center;
  background: rgba(255, 255, 255, .04);
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 10px;
  padding: 0 10px 0 32px;
  height: 36px;
  min-width: 220px;
  transition: border-color .12s ease, background .12s ease;
}

.search-box:focus-within {
  border-color: #3AA7E2;
  background: rgba(255, 255, 255, .06);
}

.search-box--right {
  margin-left: auto;
}

.search-box__icon {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #8794a8;
  pointer-events: none;
}

.search-box:focus-within .search-box__icon {
  color: #3AA7E2;
}

.search-box__input {
  flex: 1;
  background: transparent;
  border: 0;
  outline: 0;
  color: #DCE4F0;
  font-size: 13px;
  font-family: inherit;
  padding: 0;
  height: 100%;
  min-width: 0;
}

.search-box__input::placeholder {
  color: #8794a8;
  opacity: 1;
}

/**
 * digit-field.css — Ops UI Library: DigitField visual feedback
 *
 * Single rule that paints an input red while its current length is non-empty
 * but does not match any allowed lengths. Toggled by lib/digit-field.js.
 *
 * `!important` is required to override the default `.sl-input` background from
 * slider.js — slider form fields use rendering-specific selectors with higher
 * specificity than a plain class.
 */

.is-invalid-length {
    background: rgba(244, 67, 54, 0.15) !important;
    border-color: #e57373 !important;
    transition: background 0.2s, border-color 0.2s;
}

/**
 * inn-field.css — Ops UI Library: InnField visual layer
 *
 * Absolute-positioned autosuggest dropdown anchored to the wrapper.
 * The wrapper itself stays inline-block so the input keeps its slider field
 * layout; the dropdown floats below without disturbing siblings.
 *
 * Empty state — `display: none`. Open state — `.is-open` toggle from JS.
 *
 * Block 6.3.3 of task radar-os--479-contractors-mode.
 */

.if-wrapper {
    position: relative;
    display: block;
}

.if-dropdown {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 9500;
    background: var(--bg-2);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.15);
    max-height: 280px;
    overflow-y: auto;
    display: none;
    color: var(--text);
}

.if-dropdown.is-open {
    display: block;
}

.if-dropdown-row {
    padding: 10px 12px;
    cursor: pointer;
    transition: background 0.15s;
    line-height: 1.35;
    color: var(--text);
}

.if-dropdown-row:hover {
    background: var(--sidebar-active, rgba(255, 255, 255, 0.06));
}

.if-dropdown-icon {
    margin-right: 6px;
}

.if-dropdown-sub {
    margin-top: 2px;
    font-size: 12px;
    color: var(--text-2);
}

/**
 * address-field.css — Ops UI Library: AddressField visual layer
 *
 * Mirrors inn-field.css with `af-` prefix. Same absolute-positioned dropdown
 * pattern — slightly higher max-height since address suggestions list is
 * typically longer (up to 10 rows).
 *
 * Block 6.3.3 of task radar-os--479-contractors-mode.
 */

.af-wrapper {
    position: relative;
    display: block;
}

.af-dropdown {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 9500;
    background: var(--bg-2);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.15);
    max-height: 320px;
    overflow-y: auto;
    display: none;
    color: var(--text);
}

.af-dropdown.is-open {
    display: block;
}

.af-dropdown-row {
    padding: 8px 12px;
    cursor: pointer;
    transition: background 0.15s;
    line-height: 1.35;
    font-size: 13px;
    color: var(--text);
}

.af-dropdown-row:hover {
    background: var(--sidebar-active, rgba(255, 255, 255, 0.06));
}

/**
 * counterparty-picker.css — styles for counterparty-select field
 *
 * Used by window.CounterpartySelect (see counterparty-picker.js).
 * Uses team CSS vars: --bg-2 / --border / --text / --primary / --danger.
 *
 * Task: radar-os--479 block 74.
 */

.cp-container {
  position: relative;
  width: 100%;
}

.cp-field {
  position: relative;
  display: flex;
  align-items: center;
}

.cp-input {
  width: 100%;
  padding-right: 28px;
}

.cp-clear {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  background: transparent;
  border: none;
  color: var(--text, #b8bcc4);
  cursor: pointer;
  font-size: 14px;
  line-height: 1;
  padding: 4px 6px;
  border-radius: 4px;
}

.cp-clear:hover {
  background: var(--bg-2, #1a1e28);
  color: var(--text, #e6e6e6);
}

/* Block 747 round 2 task 479 — «selected input» state + meta caption below */
.cp-container.cp-selected .cp-input {
  border-color: var(--accent, #6366f1);
  background: rgba(99, 102, 241, 0.06);
}

.cp-meta {
  margin-top: 4px;
  font-size: 11px;
  color: var(--text-muted, #8a8f99);
  padding-left: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cp-meta[hidden] {
  display: none;
}

/* Dropdown container */
.cp-dropdown {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 4px);
  background: var(--bg-2, #1a1e28);
  border: 1px solid var(--border, #2a2e38);
  border-radius: 8px;
  max-height: 380px;
  overflow-y: auto;
  z-index: 1000;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}

.cp-dropdown[hidden] {
  display: none;
}

/* Search result row */
.cp-item {
  padding: 10px 14px;
  cursor: pointer;
  border-bottom: 1px solid var(--border, #2a2e38);
  transition: background 0.1s;
}

.cp-item:last-child {
  border-bottom: none;
}

.cp-item:hover {
  background: var(--bg-3, #232833);
}

.cp-item-name {
  font-size: 14px;
  color: var(--text, #e6e6e6);
  font-weight: 500;
}

.cp-item-meta {
  font-size: 12px;
  color: var(--text-muted, #8a8f99);
  margin-top: 2px;
}

/* «➕ Создать» row */
.cp-item-create {
  padding: 12px 14px;
  cursor: pointer;
  background: var(--bg-3, #232833);
  border-top: 1px dashed var(--border, #2a2e38);
  color: var(--primary, #4ea4d6);
  font-size: 14px;
  font-weight: 500;
  transition: background 0.1s;
}

.cp-item-create:hover {
  background: var(--primary, #4ea4d6);
  color: #fff;
}

.cp-item-create b {
  font-weight: 600;
}

/* Mini-form (rendered inside dropdown) */
.cp-miniform {
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.cp-mf-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text, #e6e6e6);
  margin-bottom: 4px;
}

.cp-mf-label {
  font-size: 12px;
  color: var(--text-muted, #8a8f99);
  margin-top: 2px;
}

.cp-mf-name,
.cp-mf-inn .if-input,
.cp-mf-type {
  width: 100%;
}

.cp-mf-inn {
  position: relative;
}

.cp-mf-actions {
  display: flex;
  gap: 8px;
  margin-top: 8px;
}

.cp-btn {
  padding: 8px 16px;
  border-radius: 6px;
  font-size: 14px;
  cursor: pointer;
  border: 1px solid transparent;
  transition: background 0.1s, opacity 0.15s;
}

.cp-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.cp-btn-primary {
  background: var(--primary, #4ea4d6);
  color: #fff;
  flex: 1;
}

.cp-btn-primary:hover:not(:disabled) {
  background: var(--primary-hover, #6EC1FF);
}

.cp-btn-secondary {
  background: transparent;
  border-color: var(--border, #2a2e38);
  color: var(--text, #e6e6e6);
}

.cp-btn-secondary:hover {
  background: var(--bg-3, #232833);
}

.cp-mf-error {
  color: var(--danger, #dc4a4a);
  font-size: 13px;
  padding: 8px 10px;
  background: rgba(220, 74, 74, 0.1);
  border-radius: 6px;
  margin-top: 4px;
}

.cp-mf-error[hidden] {
  display: none;
}

/**
 * load-more.css — companion styles for lib/load-more.js
 *
 * Loaded globally via <link> в index.html — доступен всем модам Team Portal.
 * Ранее правила жили в history-tab.css → страдали моды где load-more используется
 * без параллельной загрузки истории (payments_control, documents_control).
 * Extracted in block 2106.2 task radar-os--604.
 */

/* ── LoadMore button ────── */

.load-more-btn {
  padding: 8px 24px;
  border: 1px solid var(--border, rgba(255, 255, 255, 0.15));
  border-radius: 6px;
  background: transparent;
  color: var(--fg, #e8edf5);
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  transition: border-color 0.12s, background 0.12s, opacity 0.12s;
}

.load-more-btn:hover:not(:disabled) {
  border-color: var(--accent, #3aa7e2);
  background: rgba(58, 167, 226, 0.06);
}

.load-more-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.load-more-btn--loading {
  opacity: 0.7;
}

/* ── payments_control footer container (Block 2106.1) ────── */

/* Резерв под кнопкой (Block 22010 задачи 604) — не в #p-table-wrap выше, а здесь.
   Кнопка стоит последней перед sticky «Итого», поэтому воздух нужен ПОД ней:
   иначе при прокрутке в конец кнопка подходит к бару вплотную и уходит под него.
   Одно правило закрывает обе верстки режима — у оператора контейнер
   .tab-panel#p-tab-payments, у сотрудника его нет вовсе (общий #content).
   60px = высота .payments-totals-bar (padding 11+11 + font-size 15 + border 2)
   с запасом. Меняются паддинги или шрифт бара — пересчитать здесь. */

#p-load-more {
  margin: 12px 0;
  padding-bottom: 60px;
  text-align: center;
}

/* Всё загружено → _renderLoadMore чистит контейнер (page.js: footer.innerHTML = '').
   Без сброса внизу списка осталась бы дыра в 84px: 60 padding + 24 margin. */

#p-load-more:empty {
  margin: 0;
  padding: 0;
}

/* ── payments_control table wrapper — scroll room под sticky totals bar (Block 2106.3) ────── */
/* 60px = высота .payments-totals-bar (padding 11+11 + font-size 15 + border 2) + запас. */
/* Без padding-bottom последняя строка таблицы прячется под sticky «Итого» при скролле в конец. */

#p-table-wrap {
  padding-bottom: 60px;
}

/*
 * field-rows.css — примитив Team Portal: карточка пар «подпись — значение».
 *
 * Цвета берутся переменными темы портала, своих нет: карточка обязана
 * читаться и в светлой, и в тёмной теме без второго набора правил.
 *
 * ⚠️ ИМЕНА ПЕРЕМЕННЫХ СВЕРЕНЫ С ТЕМОЙ, и это не формальность. Первая редакция
 * (блок 43040) писала `--t-text`, `--t-text-muted`, `--t-border` — переменных
 * с такими именами в `team.css` НЕТ НИ ОДНОЙ. Срабатывали запасные значения,
 * подобранные под светлую тему: значение поля красилось в `#111827`, почти
 * чёрный, на тёмном фоне `#0B1320`. Карточка была нечитаема, и выглядело это
 * не поломкой, а «так задумано».
 *
 * Настоящие имена — `--text`, `--text-2`, `--muted`, `--border`
 * (`team.css:11-13`, светлая тема `:60-65`). Запасных значений здесь нет
 * намеренно: опечатка в имени должна быть ВИДНА, а не подменяться цветом,
 * который случайно оказался похож на правильный.
 *
 * Исправлено блоком 45030 раунд 3 по замечанию «текст не виден».
 */

.field-rows {
  display:        flex;
  flex-direction: column;
  gap:            20px;
}

.field-rows--empty {
  padding:    24px 0;
  text-align: center;
  color:      var(--muted);
  font-size:  14px;
}

.field-group {
  display:        flex;
  flex-direction: column;
  gap:            2px;
}

.field-group__title {
  margin-bottom:  6px;
  padding-bottom: 6px;
  border-bottom:  1px solid var(--border);
  font-size:      12px;
  font-weight:    600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color:          var(--muted);
}

.field-row {
  display:               grid;
  grid-template-columns: minmax(120px, 38%) 1fr;
  gap:                   12px;
  padding:               7px 0;
  align-items:           start;
}

.field-row + .field-row {
  border-top: 1px solid var(--border);
}

.field-row__label {
  font-size:   13px;
  line-height: 1.4;
  color:       var(--muted);
}

.field-row__value {
  font-size:   14px;
  line-height: 1.4;
  color:       var(--text);
  word-break:  break-word;
}

/* Прочерк приглушён намеренно: незаполненное поле не должно спорить
   вниманием с заполненными. */
.field-row__value--empty {
  color: var(--muted);
}

/* Узкий экран: подпись над значением, сетка в одну колонку. */
@media (max-width: 560px) {
  .field-row {
    grid-template-columns: 1fr;
    gap:                   2px;
  }
}

/**
 * link-picker.css — styling для LinkPicker two-step primitive.
 *
 * Task: radar-os--593-leads-mode-launch, Block 3006.
 * Consumer: Slider «Связи» tab (Block 3008).
 * Class prefix: .lp-* (unique — no collision with .cp-* / .es-* / .fb-* / .t-*).
 */

.lp-container {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 80px;
}

/* ── Step 1: mode selection ─────────────────────────────────── */

.lp-mode-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.lp-mode-item {
  display: block;
  width: 100%;
  padding: 10px 14px;
  border: 1px solid var(--t-border, #2a2f3a);
  border-radius: 6px;
  background: var(--t-surface-2, #12151d);
  color: var(--t-text, #e6e8ec);
  font-size: 14px;
  text-align: left;
  cursor: pointer;
  transition: background 120ms, border-color 120ms;
}

.lp-mode-item:hover {
  background: var(--t-surface-3, #1a1e28);
  border-color: var(--t-accent, #5b8def);
}

.lp-mode-item:focus {
  outline: 2px solid var(--t-accent, #5b8def);
  outline-offset: 1px;
}

/* ── Step 2: item search ────────────────────────────────────── */

.lp-item-search {
  display: flex;
  flex-direction: column;
  gap: 6px;
  position: relative;
}

.lp-back-btn {
  align-self: flex-start;
  padding: 4px 10px;
  border: none;
  background: transparent;
  color: var(--t-accent, #5b8def);
  font-size: 13px;
  cursor: pointer;
}

.lp-back-btn:hover {
  text-decoration: underline;
}

.lp-input-wrap {
  position: relative;
}

.lp-input {
  width: 100%;
  padding: 8px 32px 8px 10px;
  border: 1px solid var(--t-border, #2a2f3a);
  border-radius: 6px;
  background: var(--t-surface-2, #12151d);
  color: var(--t-text, #e6e8ec);
  font-size: 14px;
  box-sizing: border-box;
}

.lp-clear-btn {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  border: none;
  background: transparent;
  color: var(--t-text-dim, #8a8f9a);
  font-size: 14px;
  cursor: pointer;
  padding: 4px 6px;
}

.lp-clear-btn[hidden] {
  display: none;
}

.lp-dropdown {
  max-height: 240px;
  overflow-y: auto;
  border: 1px solid var(--t-border, #2a2f3a);
  border-radius: 6px;
  background: var(--t-surface-2, #12151d);
}

.lp-dropdown[hidden] {
  display: none;
}

.lp-item-row {
  padding: 8px 12px;
  cursor: pointer;
  color: var(--t-text, #e6e8ec);
  font-size: 14px;
  border-bottom: 1px solid var(--t-border-soft, #1e2129);
}

.lp-item-row:last-child {
  border-bottom: none;
}

.lp-item-row:hover {
  background: var(--t-surface-3, #1a1e28);
}

.lp-empty {
  padding: 12px;
  color: var(--t-text-dim, #8a8f9a);
  font-size: 13px;
  text-align: center;
}

/*
 * status-badge.css — Team Portal UI primitive: variant-based dot + label badge.
 *
 * Companion to lib/status-badge.js (Block 1101 of task radar-os--455-docs-control-mode).
 *
 * Colors via CSS variables `--badge-{variant}-color` defined by caller
 * (mod styles.css or scoped scope). Unknown/undefined variant falls back to
 * `--badge-color` default (gray #6b7280) — graceful degradation.
 *
 * Loaded via <link> in team/index.html (after legacy lib CSS files).
 */

.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  white-space: nowrap;
}
.status-badge__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--badge-color, #6b7280);
}
.status-badge--success  { --badge-color: var(--badge-success-color, #22c55e); }
.status-badge--danger   { --badge-color: var(--badge-danger-color,  #ef4444); }
.status-badge--warning  { --badge-color: var(--badge-warning-color, #f4a300); }
.status-badge--info     { --badge-color: var(--badge-info-color,    #38bdf8); }
.status-badge--muted    { --badge-color: var(--badge-muted-color,   #9ca3af); }
.status-badge--accent   { --badge-color: var(--badge-accent-color,  #3b82f6); }
.status-badge--draft    { --badge-color: var(--badge-draft-color,   #f4a300); }
.status-badge--archived { --badge-color: var(--badge-archived-color, #6b7280); opacity: 0.65; }

/* ring-stat.css — стили примитива lib/ring-stat.js.
 *
 * ⚠️ Здесь НЕТ ни одного цвета данных. Цвет каждой дуги приходит атрибутом
 * `stroke` от вызывающего — он живёт в каталоге источников и приезжает с
 * бэкенда уже разрешённым (задача radar-os--713, блок 3020). Появится тут
 * правило вида `.rstat__arc--meetings` — значит требование масштабирования
 * нарушено: источники окажутся перечислены в стилях.
 *
 * Цвета есть только у дорожки и у текста в середине, и оба взяты
 * переменными портала.
 *
 * Задача radar-os--713, волна 3, блок 3030.
 */

.rstat {
    position: relative;
    display: inline-grid;
    place-items: center;
    flex: none;
    /* Без этого inline-grid встаёт на базовую линию строки, и коробка выходит
     * на три пикселя выше самого круга — в ряду с текстом кольцо оказывается
     * приподнятым. Замерено в браузере: 76×79 вместо 76×76. Блок 3030. */
    vertical-align: top;
}

.rstat svg {
    display: block;
}

/* Дорожка — то, что видно, когда доля меньше целого или данных нет вовсе. */
.rstat__track {
    stroke: var(--overlay-subtle, rgba(255, 255, 255, .06));
}

.rstat__arc {
    /* Переход нужен, если вызывающий перерисовывает круг с новыми числами:
     * без него смена доли выглядит подёргиванием. Уважает системную
     * настройку «меньше движения» — см. правило ниже. */
    transition: stroke-dasharray .45s cubic-bezier(.4, 0, .2, 1),
                stroke-dashoffset .45s cubic-bezier(.4, 0, .2, 1);
}

@media (prefers-reduced-motion: reduce) {
    .rstat__arc {
        transition: none;
    }
}

/* Середина круга: две готовые строки от вызывающего. Абсолютное
 * позиционирование, а не <text> внутри SVG — так текст остаётся обычным
 * текстом страницы: его можно выделить, найти поиском и увеличить
 * настройками браузера. */
.rstat__center {
    position: absolute;
    inset: 0;
    display: grid;
    place-content: center;
    text-align: center;
    pointer-events: none;
    line-height: 1.15;
}

.rstat__value {
    font-weight: 700;
    font-size: 15px;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
}

.rstat__caption {
    color: var(--muted);
    font-size: 10.5px;
    margin-top: 2px;
}

/* split-bar.css — стили примитива lib/split-bar.js.
 *
 * ⚠️ Здесь НЕТ ни одного цвета данных: цвет каждого сегмента приходит от
 * вызывающего. Появится правило вида `.sbar__seg--meetings` — значит
 * требование масштабирования нарушено, источники перечислены в стилях.
 *
 * Свои цвета есть только у дорожки, у текста и у рамки перегруза.
 *
 * Задача radar-os--713, волна 3, блок 3040.
 */

.sbar {
    display: flex;
    width: 100%;
    overflow: hidden;
    border: 1px solid var(--line);
    border-radius: 9px;
    background: var(--panel-2);
}

/* ⚠️ Скругление — только у ВНЕШНИХ краёв полосы, и делается оно обрезкой на
 * контейнере (`overflow: hidden`), а не скруглением сегментов. Скругли мы
 * каждый сегмент — между соседними появились бы щели, и полоса перестала бы
 * читаться как одно целое. Тот же класс находки, что у ring-stat: там форма
 * концов дуги тоже зависит от того, сегмент один или их несколько. */

.sbar__seg {
    display: grid;
    place-items: center;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
}

.sbar__text {
    font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    padding: 0 6px;
    /* Текст поверх произвольного цвета сегмента. Тень даёт читаемость и на
     * светлой заливке, и на тёмной — цвет приходит снаружи, и каким он будет,
     * примитив не знает. */
    color: #fff;
    text-shadow: 0 1px 2px rgba(0, 0, 0, .45);
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Перегруз: сумма долей превысила заданное целое. Помечается рамкой, потому
 * что это свойство полосы целиком, а не какой-то одной её части. */
.sbar--over {
    border-color: var(--danger);
    box-shadow: 0 0 0 1px var(--danger) inset;
}

/* Целого нет или долей нет — пустая дорожка. Это «данных нет», а не
 * «всё свободно», и выглядеть должно иначе, чем полностью свободный день. */
.sbar--empty {
    background: var(--panel-2);
}

/* bar-rows.css — стили примитива lib/bar-rows.js.
 *
 * ⚠️ Ни одного цвета данных: цвет полосы приходит от вызывающего.
 *
 * Задача radar-os--713, волна 3, блок 3050.
 */

.brows {
    display: grid;
    gap: 8px;
}

/* Три колонки фиксированной формы. Без них строки не выравниваются между
 * собой, и глаз не может сравнить длины — а сравнение и есть смысл
 * гистограммы. */
.brow {
    display: grid;
    grid-template-columns: minmax(0, 96px) 1fr minmax(0, 54px);
    gap: 12px;
    align-items: center;
    font-size: 12.5px;
}

.brow__label {
    color: var(--muted);
    /* Обрезка, а не перенос: перенос ломает выравнивание строк по высоте,
     * ради которого сетка и заведена. */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.brow__track {
    height: 9px;
    border-radius: 5px;
    background: var(--overlay-subtle, rgba(255, 255, 255, .05));
    overflow: hidden;
}

.brow__fill {
    display: block;
    height: 100%;
    border-radius: 5px;
}

@media (prefers-reduced-motion: no-preference) {
    .brow__fill {
        transition: width .4s cubic-bezier(.4, 0, .2, 1);
    }
}

.brow__value {
    text-align: right;
    color: var(--text-2);
    /* Без табличных цифр «403» и «40» смещаются друг относительно друга,
     * и колонка выглядит рваной. */
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* gauge-dial.css — стили примитива lib/gauge-dial.js.
 *
 * ⚠️ Тон задаётся ОДНОЙ переменной `--gdial-tone`, которую читают дуга,
 * стрелка, втулка и число в середине. Три отдельных набора правил означали
 * бы, что добавление четвёртого тона трогает три места.
 *
 * Порог, при котором тон меняется, здесь НЕ живёт: его выбирает вызывающий.
 * Порог — свойство задачи, а не прибора.
 *
 * Задача radar-os--713, волна 3, блок 3060.
 */

.gdial {
    position: relative;
    display: inline-block;
    vertical-align: top;
    --gdial-tone: var(--primary);
}

.gdial--warning { --gdial-tone: var(--warning); }
.gdial--danger  { --gdial-tone: var(--danger); }

/* Шкалы нет (выходной): дуги и стрелки не рисуется вовсе, дорожка гасится —
 * иначе пустая шкала читается как «день есть, он пуст». */
.gdial--noscale { --gdial-tone: var(--muted); }

.gdial svg {
    display: block;
    width: 100%;
    height: auto;
}

.gdial__track {
    stroke: var(--overlay-subtle, rgba(255, 255, 255, .06));
}

.gdial__arc {
    stroke: var(--gdial-tone);
}

.gdial__needle,
.gdial__hub {
    fill: var(--gdial-tone);
}

.gdial__hub {
    fill: var(--bg);
    stroke: var(--gdial-tone);
}

.gdial__tick {
    stroke: var(--overlay-medium, rgba(255, 255, 255, .2));
}

.gdial__ticklabel {
    fill: var(--muted);
    font-size: 10.5px;
    font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}

.gdial__footnote {
    fill: var(--warning);
    font-size: 11px;
    font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
}

/* Середина: две готовые строки от вызывающего. Обычным текстом, а не <text>
 * внутри SVG — так его можно выделить, найти поиском и увеличить настройками
 * браузера. Тот же приём, что у ring-stat. */
.gdial__center {
    position: absolute;
    left: 0;
    right: 0;
    /* ПОД втулкой, а не в середине дуги. Сектор хода стрелки — весь верхний
     * полукруг, и при любом положении числа внутри найдётся процент, при
     * котором стрелка его перечеркнёт (замер поймал это на 27%).
     *
     * ⚠️ Запас взят с учётом того, что при перегрузе стрелка НЫРЯЕТ НИЖЕ оси
     * втулки: 112% это 201.6 градуса, то есть на 21 градус за горизонталь.
     * Пересечение коробок при 118% замерено программно и доведено до нуля,
     * а не до «на глаз не видно». Блок 3060. */
    top: 74%;
    text-align: center;
    pointer-events: none;
}

.gdial__value {
    font-size: 30px;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -.03em;
    font-variant-numeric: tabular-nums;
    font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    color: var(--gdial-tone);
}

.gdial__caption {
    color: var(--muted);
    font-size: 11px;
    margin-top: 7px;
    letter-spacing: .04em;
    text-transform: uppercase;
}

/* Стрелка без плавности выглядит скачущей при переключении состояний дня. */
@media (prefers-reduced-motion: no-preference) {
    .gdial__needle,
    .gdial__arc {
        transition: all .5s cubic-bezier(.4, 0, .2, 1);
    }
}

/*
 * status-transitions-panel.css — раскладка карточки «Переходы статусов».
 *
 * Задача radar-os--727, блок 3010. Только раскладка и чипы исполнителей:
 * пилюли, тумблер вида, таблица и переключатель в строке приносят свой вид
 * из filter-bar.css, view-toggle.css, table и settings-toggle.css — здесь
 * их не переопределяем, иначе панель разъедется с остальным порталом.
 *
 * Цвета — только через переменные темы из index.html, чтобы карточка одинаково
 * жила в светлой и тёмной.
 */

.stp__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}

.stp__pills { flex: 1 1 auto; min-width: 0; }
.stp__view  { flex: 0 0 auto; }

/* ── Чипы исполнителей ─────────────────────────────────────── */

.stp-perf {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
}

.stp-chip {
    padding: 3px 10px;
    font-size: 12px;
    line-height: 18px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg);
    color: var(--muted);
    cursor: pointer;
    transition: border-color .15s, color .15s, background .15s;
}

.stp-chip:hover { border-color: var(--accent, #3b82f6); }

.stp-chip.is-on {
    border-color: var(--accent, #3b82f6);
    color: var(--accent, #3b82f6);
    font-weight: 600;
}

.stp-any {
    font-size: 12px;
    color: var(--muted);
    font-style: italic;
}

/* ── Переключатель страниц ─────────────────────────────────── */

.stp__pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    margin-top: 14px;
}

.stp__pager:empty { margin: 0; }

.stp-page {
    padding: 6px 14px;
    font-size: 13px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg);
    color: var(--fg, inherit);
    cursor: pointer;
}

.stp-page:disabled { opacity: .45; cursor: default; }
.stp-page:not(:disabled):hover { border-color: var(--accent, #3b82f6); }

.stp-page-info {
    font-size: 12px;
    color: var(--muted);
    white-space: nowrap;
}

/*
 * status-notify-panel.css — раскладка карточки «Уведомления автору».
 *
 * Задача radar-os--730, блок 5110. Только раскладка: пилюли, тумблер вида,
 * таблица и переключатель в строке приносят свой вид из filter-bar.css,
 * view-toggle.css, table и settings-toggle.css — здесь их не переопределяем,
 * иначе панель разъедется с остальным порталом.
 *
 * Один в один с соседней карточкой «Переходы статусов» по требованию владельца
 * (2026-09-03): те же отступы, тот же переключатель страниц. Чипы исполнителей
 * из донора не переносятся — в решётке уведомлений исполнителей нет.
 *
 * Цвета — только через переменные темы из index.html, чтобы карточка одинаково
 * жила в светлой и тёмной.
 */

.snp__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}

.snp__pills { flex: 1 1 auto; min-width: 0; }
.snp__view  { flex: 0 0 auto; }

/* ── Переключатель страниц ─────────────────────────────────── */

.snp__pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    margin-top: 14px;
}

.snp__pager:empty { margin: 0; }

.snp-page {
    padding: 6px 14px;
    font-size: 13px;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--bg);
    color: var(--fg, inherit);
    cursor: pointer;
}

.snp-page:disabled { opacity: .45; cursor: default; }
.snp-page:not(:disabled):hover { border-color: var(--accent, #3b82f6); }

.snp-page-info {
    font-size: 12px;
    color: var(--muted);
    white-space: nowrap;
}

/*
 * status-pair-filter.css — раскладка фильтра пары статусов.
 *
 * Задача radar-os--730, блок 5910. Только раскладка двух рядов: сами пилюли, подписи
 * групп и активное состояние приходят из `.filters` / `.filter-group` / `.filter-label`
 * / `.filter-pills` / `.pill` в team.css — здесь их не переопределяем, иначе фильтр
 * разъедется с остальным порталом.
 *
 * Ряды идут друг под другом, а не в строку: подписи «Из статуса» и «В статус» должны
 * читаться как пара, а при одиннадцати статусах пилюли всё равно переносятся.
 */

.spf .filters {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.spf .filter-group {
    display: flex;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
}

/* Подписи одной ширины — ряды выстраиваются по левому краю пилюль. */
.spf .filter-label {
    flex: 0 0 auto;
    min-width: 92px;
}

.spf .filter-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    min-width: 0;
}

/* connect-panel.css — Team Portal lib primitive: экран подключения вендора.

   Панель рисуется из блока `connect` в манифесте вендора: форма по полям либо
   инструкция с кнопкой на страницу провайдера.
   Схема: radar/arch/concepts/integration-bus-connect-schema.md
   Задача 707, блок 25050.

   До этого блока разметка жила инлайновыми атрибутами внутри девяти функций
   _render{Vendor}ConnectionPane. Пока стили были строками в JS, «панель одна на
   всех» держалась только до первого вендора с другой кнопкой. */

.connect-panel__head {
  padding: 20px;
}

.connect-panel__actions {
  display: flex;
  gap: 8px;
}

.connect-panel__status,
.connect-panel__action {
  flex: 1;
  padding: 10px 8px;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 500;
}

/* Статус — не кнопка: он показывает состояние и на нажатие не отвечает. */
.connect-panel__status {
  border: 1px solid;
  cursor: default;
  pointer-events: none;
}

.connect-panel__status--on {
  background: rgba(74, 222, 128, 0.1);
  color: #4ade80;
  border-color: rgba(74, 222, 128, 0.3);
}

.connect-panel__status--off {
  background: rgba(248, 113, 113, 0.1);
  color: #f87171;
  border-color: rgba(248, 113, 113, 0.3);
}

.connect-panel__action {
  border: none;
  cursor: pointer;
  transition: opacity 0.15s;
}

.connect-panel__action:hover {
  opacity: 0.85;
}

.connect-panel__action--primary {
  background: #3AA7E2;
  color: #fff;
}

.connect-panel__action--danger {
  background: rgba(239, 68, 68, 0.12);
  color: #f87171;
  border: 1px solid rgba(239, 68, 68, 0.3);
}

.connect-panel__since {
  margin: 12px 0 0;
  font-size: 13px;
  color: var(--text-2, #8b93a8);
}

.connect-panel__notice {
  padding: 0 20px 12px;
}

.connect-panel__request {
  display: flex;
  gap: 8px;
  align-items: stretch;
  margin-top: 10px;
}

.connect-panel__request input {
  flex: 1;
  padding: 8px 10px;
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.15);
  background: rgba(0, 0, 0, 0.2);
  color: var(--text-1, #e8eaf0);
  font-size: 14px;
  box-sizing: border-box;
}

.connect-panel__request button {
  padding: 8px 16px;
  border-radius: 6px;
  border: none;
  background: #3AA7E2;
  color: #fff;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
}

.connect-panel__request-status {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--text-2, #8b93a8);
}

.connect-panel__request-status--ok {
  color: #4ade80;
}

.connect-panel__guide {
  padding: 0 20px 24px;
}

.connect-panel__rule {
  height: 1px;
  background: rgba(255, 255, 255, 0.07);
  margin-bottom: 16px;
}

.connect-panel__guide-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-2, #8b93a8);
  margin: 0 0 14px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.connect-panel__step {
  display: flex;
  gap: 10px;
  margin-bottom: 12px;
  align-items: flex-start;
}

.connect-panel__step-num {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #3AA7E2;
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  display: flex;
  align-items: center;
  justify-content: center;
}

.connect-panel__step-text {
  color: var(--text-2, #8b93a8);
  font-size: 14px;
  line-height: 1.5;
}

/* Плашка с названием кнопки у провайдера — Continue, Allow, Authorize.
   Своё оформление, потому что это чужое слово на чужом языке посреди
   русской фразы, и человек должен узнать его на экране провайдера. */
.connect-panel__badge {
  display: inline-block;
  padding: 2px 10px;
  border-radius: 6px;
  background: #1a73e8;
  color: #fff;
  font-size: 12px;
  font-weight: 500;
  vertical-align: middle;
  margin: 0 2px;
}

.connect-panel__console {
  padding: 0 20px 20px;
  font-size: 13px;
  color: var(--text-2, #8b93a8);
}

.connect-panel__console a {
  color: #3AA7E2;
}

.connect-panel__loading {
  padding: 32px 20px;
  text-align: center;
  color: var(--text-2, #8b93a8);
  font-size: 14px;
}

/**
 * heatmap.css — companion styles for radar/team/lib/heatmap.js primitive.
 *
 * Theme-adaptive palette using CSS custom properties + фирменные цвета
 * radar-os (primary #3AA7E2 blue scale, hover #6EC1FF).
 * Row labels use `currentColor` — inherits от parent text color (works
 * автоматом на dark и light themes без override).
 * Cell b0 (empty) — subtle rgba independent of theme + prefers-color-scheme
 * light adaptation.
 *
 * Consumer может override любую variable через `.heatmap-grid { --var: X; }`.
 *
 * Block 3006 initial + Block 3013 R5 theme refactor (task radar-os--631).
 */

.heatmap-grid {
  /* Theme-adaptive CSS variables (default dark theme, radar-os brand). */
  --heatmap-bg:              transparent;
  --heatmap-corner:          transparent;
  --heatmap-row-label:       currentColor;
  --heatmap-row-sublabel:    currentColor;
  --heatmap-col-header:      currentColor;
  --heatmap-hover-outline:   #6EC1FF;
  --heatmap-row-hover-bg:    rgba(58, 167, 226, 0.08);
  --heatmap-cell-b0:         rgba(255, 255, 255, 0.04);
  --heatmap-cell-b1:         rgba(58, 167, 226, 0.20);
  --heatmap-cell-b2:         rgba(58, 167, 226, 0.35);
  --heatmap-cell-b3:         rgba(58, 167, 226, 0.50);
  --heatmap-cell-b4:         rgba(58, 167, 226, 0.65);
  --heatmap-cell-b5:         rgba(58, 167, 226, 0.80);
  --heatmap-cell-b6:         rgba(58, 167, 226, 0.92);
  --heatmap-cell-b7:         #3AA7E2;

  display: grid;
  gap: 3px;
  padding: 12px;
  align-items: center;
  overflow-x: auto;
  background: var(--heatmap-bg);
  border-radius: 8px;
}

/* Light theme adaptation — scoped through site's data-theme toggle (не OS preference).
 * Enhanced cell values для sufficient contrast on white bg + grid backdrop trick. */
html[data-theme="light"] .heatmap-grid {
  --heatmap-bg:              var(--line);         /* gap → softer grid lines (Round 6) */
  --heatmap-cell-b0:         var(--bg);           /* empty cells = page bg (white after Round 4), gap = line */
  --heatmap-cell-b1:         rgba(58, 167, 226, 0.30);
  --heatmap-cell-b2:         rgba(58, 167, 226, 0.45);
  --heatmap-cell-b3:         rgba(58, 167, 226, 0.60);
  --heatmap-cell-b4:         rgba(58, 167, 226, 0.75);
  --heatmap-cell-b5:         rgba(58, 167, 226, 0.85);
  --heatmap-cell-b6:         rgba(58, 167, 226, 0.95);
  --heatmap-cell-b7:         #3AA7E2;
}

.heatmap-corner {
  background: var(--heatmap-corner);
}

.heatmap-col-header {
  font-size: 10px;
  color: var(--heatmap-col-header);
  opacity: 0.55;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  padding-bottom: 4px;
  min-width: 14px;
}

.heatmap-row-label {
  font-size: 13px;
  color: var(--heatmap-row-label);
  cursor: pointer;
  padding-right: 8px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: opacity 0.15s ease;
}

/* Block 3020 R6: full-row hover через display:contents wrapper.
   `:hover` на wrapper подсвечивает label + все cells той же row. */
.heatmap-row:hover .heatmap-row-label,
.heatmap-row:hover .heatmap-cell {
  background: var(--heatmap-row-hover-bg);
}

.heatmap-row-name {
  display: block;
  font-weight: 500;
}

.heatmap-row-sublabel {
  display: block;
  font-size: 11px;
  color: var(--heatmap-row-sublabel);
  opacity: 0.6;
  margin-top: 2px;
}

.heatmap-cell {
  width: 100%;
  height: 22px;
  border-radius: 2px;
  cursor: pointer;
  transition: outline 0.1s ease;
}

.heatmap-cell:hover {
  outline: 1px solid var(--heatmap-hover-outline);
  outline-offset: 1px;
}

/* Brightness scale — radar-os primary blue (var-driven, override-friendly). */
.heatmap-cell--b0 { background: var(--heatmap-cell-b0); cursor: default; }
.heatmap-cell--b0:hover { outline: none; }

.heatmap-cell--b1 { background: var(--heatmap-cell-b1); }
.heatmap-cell--b2 { background: var(--heatmap-cell-b2); }
.heatmap-cell--b3 { background: var(--heatmap-cell-b3); }
.heatmap-cell--b4 { background: var(--heatmap-cell-b4); }
.heatmap-cell--b5 { background: var(--heatmap-cell-b5); }
.heatmap-cell--b6 { background: var(--heatmap-cell-b6); }
.heatmap-cell--b7 { background: var(--heatmap-cell-b7); }

/* Empty state. */
.heatmap-empty {
  padding: 32px;
  text-align: center;
  color: currentColor;
  opacity: 0.6;
  font-style: italic;
}

/* Responsive — allow horizontal scroll on narrow viewports. */
@media (max-width: 900px) {
  .heatmap-grid {
    padding: 8px;
    gap: 2px;
  }
  .heatmap-col-header {
    font-size: 9px;
  }
  .heatmap-row-label {
    font-size: 12px;
    padding-right: 4px;
  }
}

/*
 * composition-pane.css — Team Portal UI primitive: list of items with per-item
 * fields, optional drag&drop reorder, add/remove, readOnly preview mode.
 *
 * Companion to lib/composition-pane.js (Block 1102 of task radar-os--455-docs-control-mode).
 *
 * Generic class names. Mode-specific overrides via .composition-pane scope или
 * wrapping container.
 *
 * Loaded via <link> in team/index.html (after legacy lib CSS files).
 */

.composition-pane__list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0;
  margin: 0;
}
.composition-pane__block {
  display: grid;
  grid-template-columns: 22px 1fr 22px;
  gap: 8px;
  align-items: start;
  padding: 12px;
  background: var(--surface-panel, rgba(255, 255, 255, 0.04));
  border: 1px solid var(--sidebar-pill-border, rgba(255, 255, 255, 0.10));
  border-radius: 8px;
}
.composition-pane__handle {
  cursor: grab;
  user-select: none;
  font-size: 18px;
  line-height: 1;
  color: var(--text-soft, #93a4c0);
  padding-top: 2px;
  text-align: center;
}
.composition-pane__handle:active { cursor: grabbing; }
.composition-pane__body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}
.composition-pane__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.composition-pane__row--full { grid-template-columns: 1fr; }
.composition-pane__block .field-textarea { min-height: 60px; resize: vertical; }
.composition-pane__block select.field-text { padding-right: 32px; }
.composition-pane__remove {
  cursor: pointer;
  background: transparent;
  border: none;
  color: var(--text-soft, #93a4c0);
  font-size: 18px;
  line-height: 1;
  padding: 0;
}
.composition-pane__remove:hover { color: #ef4444; }
.composition-pane__block--dragging { opacity: 0.4; }
.composition-pane__block--drag-over { box-shadow: 0 0 0 2px #3aa7e2 inset; }
.composition-pane__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}
.composition-pane__doc-name {
  font-weight: 600;
  color: #e5e7eb;
  font-size: 14px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.composition-pane__add-btn {
  -webkit-appearance: none;
  appearance: none;
  margin-top: 8px;
  width: 100%;
  padding: 10px 14px;
  background: transparent;
  border: 1px dashed rgba(255, 255, 255, 0.35);
  border-radius: 8px;
  color: var(--text-soft, #93a4c0);
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
}
.composition-pane__add-btn:hover { border-color: #3aa7e2; color: #ffffff; }
.composition-pane__empty { color: var(--text-soft, #93a4c0); font-size: 13px; padding: 12px 0; }
/* readOnly modifier — hide handle/remove, full-width block */
.composition-pane--readonly .composition-pane__block { grid-template-columns: 1fr; }
.composition-pane--readonly .composition-pane__handle,
.composition-pane--readonly .composition-pane__remove { display: none; }

/* Block 1501.2.1 — opt-in per-item extension slots (blockSlots config).
   afterFields: caller-rendered content inside body after fields rows.
   actions: caller-rendered footer (e.g. approve/reject buttons). */
.composition-pane__after-fields {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.composition-pane__actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--sidebar-pill-border, rgba(255, 255, 255, 0.10));
}

/* Block 1503 — opt-in footer slot rendered AFTER actions (last element in block).
   Used by documents_control to surface rejection reason + history below the
   member workspace (fields + files + buttons). */
.composition-pane__footer {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 8px;
}

/* view-toggle.css — Team Portal client UI primitive: compact button-group toggle.
 *
 * BEM-style classes:
 *   .view-toggle              — inline-flex pill container
 *   .view-toggle__btn         — individual mode button (default state)
 *   .view-toggle__btn--active — currently selected mode (accent background)
 *
 * Dark theme compatible via existing CSS vars (--accent, --bg-2, --text-2, --line-2, --text).
 *
 * Block 1203 of task radar-os--455-docs-control-mode.
 */

.view-toggle {
  display: inline-flex;
  border: 1px solid var(--line-2, rgba(255, 255, 255, 0.10));
  border-radius: 8px;
  overflow: hidden;
}

.view-toggle__btn {
  padding: 6px 12px;
  background: transparent;
  border: none;
  color: var(--text-2, #93a4c0);
  cursor: pointer;
  font-family: inherit;
  font-size: 13px;
  line-height: 1.4;
  transition: background-color 0.12s ease, color 0.12s ease;
}

.view-toggle__btn:hover {
  background: var(--bg-2, rgba(255, 255, 255, 0.04));
  color: var(--text, #e5e7eb);
}

.view-toggle__btn--active,
.view-toggle__btn--active:hover {
  background: var(--accent, #6366f1);
  color: #ffffff;
}

/**
 * settings-toggle.css — Team Portal lib primitive: iPhone-style boolean toggle switch.
 *
 * Migrated from radar/team/team.css:2475-2494 (block 3001 of task radar-os--476).
 * Block 5006 (task radar-os--547): saffron variant class for accent semantics
 * (pin/star/favorite indicators) vs default green (settings on/off).
 *
 * Used in: owner_questions_filter (settings tab), notes (Slider is_pinned +
 * card grid instant pin toggle — saffron variant).
 *
 * CSS variables: --line-2 (track background, dark theme line color).
 * Default active color hardcoded #4caf50 (green) — Apple-style settings UX.
 *
 * Public markup contract:
 *   <label class="settings-toggle">                            (default green)
 *   <label class="settings-toggle settings-toggle--saffron">   (saffron accent)
 *     <input type="checkbox" />
 *     <span class="settings-toggle__track"></span>
 *   </label>
 *
 * Variants:
 *   .settings-toggle--saffron — brand saffron #F4A300 (Radar OS pin accent).
 *   Add more here when semantic accents needed (blue/red/etc).
 */

.settings-toggle { display:inline-flex; align-items:center; cursor:pointer; }
.settings-toggle input { position:absolute; opacity:0; width:0; height:0; }
.settings-toggle__track {
  position:relative; display:inline-block;
  width:40px; height:22px;
  background:var(--line-2, #3a3a3a);
  border-radius:999px;
  transition:background .2s;
  flex-shrink:0;
}
.settings-toggle__track::after {
  content:''; position:absolute;
  top:3px; left:3px;
  width:16px; height:16px;
  border-radius:50%;
  background:#fff;
  transition:transform .2s;
}
.settings-toggle input:checked + .settings-toggle__track { background:#4caf50; }
.settings-toggle input:checked + .settings-toggle__track::after { transform:translateX(18px); }

/* Saffron variant — brand accent для pin/star/favorite semantics (block 5006). */
.settings-toggle--saffron input:checked + .settings-toggle__track { background:#F4A300; }

/* notice-box.css — Team Portal lib primitive: informational callout / notice banner.
   3 tones: info (blue) / warning (amber) / danger (red).
   Loaded via <link> в radar/team/index.html.
   Block 3090 (task radar-os--510-crew-mode). */

.notice-box {
  padding: 10px 12px;
  border-left: 3px solid transparent;
  border-radius: 4px;
  color: #cbd6e8;
  font-size: 13px;
  line-height: 1.45;
}

.notice-box--info {
  background: rgba(58, 167, 226, 0.08);
  border-left-color: #3AA7E2;
}

.notice-box--warning {
  background: rgba(244, 163, 0, 0.10);
  border-left-color: #F4A300;
}

.notice-box--danger {
  background: rgba(220, 74, 74, 0.10);
  border-left-color: #DC4A4A;
}

.notice-box b {
  color: #e8edf5;
}

.notice-box a {
  color: inherit;
  text-decoration: underline;
}

/* settings-row.css — Team Portal lib primitive: settings list row.
   Flex row layout: title + subtitle слева, control slot справа.
   Loaded via <link> в radar/team/index.html.
   Block 3090 (task radar-os--510-crew-mode). */

.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
  background: rgba(255, 255, 255, 0.03);
  border-radius: 6px;
}

.settings-row__meta {
  flex: 1;
  min-width: 0;
}

.settings-row__title {
  color: #e8edf5;
  font-size: 14px;
  font-weight: 500;
  line-height: 1.3;
}

.settings-row__subtitle {
  color: #6c7789;
  font-size: 11px;
  font-family: 'SF Mono', Menlo, Consolas, monospace;
  margin-top: 2px;
}

.settings-row__control {
  flex-shrink: 0;
}

/* Несколько контролов в одну строку — SettingsRow.render({inline: true}).
   Задача radar-os--792, блок 3016: TimePicker и тумблер задания стояли столбиком. */
.settings-row__control--inline {
  display: flex;
  align-items: center;
  gap: 12px;
}

/**
 * notes-card.css — lib primitive: card grid layout для коротких заметок.
 *
 * Extracted from monolith team.css per memory `feedback_no_monolith_css` —
 * каждый visual primitive = свой lib/*.css файл.
 *
 * Task: radar-os--547-notes-mode-unified, block 3050 (⭐ lib-first anchor per
 * CADENCE_HEURISTICS v1.0.2 §5 Q6). Producer of `.notes-grid` + `.note-card`
 * classes consumed by block 3055 render.
 *
 * Reference pattern: training `.prog-grid` + `.prog-card` (radar/team/team.css)
 * — но здесь extracted в lib/ вместо monolith, готово к future reuse
 * (courses / kb-cards / short-text modes).
 *
 * Loaded via radar/team/index.html <link rel="stylesheet"> (block 5004 fix,
 * task radar-os--547 audit-doc hole #3). NOT loaded via manifest.deps.esm —
 * mode_loader._validateDeps (radar/team/src/mode_loader.js:111) requires each
 * esm entry to return content-type=application/javascript, CSS files return
 * text/css and fail validation → mode init skipped → error renderer.
 * All lib CSS primitives follow this pattern (sibling <link> lines in index.html).
 *
 * Structure:
 *   .notes-grid                       — CSS Grid container, responsive 4→3→1 cols
 *   .note-card                        — single note card, badge/text/entity-sub/footer layout
 *   .note-card__badge                 — entity_type label top-left (Контакт/Встреча/Задача)
 *   .note-card__badge--contact        — color variant by entity_type (contact = blue)
 *   .note-card__badge--meeting        — meeting = purple
 *   .note-card__badge--task           — task = green
 *   .note-card__badge--offer          — offer = orange
 *   .note-card__text                  — main body, 3-line clamp
 *   .note-card__entity-sub            — «Клиент Иван» / «Встреча 2026-07-11» attach preview
 *   .note-card__footer                — bottom row: pin icon + relative time
 *   .note-card__pin                   — 📌 icon (visible when is_pinned=1)
 *   .note-card__time                  — «5 мин назад» / «12 июля» relative datetime
 *   .note-card--pinned                — modifier: subtle top border accent когда pinned
 */

/* ============================================================
 * Grid container — responsive breakpoints
 * ============================================================ */

.notes-grid {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  padding: 16px 0;
}

/* Tablet: 3 cols cap */
@media (max-width: 1200px) {
  .notes-grid {
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  }
}

/* Mobile: 1 col */
@media (max-width: 640px) {
  .notes-grid {
    grid-template-columns: 1fr;
    gap: 12px;
    padding: 12px 0;
  }
}

/* ============================================================
 * Card container
 * ============================================================ */

.note-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px 16px;
  background: var(--panel-bg, #0d1828);
  border: 1px solid var(--panel-border, #1a2942);
  border-radius: 10px;
  cursor: pointer;
  transition: border-color 0.15s ease, transform 0.1s ease;
  min-height: 120px;
}

.note-card:hover {
  border-color: var(--accent, #3aa7e2);
  transform: translateY(-1px);
}

.note-card--pinned {
  border-top: 2px solid var(--saffron, #F4A300);
}

/* ============================================================
 * Badge — entity_type tag top-left
 * ============================================================ */

.note-card__badge {
  align-self: flex-start;
  padding: 2px 10px;
  font-size: 11px;
  font-weight: 500;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  border-radius: 999px;
  color: var(--text-secondary, #8a9ab5);
  background: rgba(138, 154, 181, 0.12);
}

.note-card__badge--contact {
  color: #7cc2ff;
  background: rgba(124, 194, 255, 0.14);
}

.note-card__badge--meeting {
  color: #b19cff;
  background: rgba(177, 156, 255, 0.14);
}

.note-card__badge--task {
  color: #7ae0a3;
  background: rgba(122, 224, 163, 0.14);
}

.note-card__badge--offer {
  color: #ffb27a;
  background: rgba(255, 178, 122, 0.14);
}

/* ============================================================
 * Text body — 3 line clamp
 * ============================================================ */

.note-card__text {
  font-size: 14px;
  line-height: 1.5;
  color: var(--text-primary, #e8edf5);
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-word;
}

/* ============================================================
 * Entity subtitle — «прикреплено к»
 * ============================================================ */

.note-card__entity-sub {
  font-size: 12px;
  color: var(--text-secondary, #8a9ab5);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ============================================================
 * Footer — pin icon + relative time
 * ============================================================ */

.note-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: auto;
  padding-top: 8px;
  border-top: 1px solid rgba(138, 154, 181, 0.1);
}

.note-card__pin {
  font-size: 13px;
  line-height: 1;
  opacity: 0.85;
}

.note-card__pin--hidden {
  visibility: hidden;
}

.note-card__time {
  font-size: 11px;
  color: var(--text-secondary, #8a9ab5);
}

/* ============================================================
 * Empty state (grid contains только empty placeholder)
 * ============================================================ */

.notes-grid--empty {
  display: block;
  padding: 32px 16px;
  text-align: center;
  color: var(--text-secondary, #8a9ab5);
  font-size: 14px;
}

/* vendor-card — shared card layout для vendor listings.
 *
 * Extracted 2026-08-12 (task 671 block 560) из modes/integrations/styles.css
 * для reuse в mode integrations panel (Settings tab режимов) + integrations mode
 * (каталог vendor'ов в Team Portal).
 *
 * Contract: .integrations-grid + .service-card (+ __body / __name / __desc /
 * __footer / __type / __status modifiers). Filter tabs через
 * `.integrations-grid[data-filter="X"]` — CSS hides non-matching cards.
 *
 * Consumers:
 *   - radar/team/src/modes/integrations/page.js (каталог)
 *   - radar/team/src/lib/mode-integrations-panel.js (mode Settings panel)
 */

.integrations-loading {
  padding: 2rem;
  text-align: center;
  color: var(--muted);
  font-size: 0.95rem;
}

.integrations-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  grid-auto-rows: 1fr;
  gap: 1rem;
  margin-top: 1rem;
}

/* Старый способ фильтрации — через grid[data-filter], по правилу на значение.
 * Оставлен для панели интеграций в карточке сотрудника
 * (radar/team/src/lib/mode-integrations-panel.js) — она на нём живёт.
 * Удалять нельзя: у панели свои вкладки и свой набор значений.
 *
 * Каталог интеграций с блока 8090 задачи 683 на него больше не опирается —
 * перечисление значений в стилях означало, что новая вкладка без новой строки
 * здесь молча ничего не показывает. Каталог скрывает карточки классом ниже. */
.integrations-grid[data-filter="ai"] .service-card:not([data-type="ai"]) { display: none; }
.integrations-grid[data-filter="crm"] .service-card:not([data-type="crm"]) { display: none; }
.integrations-grid[data-filter="communications"] .service-card:not([data-type="communications"]) { display: none; }
.integrations-grid[data-filter="other"] .service-card:not([data-type="other"]) { display: none; }

/* Блок 8090: один общий признак вместо перечисления. Новая категория работает
 * без правки стилей — это и было целью. */
.service-card.is-hidden { display: none; }

.service-card {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1.25rem;
  background: var(--panel);
  border: 1px solid var(--line-2);
  border-radius: 12px;
  cursor: pointer;
  transition: transform 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.service-card:hover {
  border-color: var(--overlay-strong);
  background: var(--panel-2);
  transform: translateY(-2px);
}

.service-card__body {
  flex: 1;
  min-height: 3rem;
}

.service-card__name {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 0.35rem;
}

.service-card__desc {
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.service-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 0.25rem;
}

.service-card__type {
  display: inline-block;
  font-size: 0.65rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--overlay-subtle);
  border-radius: 4px;
  padding: 0.2rem 0.5rem;
}

.service-card__status {
  font-size: 0.75rem;
  font-weight: 600;
  border-radius: 4px;
  padding: 0.2rem 0.55rem;
}

.service-card__status--connected {
  color: #6ee7b7;
  background: rgba(16, 185, 129, 0.15);
}

.service-card__status--idle {
  color: #a5b4fc;
  background: rgba(99, 102, 241, 0.15);
}

.service-card__status--needs-key {
  color: #fbbf24;
  background: rgba(245, 158, 11, 0.15);
}

.service-card__toggle {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

/* Block 590: disabled state — vendor не установлен в bus_tenant_connections для тенанта.
 * Toggle grayed + not-clickable (input[disabled] handles pointer events).
 * Card остаётся visible, только status badge amber + toggle disabled.
 */
.service-card--not-installed .settings-toggle {
  opacity: 0.4;
  cursor: not-allowed;
}
.service-card--not-installed .settings-toggle input[type="checkbox"] {
  cursor: not-allowed;
}

/**
 * time-picker.css — Team Portal lib primitive: two-dropdown time selector.
 *
 * Layout: flexbox 50/50 hours left / minutes right (block 9003 task 546).
 * Consistent styling с existing select fields (reuse .field-text-like appearance).
 *
 * Public markup contract (per time-picker.js:24-30):
 *   <div class="time-picker">
 *     <select class="time-picker__hh">...</select>
 *     <select class="time-picker__mm">...</select>
 *   </div>
 */

.time-picker {
  display: flex;
  gap: 8px;
  width: 100%;
}

.time-picker__hh,
.time-picker__mm {
  flex: 1;
  padding: 8px 10px;
  border: 1px solid var(--line-2, #3a3a3a);
  border-radius: 6px;
  background: var(--input-bg, #0f1b2c);
  color: var(--text-primary, #e8edf5);
  font-size: 14px;
  font-family: inherit;
  cursor: pointer;
}

.time-picker__hh:focus,
.time-picker__mm:focus {
  outline: none;
  border-color: var(--accent, #3aa7e2);
}

/*
 * format-icons.css — Team Portal lib primitive styles.
 *
 * Block 2010 task radar-os--546. See format-icons.js for design decisions.
 *
 * Base .fmt-icon: 24×24 monochrome stroke SVG wrapper.
 * Size modifiers: --sm (18×18), --lg (32×32). Inline size override via style attr.
 * Color: currentColor from parent — automatic contrast (active pill = white on accent).
 */

.fmt-icon {
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: inherit;
  vertical-align: middle;
  flex-shrink: 0;
}

.fmt-icon svg {
  width: 100%;
  height: 100%;
}

.fmt-icon--sm { width: 18px; height: 18px; }
.fmt-icon--lg { width: 32px; height: 32px; }

/*
 * slider-pills.css — Team Portal lib primitive styles.
 *
 * Block 2010 task radar-os--546. Consumer: Slider primitive type='pills'.
 * Also defines global .sl-field--hidden helper for Slider showIf mechanism.
 */

.sl-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 4px;
}

.sl-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 8px;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: 13px;
  line-height: 1.2;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.sl-pill:hover {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.25);
}

.sl-pill--active {
  background: var(--accent, #4a9eff);
  border-color: var(--accent, #4a9eff);
  color: #fff;
}

.sl-pill--active:hover {
  background: var(--accent, #4a9eff);
}

.sl-pill .fmt-icon {
  width: 18px;
  height: 18px;
}

.sl-pill__label {
  white-space: nowrap;
}

/* Global helper for Slider showIf mechanism — hides field wrapper. */
.sl-field--hidden {
  display: none !important;
}

/*
 * slider-field-actions.css — Team Portal lib primitive styles.
 *
 * Block 2020 task radar-os--546. Consumer: Slider primitive f.actions array.
 * Renders row of icon buttons after input for open/copy/share/custom actions.
 */

.sl-field__actions {
  display: flex;
  gap: 6px;
  margin-top: 6px;
  flex-wrap: wrap;
}

.sl-field-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 8px;
  background: transparent;
  color: inherit;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.sl-field-action:hover {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.25);
}

.sl-field-action:focus-visible {
  outline: 2px solid var(--accent, #4a9eff);
  outline-offset: 2px;
}

.sl-field-action svg {
  width: 18px;
  height: 18px;
}

/* StatusFilterPills primitive — Block 2104.
 *
 * Visual styling inherited из FilterBar primitive (filter-bar.css / team.css
 * .filters / .filter-group / .pill / .pill--active).
 *
 * Placeholder file для future per-primitive overrides (если понадобятся
 * mode-specific визуальные адаптации без затрагивания FilterBar).
 *
 * Memory feedback_no_monolith_css — каждый primitive имеет свой CSS file
 * даже если empty для consistency и future-proofing.
 */

/*
 * shared-helpers.css — Team Portal shared helpers companion CSS.
 *
 * Companion to lib/shared-helpers.js (Block 1103 of task radar-os--455-docs-control-mode).
 *
 * Loaded via <link> in team/index.html after legacy lib CSS files.
 */

/* Overdue date marker used by formatDateRu() when iso < overdueAfter && !isFinal */
.t-date-overdue {
  color: var(--date-overdue-color, #ef4444);
  font-weight: 600;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: none;
  border-radius: 12px;
  padding: 10px 18px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background .12s ease;
}
.btn-primary { background: #3AA7E2; color: #fff; }
.btn-primary:hover { background: #6EC1FF; }
.btn-primary:disabled { opacity: .6; cursor: default; }
.btn-ghost {
  background: transparent;
  color: rgba(255,255,255,.92);
  border: 1px solid rgba(255,255,255,.12);
}
.btn-ghost:hover { background: rgba(255,255,255,.06); }
.btn-ghost:disabled { opacity: .4; cursor: default; }
.btn-danger { background: #d93838; color: #fff; }
.btn-danger:hover { background: #b82a2a; }
.btn-danger:disabled { opacity: .6; cursor: default; }

.confirm-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,.45);
  z-index: 1100;
  display: flex;
  align-items: center;
  justify-content: center;
}
.confirm-overlay[hidden] { display: none; }
.confirm-modal {
  background: #141F33;
  color: #DCE4F0;
  border: 1px solid rgba(255,255,255,.08);
  border-radius: 12px;
  padding: 20px 22px;
  min-width: 320px;
  max-width: 440px;
  box-shadow: 0 12px 40px rgba(0,0,0,.45);
}
.confirm-title { font-weight: 600; font-size: 15px; margin-bottom: 8px; color: #DCE4F0; }
.confirm-message { color: #B7C3D8; font-size: 13px; margin-bottom: 18px; line-height: 1.45; }
.confirm-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* Block 1502 — opt-in textarea input field (inputField config in Confirm.show). */
.confirm-input-wrap {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 16px;
}
.confirm-textarea {
  width: 100%;
  box-sizing: border-box;
  background: rgba(255, 255, 255, 0.04);
  color: #DCE4F0;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 8px;
  padding: 10px;
  font-size: 13px;
  font-family: inherit;
  min-height: 80px;
  resize: vertical;
}
.confirm-textarea:focus {
  outline: none;
  border-color: #3AA7E2;
}
.confirm-counter {
  font-size: 12px;
  color: #93a4c0;
  text-align: right;
}
.confirm-counter--invalid {
  color: #ef4444;
}

/*
 * timeline.css — Team Portal UI primitive: generic vertical timeline.
 *
 * Companion to lib/timeline.js (block 9 of task radar-os--464-history-tab-all-modes).
 *
 * Dot colors via `--badge-{variant}-color` from status-badge.css palette.
 * Graceful degradation when CSS-vars missing (fallback colors hardcoded).
 *
 * No emojis (memory rule).
 */

.tl-container {
  display: flex;
  flex-direction: column;
}

.tl-event {
  display: grid;
  grid-template-columns: 16px 1fr;
  gap: 12px;
  position: relative;
  padding-bottom: 12px;
}

.tl-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  margin-top: 6px;
  margin-left: 2px;
  background: var(--badge-color, #9ca3af);
  flex-shrink: 0;
}

.tl-dot--success { background: var(--badge-success-color, #22c55e); }
.tl-dot--danger  { background: var(--badge-danger-color,  #ef4444); }
.tl-dot--warning { background: var(--badge-warning-color, #f4a300); }
.tl-dot--info    { background: var(--badge-info-color,    #38bdf8); }
.tl-dot--muted   { background: var(--badge-muted-color,   #9ca3af); }

.tl-connector {
  position: absolute;
  left: 9px;
  top: 22px;
  bottom: 0;
  width: 2px;
  background: var(--border, rgba(255, 255, 255, 0.08));
}

.tl-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 4px 8px;
  border-radius: 6px;
  transition: background 0.12s;
}

.tl-card--clickable {
  cursor: pointer;
}

.tl-card--clickable:hover {
  background: rgba(58, 167, 226, 0.06);
}

.tl-time {
  font-size: 11px;
  color: var(--hint, #9ca3af);
}

.tl-actor {
  font-size: 12px;
  color: var(--hint, #9ca3af);
}

.tl-label {
  font-size: 13px;
  color: var(--fg, #e8edf5);
}

.tl-status {
  font-size: 11px;
  color: var(--hint, #9ca3af);
  font-style: italic;
}

.tl-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
}

.tl-channel,
.tl-badge {
  font-size: 10px;
  color: var(--hint, #9ca3af);
  padding: 1px 6px;
  border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
  border-radius: 4px;
}

.tl-empty {
  font-size: 13px;
  color: var(--hint, #9ca3af);
  font-style: italic;
  text-align: center;
  padding: 24px 12px;
}

/**
 * item-pipeline-panel.css — Whitelist timeline styling.
 *
 * Timeline visual — из lib/timeline.css (dot+connector+card).
 * Здесь только host padding + loading/error state.
 *
 * Block 4 of task radar-os--538-mode-timeline-config-questions.
 * Replaces phases/chain-group/expected-chain styling (task 521 legacy).
 */

.pp-host {
  padding: 12px 16px;
}

.pp-loading {
  padding: 24px 12px;
  text-align: center;
  color: var(--muted, #8892a6);
  font-size: 13px;
}

.pp-error {
  padding: 16px 12px;
  color: var(--pp-danger, #e05b5b);
  font-size: 13px;
}

/*
 * spinner.css — Team Portal UI primitive: rotating loader indicator.
 *
 * Companion to lib/spinner.js (Block 463/26.1.1 of task
 * radar-os--463-chains-and-atoms-architecture).
 *
 * CSS-only border circle with single transparent edge для visible rotating arc.
 * Customizable через CSS variables. `prefers-reduced-motion` disables animation
 * (border circle stays as static visual indicator).
 *
 * Loaded via <link> in team/index.html (after status-badge.css per visual primitives
 * group, before main mode pages).
 */

.spinner {
  display: inline-block;
  width: var(--spinner-size, 16px);
  height: var(--spinner-size, 16px);
  border: var(--spinner-thickness, 2px) solid var(--spinner-color, currentColor);
  border-top-color: transparent;
  border-radius: 50%;
  animation: spinner-rotate 0.8s linear infinite;
  vertical-align: middle;
  box-sizing: border-box;
}

@keyframes spinner-rotate {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
  }
}

/**
 * money-calendar/styles.css — layout styles for MoneyCalendar lib.
 *
 * Namespace: `.mc-*` prefix (money-calendar). Avoids collision with
 * payments `.p-cal-*` classes.
 *
 * Colors: layout via Team Portal CSS vars (--fg, --line-2, --muted, --bg).
 * Status colors (paid green / late purple / etc.) are applied inline from
 * STATUS_COLORS map in index.js — data-driven, extensible via config.
 */

.mc-root {
  color: var(--fg);
}

.mc-wrap {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 14px 0;
}

/* ── Undated section ─────────────────────────────────────── */

.mc-undated {
  border-radius: 12px;
  background: var(--panel, rgba(255,255,255,0.02));
  border: 1px solid var(--line-2, rgba(148,163,184,0.15));
  padding: 14px;
}

.mc-undated-toggle {
  background: transparent;
  border: 0;
  color: var(--fg);
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  cursor: pointer;
  padding: 0;
  font-family: inherit;
}

.mc-undated-label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 500;
}

.mc-undated-arrow {
  font-size: 11px;
  color: var(--muted);
}

.mc-undated-title {
  color: var(--fg);
}

.mc-undated-total {
  font-size: 13px;
  color: var(--muted);
}

.mc-undated-content {
  margin-top: 12px;
  flex-direction: column;
  gap: 6px;
}

.mc-undated-card {
  padding: 8px 12px;
  border-radius: 8px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
}

/* ── Main panel ─────────────────────────────────────────── */

.mc-panel {
  border-radius: 12px;
  background: var(--panel, rgba(255,255,255,0.02));
  border: 1px solid var(--line-2, rgba(148,163,184,0.15));
  padding: 16px;
}

.mc-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}

.mc-nav {
  display: flex;
  align-items: center;
  gap: 12px;
}

.mc-nav-btn {
  padding: 6px 14px;
  font-size: 16px;
  line-height: 1;
  background: transparent;
  border: 1px solid var(--line-2, rgba(148,163,184,0.3));
  color: var(--fg);
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
}

.mc-nav-btn:hover {
  background: rgba(255,255,255,0.05);
}

.mc-week-range {
  font-size: 18px;
  margin: 0;
  min-width: 240px;
  text-align: center;
  color: var(--fg);
  font-weight: 500;
}

/* Round 2 (block 7.2): 2-line week total — plan/fact stacked with color labels. */
.mc-week-total {
  font-size: 13px;
  color: var(--muted);
  text-align: right;
  line-height: 1.35;
}

.mc-week-total-line {
  font-size: 13px;
}

.mc-week-total-line.mc-week-plan {
  color: rgba(252, 165, 165, 0.9);
}

.mc-week-total-line.mc-week-fact {
  color: rgba(134, 239, 172, 0.9);
}

/* ── Grid ──────────────────────────────────────────────── */

.mc-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 8px;
}

.mc-day-col {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.mc-day-header {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 6px;
  border-bottom: 1px solid var(--line-2, rgba(148,163,184,0.15));
  min-width: 0;
}

.mc-day-name {
  font-size: 12px;
  color: var(--fg);
  font-weight: 500;
}

/* Round 2 (block 7.2): 2-line day sub — plan on top, fact below.
   Vertically stacked with distinct colors for at-a-glance recognition. */
.mc-day-sub {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 11px;
  color: var(--muted);
  min-width: 0;
}

.mc-day-sub-plan,
.mc-day-sub-fact {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mc-day-sub-plan {
  color: rgba(252, 165, 165, 0.9);
}

.mc-day-sub-fact {
  color: rgba(134, 239, 172, 0.9);
}

.mc-day-cards {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

/* ── Cards ─────────────────────────────────────────────── */

.mc-card {
  border-radius: 8px;
  padding: 6px 8px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
  transition: filter 0.15s ease;
}

.mc-card:hover {
  filter: brightness(1.1);
}

.mc-card-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mc-card-amount {
  font-weight: 600;
}

/* Fact cards may want subtle visual distinction (dashed border for
   "fact only" state) — apply if design wants later.
.mc-card-fact {
  border-style: dashed;
}
*/

/* ── Empty state ─────────────────────────────────────── */

.mc-empty {
  padding: 32px 0;
  text-align: center;
  color: var(--muted);
  font-size: 13px;
}

/*
 * time-strip.css — Team Portal UI primitive: rows × continuous time axis.
 *
 * Companion to lib/time-strip.js (блок 6010 задачи radar-os--696).
 *
 * Геометрия принципиально иная, чем у heatmap.css: там решётка равных ячеек,
 * здесь непрерывная ось. Отрезки позиционируются в ПРОЦЕНТАХ от ширины полотна,
 * поэтому 09:00 и 09:15 отстоят ровно на четверть часа, а объект с двумя
 * контрольными точками честно сравнивается с объектом, у которого их пять.
 *
 * Проценты, а не пиксели, ещё и потому, что мобильный вид — отдельный блок
 * (6140). Жёсткая минимальная ширина сделала бы его переписыванием.
 *
 * Цвета состояний названы как варианты status-badge (success / warning /
 * danger / muted / info) — в библиотеке уже есть этот словарь, заводить второй
 * значило бы объяснять каждому, чем «bad» отличается от «danger».
 *
 * Подключается через bundle.css — файл добавлен в CSS_FILES скрипта
 * scripts/team-bundle.sh. Без этой записи стиль просто не загрузится.
 */

.tstrip {
  --tstrip-bg:            rgba(255, 255, 255, 0.02);
  --tstrip-line:          rgba(255, 255, 255, 0.08);
  --tstrip-tick:          rgba(255, 255, 255, 0.06);
  --tstrip-label-bg:      #141C27;
  --tstrip-text:          #E5EAF1;
  --tstrip-text-dim:      rgba(229, 234, 241, 0.55);
  --tstrip-row-hover:     rgba(58, 167, 226, 0.08);

  --tstrip-success-bg:    rgba(34, 197, 94, 0.20);
  --tstrip-success-bd:    rgba(34, 197, 94, 0.55);
  --tstrip-warning-bg:    rgba(245, 158, 11, 0.20);
  --tstrip-warning-bd:    rgba(245, 158, 11, 0.50);
  --tstrip-danger-bg:     rgba(239, 68, 68, 0.20);
  --tstrip-danger-bd:     rgba(239, 68, 68, 0.50);
  --tstrip-info-bg:       rgba(58, 167, 226, 0.20);
  --tstrip-info-bd:       rgba(58, 167, 226, 0.50);
  --tstrip-muted-bg:      rgba(148, 163, 184, 0.16);
  --tstrip-muted-bd:      rgba(148, 163, 184, 0.38);

  /* Состояния дня (блок 6060). Значения ровно те три, что пишет бэкенд —
     day_scores.php:44-58 возвращает green / yellow / red и ничего больше.
     Четвёртое, --day-future, задаёт вид ещё не наступивших суток: они не
     зелёные (исхода нет) и не пустые (иначе теряется сетка). */
  --tstrip-day-green:     rgba(34, 197, 94, 0.14);
  --tstrip-day-yellow:    rgba(245, 158, 11, 0.16);
  --tstrip-day-red:       rgba(239, 68, 68, 0.16);
  --tstrip-day-future:    rgba(148, 163, 184, 0.05);

  /* Разлиновка суток (блок 6220). Ничего не означает — только показывает, где
     кончаются одни сутки и начинаются другие. Разница между парой умышленно на
     грани заметности: глаз ловит стык, но не ищет в оттенке смысла. Контрастная
     зебра стала бы вторым цветовым языком поверх отметок, а от этого и уходим. */
  --tstrip-day-zebra-a:   rgba(255, 255, 255, 0.012);
  --tstrip-day-zebra-b:   rgba(255, 255, 255, 0.040);

  position: relative;
  overflow-x: auto;
  overflow-y: visible;

  /* Жест на тач-экране (блок 6140). Без touch-action полотно ловит и
     диагональный свайп, забирая у страницы вертикальную прокрутку: палец ведёт
     вниз-вбок, страница стоит. pan-x отдаёт вертикаль странице, оставляя
     полотну только горизонталь. Замерено до правки: touch-action был auto.
     contain — чтобы домотка до края ленты не начинала листать историю
     браузера жестом «назад». */
  touch-action: pan-x;
  overscroll-behavior-x: contain;

  /* Короткое имя для цепочки ширины колонки: её используют и обе колонки, и
     линия «сейчас», и повторять трёхэтажный var() в трёх местах — верный
     способ поправить два из трёх. */
  --tstrip-lw: var(--tstrip-label-width-narrow, var(--tstrip-label-width, 180px));
  background: var(--tstrip-bg);
  border: 1px solid var(--tstrip-line);
  border-radius: 6px;
  font-size: 12px;
  color: var(--tstrip-text);
}

html[data-theme="light"] .tstrip {
  --tstrip-day-green:  rgba(34, 197, 94, 0.18);
  --tstrip-day-yellow: rgba(245, 158, 11, 0.22);
  --tstrip-day-red:    rgba(239, 68, 68, 0.18);
  --tstrip-day-future: rgba(100, 116, 139, 0.07);
  /* В светлой теме пара идёт ВНИЗ от подложки: осветлять белое нечем. */
  --tstrip-day-zebra-a: rgba(15, 23, 42, 0.012);
  --tstrip-day-zebra-b: rgba(15, 23, 42, 0.040);
  --tstrip-bg:        rgba(0, 0, 0, 0.015);
  --tstrip-line:      rgba(0, 0, 0, 0.10);
  --tstrip-tick:      rgba(0, 0, 0, 0.06);
  --tstrip-label-bg:  #FFFFFF;
  --tstrip-text:      #1F2937;
  --tstrip-text-dim:  rgba(31, 41, 55, 0.55);
}

/* Минимальная ширина полотна: ниже неё подписи шкалы наезжают друг на друга.
   Задана переменной, чтобы блок 6140 менял её для узкого экрана, а не правил
   правило. */
.tstrip-inner {
  min-width: var(--tstrip-min-width, 720px);
}

/* ── шкала делений ─────────────────────────────────────────── */

.tstrip-head {
  display: flex;
  border-bottom: 1px solid var(--tstrip-line);
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--tstrip-label-bg);
}

.tstrip-head__label {
  /* Две ступени, а не одна, и это не стилистика. Примитив ставит
     --tstrip-label-width ИНЛАЙН-стилем (time-strip.js:334), а инлайн сильнее
     любого правила таблицы стилей. Медиазапрос, переопределяющий саму
     --tstrip-label-width, молча проиграл бы: правило лежало бы в файле, а
     ширина осталась бы прежней. Узкую ступень ставит только медиазапрос,
     примитив её не трогает — поэтому она и выигрывает. */
  flex: 0 0 var(--tstrip-lw);
  padding: 6px 10px;
  font-weight: 600;
  color: var(--tstrip-text-dim);
  border-right: 1px solid var(--tstrip-line);
  position: sticky;
  left: 0;
  z-index: 3;
  background: var(--tstrip-label-bg);
}

.tstrip-head__lane {
  position: relative;
  flex: 1 1 auto;
  height: 26px;
}

.tstrip-tick {
  position: absolute;
  top: 0;
  bottom: 0;

  border-left: 1px solid var(--tstrip-tick);
  padding-left: 4px;
  font-size: 11px;
  line-height: 26px;
  color: var(--tstrip-text-dim);
  white-space: nowrap;
  pointer-events: none;
}

/* Крайнее правое деление (блок 6140).
 *
 * Оно стоит на left: 100%, и подпись уходила ВПРАВО за край полотна: замер до
 * правки — правый край полотна 733px, правый край подписи 769px. Тридцать
 * шесть пикселей мёртвой прокрутки, до которых пользователь домотает и увидит
 * пустоту. Разворачиваем: сам элемент сдвигаем на свою ширину влево, чтобы
 * линия осталась ровно на 100%, а подпись легла внутрь полотна. Линию при
 * этом переносим с левой границы на правую — иначе она уехала бы вместе с
 * элементом и встала не там, где означает конец периода. */
.tstrip-tick--last {
  transform: translateX(-100%);
  padding-left: 0;
  padding-right: 4px;
  text-align: right;
  border-left: 0;
  border-right: 1px solid var(--tstrip-tick);
}

/* ── ряды ──────────────────────────────────────────────────── */

/* Разделитель рядов живёт в колонке названий, а не через всю ширину
 * (блок 6170).
 *
 * Через всю ширину он давал вторую горизонтальную линию в дорожке — рядом с
 * линией смены, того же цвета и толщины, в тридцати пикселях от неё. Глаз их
 * путал: «куча линий, всё сливается». Смысл при этом несёт только одна, и это
 * линия смены.
 *
 * Совсем убрать разделитель нельзя: в списке из тридцати семи объектов имена
 * слиплись бы по вертикали. Поэтому он остаётся там, где читается список, и
 * уходит оттуда, где читается время. Подсветка ряда при наведении тоже
 * остаётся — она помогает вести глаз по строке на широком экране. */
.tstrip-row {
  display: flex;
}
.tstrip-row:hover { background: var(--tstrip-row-hover); }

.tstrip-row__label {
  flex: 0 0 var(--tstrip-lw);
  padding: 8px 10px;
  border-right: 1px solid var(--tstrip-line);
  border-bottom: 1px solid var(--tstrip-line);
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--tstrip-label-bg);
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tstrip-row__sub {
  display: block;
  font-size: 11px;
  color: var(--tstrip-text-dim);
  /* Своё обрезание, а не родительское. У .tstrip-row__label стоит
     text-overflow: ellipsis, но он относится к СОБСТВЕННОМУ строчному
     содержимому — до блочного потомка не достаёт. Без этих трёх строк подпись
     обрубается посреди буквы, без многоточия: видно на скриншоте узкого
     экрана, где «чисто 10/14 · срывов 0» упиралось в край колонки. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tstrip-row:last-child .tstrip-row__label { border-bottom: 0; }

.tstrip-row__lane {
  position: relative;
  flex: 1 1 auto;
  min-height: 34px;
}

/* Фон ряда приходит данными, а не решается примитивом: у дежурств это светофор
   суток (блок 6060), у другого потребителя может быть что угодно. */
.tstrip-band {
  position: absolute;
  top: 0;
  bottom: 0;
  pointer-events: none;
}

/* Полоса с подсказкой должна ловить наведение, иначе tooltip не покажется.
   Клики всё равно уходят в делегированный слушатель ряда. */
.tstrip-band--hoverable { pointer-events: auto; cursor: default; }

/* Идущая смена бледнее закрытой: закрытая — итог, идущая ещё меняется. */
.tstrip-band--live { opacity: 0.55; }

/* ── отрезки ───────────────────────────────────────────────── */

/* Отрезок центрируется по высоте дорожки, а не отсчитывается от её верха
 * (блок 6170).
 *
 * Раньше здесь стояло `top: 7px` при высоте 20 — числа подобраны под дорожку в
 * 34 пикселя, ровно столько обещает `min-height` у .tstrip-row__lane. Но высоту
 * задаёт не она, а соседняя колонка названий: у дежурств там две строки, имя и
 * «срывов 1 · чисто 0/2», плюс отступы по восемь пикселей — около пятидесяти.
 * Флексбокс растягивает дорожку под неё, а отрезки остаются на своих семи и
 * оказываются в верхней трети. На скриншоте это читалось как «линия проходит не
 * по центру» — и то же самое было верно для точек, просто менее заметно.
 *
 * Процент от высоты снимает вопрос навсегда: подпись станет длиннее, дорожка
 * вырастет, отрезки останутся посередине без единой правки. */
.tstrip-seg {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  height: 20px;
  border-radius: 3px;
  border: 1px solid transparent;
  background: var(--tstrip-muted-bg);
  border-color: var(--tstrip-muted-bd);
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 0 5px;
  line-height: 18px;
  font-size: 11px;
  box-sizing: border-box;
}

.tstrip-seg--success { background: var(--tstrip-success-bg); border-color: var(--tstrip-success-bd); }
.tstrip-seg--warning { background: var(--tstrip-warning-bg); border-color: var(--tstrip-warning-bd); }
.tstrip-seg--danger  { background: var(--tstrip-danger-bg);  border-color: var(--tstrip-danger-bd);  }
.tstrip-seg--info    { background: var(--tstrip-info-bg);    border-color: var(--tstrip-info-bd);    }
.tstrip-seg--muted   { background: var(--tstrip-muted-bg);   border-color: var(--tstrip-muted-bd);   }

.tstrip-seg:focus-visible,
.tstrip-row__label:focus-visible {
  outline: 2px solid var(--tstrip-info-bd);
  outline-offset: 1px;
}

/* Точечная отметка — отрезок нулевой длительности (контрольная точка).
 *
 * Пятнадцать пикселей: восемь в блоке 6160, двенадцать, затем пятнадцать в 6170.
 * Восемь терялись на десктопе и были почти невидимы на узком экране, а после
 * переезда цвета с полотна на отметку она стала единственным носителем сигнала —
 * мельчить больше нельзя. Пятнадцать понадобились, когда форма стала щитом у
 * всех отметок: у него, в отличие от круга, есть верх и низ, и на двенадцати он
 * начинал читаться как пятно.
 *
 * `border-radius` остаётся, хотя щит его перекрывает: правило описывает
 * ГЕОМЕТРИЮ точки, а не её вид, и потребитель без щита получит круг.
 *
 * Половина размера дублируется отрицательным отступом в JS (SEG_POINT_SIZE):
 * без него отметка встала бы левым краем на свой момент, а не центром.
 * Вертикальное положение задаёт .tstrip-seg — процентом от высоты дорожки. */
.tstrip-seg--point {
  width: 15px;
  padding: 0;
  border-radius: 50%;
  height: 15px;
}

/* Щит вместо круга у критичных отметок (блок 6160, D20).
 *
 * Плашка гасится полностью: у щита цвет несёт САМА ФИГУРА через fill:
 * currentColor, а фон и рамка превратили бы её в цветной квадрат с силуэтом
 * внутри. Поэтому правило стоит ПОСЛЕ состояний .tstrip-seg--{state} — при
 * равной специфичности побеждает последнее, и фон снимается.
 *
 * Цвет берётся из «бордюрной» переменной, а не из фоновой: фоновые заливки
 * приглушены под подложку, и щит на них читался бы бледнее круга. */
.tstrip-seg--shield {
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  overflow: visible;
}

.tstrip-seg--shield svg {
  width: 100%;
  height: 100%;
  display: block;
}

.tstrip-seg--shield.tstrip-seg--success { color: var(--tstrip-success-bd); }
.tstrip-seg--shield.tstrip-seg--warning { color: var(--tstrip-warning-bd); }
.tstrip-seg--shield.tstrip-seg--danger  { color: var(--tstrip-danger-bd);  }
.tstrip-seg--shield.tstrip-seg--info    { color: var(--tstrip-info-bd);    }
.tstrip-seg--shield.tstrip-seg--muted   { color: var(--tstrip-muted-bd);   }

/* Соединительная линия между отметками (блок 6160).
 *
 * Отдельный вид, а не тонкий отрезок. `.tstrip-seg` рисует ИНТЕРВАЛ полосой в
 * 20px, и пропорциональный интервал — единственное, ради чего примитив писался
 * вместо heatmap.js. Правило действует только при явном флаге `line` от
 * потребителя: занятость оборудования и бронь переговорки остаются полосами.
 *
 * Прозрачная рамка базового класса обнуляется — иначе двухпиксельная линия
 * состояла бы из рамки целиком и в тёмной теме выглядела бы рваной. */
.tstrip-seg--line {
  height: 2px;
  border: none;
  border-radius: 1px;
  padding: 0;
  opacity: .55;
}

/* ── линия текущего момента (блок 6070) ────────────────────── */

/* Обёртка рядов нужна, чтобы линия позиционировалась относительно всего
   полотна, а не отдельного ряда. */
.tstrip-lanes { position: relative; }

.tstrip-now {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 0;
  border-left: 2px solid var(--tstrip-now-color, #F87171);
  /* Без этого линия накрыла бы отрезки под собой, и отметка в текущем часе
     перестала бы открываться по клику. Тот же приём, что у полос фона. */
  pointer-events: none;
  /* Ниже колонки названий (у неё z-index: 1), но выше полос фона: те лежат
     раньше по документу и своего z-index не имеют. При z-index: 4 линия
     рисовалась ПОВЕРХ липкой колонки и перечёркивала имена объектов —
     видно на замере светлой темы в 01:43 (блок 6140). */
  z-index: 0;
}

.tstrip-now__label {
  position: sticky;
  top: 26px;              /* под шкалой делений */
  display: inline-block;
  transform: translateX(-50%);
  padding: 1px 5px;
  border-radius: 3px;
  font-size: 10px;
  line-height: 14px;
  white-space: nowrap;
  background: var(--tstrip-now-color, #F87171);
  color: #12181F;
  font-weight: 600;
}

html[data-theme="light"] .tstrip { --tstrip-now-color: #DC2626; }

.tstrip-empty {
  padding: 18px 12px;
  color: var(--tstrip-text-dim);
}

/* ── узкий экран (блок 6140) ────────────────────────────────────
 *
 * Все числа ниже — из замера в браузере на настоящем CSS, не из рассуждения.
 * До правки на iPhone 14 (390×844) видимая ширина полотна была 364px, а
 * колонка названий занимала из них 180px — 49%. На iPhone SE (375×667) — 52%.
 * То есть половина экрана уходила на имена объектов, а на саму ось времени
 * оставалось 184 и 169 пикселей.
 *
 * Порог 560px, а не 480: между ними лежат узкие окна на десктопе и планшеты в
 * портрете, где половина экрана под названия так же неуместна.
 */
@media (max-width: 560px) {
  .tstrip {
    /* Узкая ступень переменной. Именно она, а не --tstrip-label-width:
       ту ставит инлайн-стилем сам примитив (time-strip.js:334), и инлайн
       сильнее таблицы стилей — правило молча не применилось бы. */
    --tstrip-label-width-narrow: 120px;

    /* Полотно шире экрана всё равно, поэтому лучше сделать его ЧИТАЕМЫМ, чем
       коротким. До правки месяц умещался в дорожку 540px, то есть 18 пикселей
       на сутки: полоса дня превращалась в риску. При 960px сутки получают
       28 пикселей, а прокрутка на телефоне и так неизбежна. */
    --tstrip-min-width: 960px;
  }

  /* Кегль ставим на сам .tstrip-row__label: имя объекта — это голый текстовый
     узел внутри него (time-strip.js, _rowHtml), отдельного класса у названия
     нет. Правило на выдуманный .tstrip-row__name лежало бы в файле и не
     применялось бы ни к чему — ни ошибки, ни следа. */
  .tstrip-row__label { padding: 8px; font-size: 12px; }
  .tstrip-row__sub   { font-size: 10px; }
  .tstrip-tick       { font-size: 10px; }
}

/* stat-tiles.css — стили примитива lib/stat-tiles.js.
 *
 * Геометрия и токены сняты с существующего ряда KPI режима monitor
 * (monitor/styles.css:5-48) намеренно: новый компонент не должен выбиваться
 * из того, что пользователь уже видит в портале. Отличие одно — сетка не
 * фиксирована на четыре колонки, а подстраивается под число плиток.
 */

.stiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}

.stiles__tile {
  background: var(--panel);
  border: 1px solid var(--line-2);
  border-radius: 10px;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  transition: background .15s;
}

.stiles__tile:hover {
  background: var(--panel-2);
}

.stiles__value {
  font-size: 28px;
  font-weight: 700;
  line-height: 1.1;
  color: var(--text);
  font-variant-numeric: tabular-nums;   /* цифры не «прыгают» при обновлении */
}

.stiles__label {
  font-size: 12px;
  color: var(--muted);
  line-height: 1.3;
}

/* Варианты повторяют словарь status-badge — info / danger / success.
 * Свой словарь означал бы два набора состояний в одной библиотеке. */
.stiles__tile--info    .stiles__value { color: var(--primary-hover); }
.stiles__tile--danger  .stiles__value { color: var(--danger); }
.stiles__tile--success .stiles__value { color: var(--success); }

/* ── узкий экран (блок 6140) ────────────────────────────────────
 *
 * Замер до правки на 390×844: сетка auto-fit давала ДВЕ колонки, третья плитка
 * вставала одна во втором ряду с пустотой рядом, и весь ряд занимал 196
 * пикселей из 844 — почти четверть экрана до того, как видно хоть одну смену.
 *
 * Здесь сетка фиксируется в три равные колонки: три коротких числа помещаются
 * в ряд на любом телефоне, а рваная раскладка 2+1 исчезает. Отступы и кегль
 * уменьшены, чтобы ряд стал плоским.
 */
@media (max-width: 560px) {
  .stiles {
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    margin-bottom: 12px;
  }

  .stiles__tile  { padding: 10px 8px; border-radius: 8px; }
  .stiles__value { font-size: 20px; }
  .stiles__label { font-size: 10px; }
}

/*
 * mode-scenarios-panel.css — вкладка «Сценарии»: недельная сетка расписания.
 * Задача radar-os--731, блок 90.
 *
 * Свой файл, а не строки в team.css: правило проекта — у каждого примитива
 * своя таблица стилей, монолит не растёт. Файл подключается через bundle.css,
 * запись добавлена в radar/scripts/team-bundle.sh.
 *
 * Переменные берутся из index.html — тема переключается сама, своих цветов
 * здесь нет.
 */

/* Строка дня: имя слева, времена в середине, кнопка добавления справа.
   Порядок повторяет донор — «Настройки дайджеста» в режиме «Вопросы», — чтобы
   человек, знающий тот экран, узнал этот. */
.msp-day {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 0;
  flex-wrap: wrap;
}

.msp-day + .msp-day {
  border-top: 1px solid var(--line, rgba(255, 255, 255, .06));
}

/* Ширина имени дня фиксирована: без неё «Пн» и «Вс» разъезжаются, и столбец
   перестаёт читаться столбцом. */
.msp-day__name {
  flex: 0 0 44px;
  font-size: 13px;
  color: var(--text-2);
}

.msp-day__times {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  flex: 1 1 auto;
  min-width: 0;
}

.msp-time {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

/* Поле времени узкое намеренно: в нём пять знаков, и растянутое на всю строку
   оно выглядело бы как поле для текста. */
.msp-time__input {
  width: 110px;
  min-width: 110px;
}

.msp-time__del {
  border: none;
  background: transparent;
  color: var(--text-2);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 4px;
  border-radius: 4px;
}

.msp-time__del:hover  { color: var(--danger, #e5484d); }
.msp-time__del:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.msp-day__add {
  flex: 0 0 auto;
}

