/* TrustLab — дашборд лаборатории.
   Рабочий инструмент: плотная сетка, табличные цифры, состояние читается
   формой, а не только числом. Палитра инженерной документации. */

:root {
  --ground:      #EDEFEC;
  --surface:     #FAFBF9;
  --surface-2:   #F3F5F1;
  --ink:         #14181A;
  --ink-2:       #3C4643;
  --muted:       #6C7671;
  --line:        #D5DAD3;
  --line-strong: #B9C0B6;
  --accent:      #1F4E79;
  --accent-soft: rgba(31, 78, 121, .10);
  --ok:          #2C6A4C;
  --ok-soft:     rgba(44, 106, 76, .12);
  --warn:        #A8521B;
  --warn-soft:   rgba(168, 82, 27, .12);
  --bad:         #A32C22;
  --bad-soft:    rgba(163, 44, 34, .12);

  --f-display: "IBM Plex Sans Condensed", "Arial Narrow", system-ui, sans-serif;
  --f-body:    "IBM Plex Sans", system-ui, -apple-system, sans-serif;
  --f-mono:    "IBM Plex Mono", ui-monospace, "Courier New", monospace;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground:      #14171A;
    --surface:     #1B1F22;
    --surface-2:   #212629;
    --ink:         #E8EBE7;
    --ink-2:       #BFC7C2;
    --muted:       #8A948E;
    --line:        #2C3236;
    --line-strong: #3D454A;
    --accent:      #7EB0DD;
    --accent-soft: rgba(126, 176, 221, .14);
    --ok:          #6FBF95;
    --ok-soft:     rgba(111, 191, 149, .15);
    --warn:        #E09355;
    --warn-soft:   rgba(224, 147, 85, .15);
    --bad:         #E27A6E;
    --bad-soft:    rgba(226, 122, 110, .15);
  }
}

:root[data-theme="dark"] {
  --ground:      #14171A;
  --surface:     #1B1F22;
  --surface-2:   #212629;
  --ink:         #E8EBE7;
  --ink-2:       #BFC7C2;
  --muted:       #8A948E;
  --line:        #2C3236;
  --line-strong: #3D454A;
  --accent:      #7EB0DD;
  --accent-soft: rgba(126, 176, 221, .14);
  --ok:          #6FBF95;
  --ok-soft:     rgba(111, 191, 149, .15);
  --warn:        #E09355;
  --warn-soft:   rgba(224, 147, 85, .15);
  --bad:         #E27A6E;
  --bad-soft:    rgba(226, 122, 110, .15);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--f-body);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); }

/* ---------- шапка ---------- */

.topbar {
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 10;
}

.topbar-inner {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 20px;
  display: flex;
  align-items: center;
  gap: 24px;
  min-height: 54px;
  flex-wrap: wrap;
}

.brand {
  font-family: var(--f-display);
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -.01em;
  text-decoration: none;
  color: var(--ink);
}

.brand span { color: var(--accent); }

.nav { display: flex; gap: 4px; flex: 1; flex-wrap: wrap; }

.nav a {
  font-size: 14px;
  text-decoration: none;
  color: var(--ink-2);
  padding: 6px 11px;
  border-radius: 3px;
}

.nav a:hover { background: var(--surface-2); }
.nav a[aria-current="page"] { background: var(--accent-soft); color: var(--accent); font-weight: 500; }

.whoami {
  font-family: var(--f-mono);
  font-size: 12px;
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 10px;
}

.linkbtn {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--muted);
  cursor: pointer;
  text-decoration: underline;
}

.linkbtn:hover { color: var(--ink); }

/* ---------- каркас ---------- */

main {
  max-width: 1180px;
  margin: 0 auto;
  padding: 24px 20px 72px;
}

h1 {
  font-family: var(--f-display);
  font-size: 27px;
  font-weight: 600;
  letter-spacing: -.01em;
  margin: 0 0 4px;
}

.subtitle {
  margin: 0 0 22px;
  color: var(--muted);
  font-size: 14px;
  font-family: var(--f-mono);
}

/* ---------- счётчики ---------- */

.counters {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-bottom: 30px;
}

.counter {
  background: var(--surface);
  padding: 13px 16px;
  display: block;
  text-decoration: none;
  color: inherit;
}

.counter dt {
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 3px;
}

.counter dd {
  margin: 0;
  font-family: var(--f-display);
  font-size: 26px;
  font-weight: 600;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}

.counter.hot dd  { color: var(--warn); }
.counter.bad dd  { color: var(--bad); }
.counter.good dd { color: var(--ok); }

/* ---------- блоки списков ---------- */

.block { margin-bottom: 34px; }

.block-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 10px;
  padding-bottom: 7px;
  border-bottom: 1px solid var(--line);
}

.block-head h2 {
  font-family: var(--f-display);
  font-size: 18px;
  font-weight: 600;
  margin: 0;
}

.block-head .count {
  font-family: var(--f-mono);
  font-size: 12px;
  color: var(--muted);
}

.rows { display: flex; flex-direction: column; gap: 1px; background: var(--line); border: 1px solid var(--line); }

.row {
  background: var(--surface);
  display: grid;
  grid-template-columns: 62px minmax(140px, 1.4fr) minmax(120px, 1.6fr) 76px 92px 96px;
  gap: 12px;
  align-items: center;
  padding: 10px 14px;
  text-decoration: none;
  color: inherit;
  border-left: 3px solid transparent;
}

.row:hover { background: var(--surface-2); }
.row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.row.late  { border-left-color: var(--bad); }
.row.now   { border-left-color: var(--accent); }
.row.soon  { border-left-color: var(--line-strong); }

.seq {
  font-family: var(--f-mono);
  font-size: 13px;
  font-weight: 500;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

.obj { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.struct {
  color: var(--muted);
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.age, .mark, .norm {
  font-family: var(--f-mono);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.norm { color: var(--muted); text-align: right; }
.norm.none { color: var(--warn); }

.empty {
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  padding: 22px;
  text-align: center;
  color: var(--muted);
  font-size: 14px;
}

/* ---------- чипы ---------- */

.chip {
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: .07em;
  text-transform: uppercase;
  padding: 2px 7px;
  border: 1px solid currentColor;
  white-space: nowrap;
  display: inline-block;
}

.chip.ok   { color: var(--ok); background: var(--ok-soft); }
.chip.warn { color: var(--warn); background: var(--warn-soft); }
.chip.bad  { color: var(--bad); background: var(--bad-soft); }
.chip.info { color: var(--accent); background: var(--accent-soft); }

/* ---------- формы ---------- */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  padding: 22px;
  max-width: 720px;
}

.field { margin-bottom: 16px; }

label {
  display: block;
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 5px;
}

/* Списки и поля даты/времени раньше сюда не попадали: они оставались
   строчными, подпись прилипала сбоку, и форма читалась как каша из
   наехавших друг на друга строк. */
input[type="text"], input[type="password"], input[type="number"],
input[type="date"], input[type="time"], input[type="search"],
select, textarea {
  width: 100%;
  padding: 9px 11px;
  font-family: var(--f-mono);
  font-size: 15px;
  background: var(--ground);
  color: var(--ink);
  border: 1px solid var(--line-strong);
  border-radius: 2px;
}

/* Сетка формы. Обычное поле занимает колонку, широкое — всю строку.
   Подпись всегда над полем: разнобой «где сверху, где сбоку» и создавал
   ощущение наложенных строк. */
.object-form .form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px 20px;
  align-items: start;
}
.object-form .form-grid > label { margin-bottom: 0; }
.object-form .form-grid > .wide-field { grid-column: 1 / -1; }
.object-form label > span { display: block; margin-bottom: 5px; }
.object-form label > em { text-transform: none; font-size: 11px; }

input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
  border-color: var(--accent);
}

button.primary {
  font-family: var(--f-body);
  font-size: 15px;
  font-weight: 500;
  padding: 10px 22px;
  background: var(--accent);
  color: var(--surface);
  border: none;
  border-radius: 2px;
  cursor: pointer;
}

button.primary:hover { filter: brightness(1.1); }
button.primary:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

.alert {
  padding: 10px 14px;
  margin-bottom: 16px;
  font-size: 14px;
  border: 1px solid var(--bad);
  color: var(--bad);
  background: var(--bad-soft);
}

.hint { font-size: 13px; color: var(--muted); margin: 6px 0 0; }

/* ---------- карточка испытания ---------- */

.meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  margin-bottom: 24px;
}

.meta div { background: var(--surface); padding: 11px 14px; }
.meta dt {
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 2px;
}
.meta dd {
  margin: 0;
  font-size: 15px;
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
}

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

.specimen {
  border: 1px solid var(--line);
  background: var(--surface-2);
  padding: 12px;
}

.specimen h3 {
  font-family: var(--f-mono);
  font-size: 11px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 9px;
  font-weight: 500;
}

.login-page {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
}

.login-card { width: 100%; max-width: 360px; }

.login-card h1 { font-size: 25px; margin-bottom: 3px; }
.login-card .subtitle { margin-bottom: 24px; }

@media (max-width: 780px) {
  .row {
    grid-template-columns: 54px 1fr 78px;
    row-gap: 4px;
  }
  .struct, .mark { display: none; }
}

/* ---------- фильтры журнала ---------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
  background: var(--surface);
  border: 1px solid var(--line);
  padding: 14px 16px;
  margin-bottom: 20px;
}

.filter { display: flex; flex-direction: column; min-width: 130px; }
.filter.grow { flex: 1 1 260px; }
.filter.actions { flex-direction: row; align-items: center; gap: 14px; }

.filter label { margin-bottom: 5px; }

.filter input, .filter select {
  padding: 7px 9px;
  font-family: var(--f-body);
  font-size: 14px;
  background: var(--ground);
  color: var(--ink);
  border: 1px solid var(--line-strong);
  border-radius: 2px;
}

.filter select:focus-visible, .filter input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}

.reset { font-size: 13px; color: var(--muted); }

/* ---------- таблица журнала ---------- */

.table-scroll { overflow-x: auto; border: 1px solid var(--line); background: var(--surface); }

table.journal {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

table.journal th, table.journal td {
  text-align: left;
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

table.journal thead th {
  font-family: var(--f-mono);
  font-size: 10px;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 500;
  background: var(--surface-2);
  position: sticky;
  top: 0;
}

table.journal tbody tr { cursor: pointer; }
table.journal tbody tr:hover { background: var(--surface-2); }
table.journal tbody tr:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
table.journal tbody tr:last-child td { border-bottom: none; }

table.journal .num {
  font-family: var(--f-mono);
  font-variant-numeric: tabular-nums;
  font-size: 13px;
}

table.journal .strong { font-weight: 600; font-size: 14px; }
table.journal .dim { color: var(--muted); }
table.journal .obj-cell { font-weight: 500; }
table.journal a { text-decoration: none; }
table.journal a:hover { text-decoration: underline; }

.pager {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-top: 16px;
  font-family: var(--f-mono);
  font-size: 13px;
  color: var(--muted);
}

.crumbs { margin: 0 0 10px; font-size: 13px; }
.crumbs a { text-decoration: none; }
.crumbs a:hover { text-decoration: underline; }

.meta dd.plain { font-family: var(--f-body); }

pre.raw {
  background: var(--surface-2);
  border: 1px solid var(--line);
  padding: 14px 16px;
  font-family: var(--f-mono);
  font-size: 13px;
  line-height: 1.5;
  white-space: pre-wrap;
  overflow-x: auto;
  margin: 0;
  color: var(--ink-2);
}

/* ---------- очередь проверки ---------- */

.actions-cell { display: flex; gap: 6px; }
.actions-cell form { margin: 0; }

button.mini {
  font-family: var(--f-body);
  font-size: 12px;
  padding: 4px 10px;
  border-radius: 2px;
  cursor: pointer;
  border: 1px solid currentColor;
  background: transparent;
  white-space: nowrap;
}

button.mini.ok  { color: var(--ok); background: var(--ok-soft); }
button.mini.bad { color: var(--bad); background: var(--bad-soft); }
button.mini:hover { filter: brightness(1.08); }
button.mini:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

td .chip + .chip { margin-left: 4px; }

/* ---------- справочники ---------- */

.inline-form { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0; }

input.tiny {
  width: 110px;
  padding: 5px 8px;
  font-family: var(--f-mono);
  font-size: 13px;
  background: var(--ground);
  color: var(--ink);
  border: 1px solid var(--line-strong);
  border-radius: 2px;
}

input.tiny.narrow { width: 62px; }
input.tiny:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }

table.refs td { vertical-align: middle; }
tr.just-saved { background: var(--ok-soft); }

code {
  font-family: var(--f-mono);
  font-size: .92em;
  background: var(--surface-2);
  border: 1px solid var(--line);
  padding: 1px 5px;
  border-radius: 2px;
}


/* --------------------------------------------------------------------------
   Журнал в виде лаборатории: разворот на все графы её файла.
   Таблица заведомо шире экрана — это нормально, у них она такая же и
   прокручивается вбок. Контейнер шире обычного, прокрутка внутри .table-scroll.
   -------------------------------------------------------------------------- */
main.wide { max-width: min(1800px, 96vw); }

.lab-head {
  display: flex;
  flex-wrap: wrap;
  gap: 18px 32px;
  padding: 14px 18px;
  margin: 0 0 18px;
  background: var(--surface-2);
  border: 1px solid var(--line);
}
.lab-head > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.lab-head > div.grow { flex: 1 1 320px; }
.lab-head-label {
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
.lab-head strong { font-weight: 600; }
.lab-head .dim { color: var(--muted); font-size: 13px; }
.warn-text { color: var(--warn); }

.equipment { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.equipment li { font-size: 13px; }
.equipment .dim { margin-left: 6px; font-family: var(--f-mono); font-size: 12px; }

.lab-journal { font-size: 13px; }
.lab-journal th {
  vertical-align: bottom;
  font-size: 11px;
  line-height: 1.25;
  white-space: nowrap;
}
.lab-journal th.age-group {
  text-align: center;
  background: var(--accent-soft);
  color: var(--accent);
  letter-spacing: .04em;
  border-left: 2px solid var(--line-strong);
}
.lab-journal th.sub {
  font-weight: 500;
  color: var(--muted);
  background: var(--surface-2);
}
.lab-journal td { vertical-align: top; }
.lab-journal td.small { font-family: var(--f-mono); font-size: 12px; line-height: 1.35; }
.lab-journal td.age-missing { text-align: center; color: var(--muted); font-style: italic; }


/* --------------------------------------------------------------------------
   Карточка объекта: шапка, показатели работы, хлебные крошки.
   -------------------------------------------------------------------------- */
.crumbs { margin: 0 0 6px; font-size: 13px; color: var(--muted); }
.crumbs a { color: var(--muted); }
.crumbs a:hover { color: var(--accent); }

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px;
  margin: 0 0 18px;
  background: var(--line);
  border: 1px solid var(--line);
}
.stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 14px;
  background: var(--surface);
}
.stat-label {
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
.stat-value { font-family: var(--f-display); font-size: 26px; line-height: 1; }
.stat-value.small { font-family: var(--f-body); font-size: 13px; line-height: 1.3; }
.stat.accent .stat-value { color: var(--accent); }
.stat.warn   .stat-value { color: var(--warn); }
.stat.bad    .stat-value { color: var(--bad); }

.object-actions { display: flex; gap: 14px; margin: 0 0 20px; }
.section-title {
  font-family: var(--f-display);
  font-size: 15px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 10px;
}

/* ------------------------------------------------------------------ */
/* Протокол испытаний. Бланк повторяет образец лаборатории построчно.  */
/* Печатают его на бумагу, поэтому размеры заданы в миллиметрах, а всё */
/* экранное (шапка сайта, кнопки) при печати убирается.                */
/* ------------------------------------------------------------------ */

.protocol-screen { max-width: 220mm; margin: 0 auto; }

.protocol-warn {
  border: 1px solid #d98324; background: #fff6ec; color: #7a4a12;
  padding: .7rem .9rem; border-radius: 6px; margin-bottom: .9rem;
}
.protocol-actions { display: flex; gap: .7rem; align-items: center; margin-bottom: 1rem; }

.protocol-sheet {
  width: 190mm; margin: 0 auto; padding: 6mm;
  background: #fff; color: #000;
  border: 2px solid #000;
  font-family: "Times New Roman", Times, serif; font-size: 10.5pt; line-height: 1.25;
}
.protocol-sheet table { width: 100%; border-collapse: collapse; }
.protocol-sheet td, .protocol-sheet th { border: 1px solid #000; padding: 1.5mm 2mm; vertical-align: top; }

/* Шапка: логотип слева, реквизиты по центру. */
.pr-head td { border: 1px solid #000; }
.pr-logo { width: 45mm; text-align: center; font-weight: 700; font-size: 9pt; letter-spacing: .5px; }
.pr-org { text-align: center; }
.pr-org-line { font-size: 10pt; }
.pr-org-name { font-size: 13pt; font-weight: 700; margin: .5mm 0; }
.pr-org-addr { font-size: 9pt; }

.pr-title td { text-align: center; font-weight: 700; font-size: 12pt; border-top: none; }
.pr-title .pr-num-label { width: 12mm; font-weight: 400; }
.pr-title .pr-num { width: 34mm; }

.pr-fields th { width: 55mm; text-align: left; font-weight: 700; }
.pr-fields .pr-class { font-size: 12pt; }
.pr-fields .pr-size { font-size: 9pt; }
.pr-conditions span { margin-right: 2mm; }
.pr-conditions strong { margin-right: 8mm; }

.protocol-sheet caption {
  caption-side: top; text-align: center; font-weight: 700;
  padding: 1.5mm 0; border: 1px solid #000; border-bottom: none;
}
.pr-equipment thead th, .pr-results thead th { text-align: center; font-weight: 700; }
.pr-n { width: 8mm; text-align: center; }

.pr-results .pr-colnums td { text-align: center; font-size: 9pt; }
.pr-results .pr-nd, .pr-results .pr-fact, .pr-results .pr-verdict { text-align: center; }
.pr-results .pr-class { font-weight: 700; }
.pr-results .pr-rt { font-size: 9.5pt; }

/* Блок проверки подлинности: QR слева, пояснение справа. Квадрат 20 мм —
   меньше не читается дешёвым телефоном при печати на обычном принтере. */
.pr-qr { display: flex; align-items: center; gap: 3mm; padding: 2mm;
         border: 1px solid #000; border-top: none; }
.pr-qr img { width: 20mm; height: 20mm; }
.pr-qr-text { font-size: 8pt; line-height: 1.35; }
.pr-qr-title { font-weight: 700; }
.pr-qr-url { font-family: monospace; word-break: break-all; }

.pr-notes { border: 1px solid #000; border-top: none; }
.pr-notes div { padding: 1.5mm 2mm; border-bottom: 1px solid #000; font-weight: 700; }
.pr-notes div:last-child { border-bottom: none; }

.pr-signs td { border: none; padding-top: 4mm; vertical-align: top; }
.pr-sign-left { width: 55%; }
.pr-sign-right { text-align: center; }
.pr-approve { font-weight: 700; margin-bottom: 3mm; }
.pr-sign-role { margin-top: 2mm; }
.pr-sign-name { margin-top: 6mm; white-space: nowrap; }
.pr-sign-line { display: inline-block; width: 38mm; border-bottom: 1px solid #000; margin: 0 2mm; }

.pr-footer { text-align: center; font-size: 9pt; margin-top: 5mm; }

.protocol-extra { margin-top: 1.5rem; }

@media print {
  .no-print, .topbar, .nav, .whoami { display: none !important; }
  body { background: #fff; }
  .protocol-sheet { border: 2px solid #000; margin: 0; width: auto; }
  /* Печать пачкой: каждый следующий бланк — с новой страницы. Первый разрыв
     не ставим, иначе печать начнётся с пустого листа. */
  .protocol-sheet + .protocol-sheet { page-break-before: always; }
  @page { size: A4 portrait; margin: 8mm; }
}

/* ------------------------------------------------------------------ */
/* Договор с заказчиком.                                              */
/* Цвет метки говорит быстрее слова: истёкший договор должен бросаться */
/* в глаза так же, как просроченная проба.                            */
/* ------------------------------------------------------------------ */

.contract-state {
  font-family: var(--f-mono); font-size: 11px; letter-spacing: .06em;
  text-transform: uppercase; padding: 2px 7px; border: 1px solid currentColor;
  border-radius: 2px; white-space: nowrap;
}
.contract-active   { color: #1a7f37; }
.contract-expiring { color: #b06a00; }
.contract-expired  { color: #b42318; }
.contract-unknown  { color: #5c6b84; }

/* В таблице договоров текст переносится: имя файла и примечание бывают
   длинными, а рвать их многоточием здесь нечего — строк мало. */
.contracts-table td { white-space: normal; }
.inline-form { display: inline; margin: 0; }

/* ------------------------------------------------------------------ */
/* Выбор объекта и полоса «где я работаю».                            */
/* Объект — контекст всей работы, поэтому он виден постоянно.         */
/* ------------------------------------------------------------------ */

.object-bar { background: #eef4ff; border-bottom: 1px solid #cbd9f0; }
.object-bar.empty { background: #fff6ec; border-bottom-color: #e5c69f; }
.object-bar-inner {
  max-width: 1180px; margin: 0 auto; padding: .5rem 1rem;
  display: flex; align-items: baseline; gap: .8rem; flex-wrap: wrap;
}
.object-bar-label { font-size: .82rem; color: #5c6b84; }
.object-bar-name { font-weight: 700; font-size: 1.02rem; color: #17324f; text-decoration: none; }
.object-bar-name:hover { text-decoration: underline; }
.object-bar-switch { margin-left: auto; font-size: .85rem; }

.select-screen { max-width: 900px; margin: 0 auto; }
.select-search { display: flex; gap: .6rem; margin: 1rem 0 1.4rem; flex-wrap: wrap; }
.select-search input[type="search"] { flex: 1 1 320px; padding: .6rem .8rem; font-size: 1rem; }
.select-search select { padding: .6rem .5rem; }

.object-cards { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
/* `display: grid` выше перебивал атрибут hidden, и выпадающий список
   раскрывался сам при загрузке страницы (08.09.2026). */
.object-cards[hidden], .object-card[hidden] { display: none; }
.object-card form { margin: 0; }
.object-card-btn {
  width: 100%; text-align: left; cursor: pointer;
  background: #fff; border: 1px solid #d8dee9; border-radius: 8px;
  padding: .75rem .9rem; display: grid; gap: .25rem;
  grid-template-columns: 1fr auto;
  grid-template-areas: "name enter" "customer enter" "stats enter";
  font: inherit;
}
.object-card-btn:hover { border-color: #7aa2e3; background: #f7faff; }
.object-card.has-late .object-card-btn { border-left: 4px solid #d64545; }
.object-card-name { grid-area: name; font-weight: 700; }
.object-card-customer { grid-area: customer; color: #5c6b84; font-size: .88rem; }
.object-card-stats { grid-area: stats; display: flex; gap: .35rem; flex-wrap: wrap; margin-top: .2rem; }
.object-card-enter { grid-area: enter; align-self: center; color: #2b6cb0; white-space: nowrap; }

.scope-switch {
  margin: -.4rem 0 1rem; font-size: .88rem; color: #5c6b84;
}
.scope-switch a { margin-left: .4rem; }
.orphan-note {
  border: 1px solid #e5c69f; background: #fff6ec; color: #7a4a12;
  padding: .6rem .8rem; border-radius: 6px; margin: 0 0 1rem;
}

/* Прихожая: поиск крупный, список закрыт до первого касания. */
.select-box { max-width: 720px; margin: 1.2rem auto 0; }
.select-box input[type="search"] {
  width: 100%; padding: .85rem 1rem; font-size: 1.05rem;
  border: 1px solid #c9d3e3; border-radius: 8px;
}
.select-box input[type="search"]:focus { outline: 2px solid #7aa2e3; border-color: #7aa2e3; }
.select-hint { color: #7a879c; font-size: .88rem; margin: .5rem .2rem 0; }
#object-list { margin-top: .8rem; max-height: 60vh; overflow-y: auto; }

.admin-links {
  max-width: 720px; margin: 2.4rem auto 0; padding-top: 1rem;
  border-top: 1px solid #e2e7f0; display: flex; gap: 1.2rem; align-items: baseline;
  flex-wrap: wrap;
}
.admin-links-title { color: #98a3b5; font-size: .82rem; text-transform: uppercase; letter-spacing: .04em; }
.admin-links a { font-size: .92rem; }

/* Правки после выпуска протокола: бумага у заказчика разошлась с базой. */
.alerts-block { border: 1px solid #d98324; border-radius: 8px; padding: .8rem 1rem; background: #fffaf4; }
.alerts-block .block-head h2 { color: #7a4a12; }
.count.bad { background: #d64545; color: #fff; }

.add-test { display: flex; gap: .4rem; align-items: center; flex-wrap: wrap; margin: .8rem 0; }
.add-test span { color: #5c6b84; font-size: .9rem; }

/* Кнопка «Новая проба»: заводится вручную, в том числе задним числом. */
.primary-link {
  display: inline-block; padding: .45rem .8rem; border-radius: 6px;
  background: #2b6cb0; color: #fff !important; text-decoration: none; font-size: .9rem;
}
.primary-link:hover { background: #245a94; }
main.narrow { max-width: 900px; margin: 0 auto; }

/* Пробы без объекта: показываем само сообщение прораба, а не счётчик. */
.orphans-block { border: 1px solid #d98324; border-radius: 8px; padding: .8rem 1rem; background: #fffaf4; }
.orphans-block .block-head h2 { color: #7a4a12; }
/* Сообщение прораба — единственная ячейка журнала, которую нужно читать
   целиком. Правило table.journal td ставит nowrap, и в таблице это верно:
   даты и числа рвать нельзя. Но по специфичности оно перебивало .orphan-msg,
   текст шёл одной строкой и рисовался ПОВЕРХ соседней колонки — ровно та
   «строка на строке», на которую пожаловался Рустам 02.09.2026.

   pre-line вместо pre-wrap: шаблон, введённый лабораторией 28.08.2026, идёт
   одной строкой с длинными цепочками пробелов между графами — pre-line их
   схлопывает, а настоящие переносы строк сохраняет. */
table.journal td.orphan-msg {
  white-space: pre-line;
  overflow-wrap: anywhere;
  font-size: .85rem;
  line-height: 1.35;
  max-width: 420px;
  min-width: 240px;
  color: #33414f;
}
.orphan-pick select { max-width: 220px; }
.orphan-pick form { display: flex; gap: .4rem; align-items: center; }

/* Печать до выпуска разрешена (выбор Рустама 05.09.2026), но лист обязан сам
   про себя сказать — и именно НА БУМАГЕ. Прежде предупреждение жило в блоке
   no-print, и официальный на вид бланк уходил заказчику без единой пометки. */
.preliminary-stamp {
  margin: 12px 0 0;
  padding: 8px 12px;
  border: 2px solid #b00020;
  color: #b00020;
  font-weight: 700;
  letter-spacing: .08em;
  text-align: center;
  text-transform: uppercase;
}

/* Аннулирование — действие, которое видит заказчик. Кнопка должна выглядеть
   опасной, а не как обычная. */
button.danger {
  background: #b00020;
  border-color: #b00020;
  color: #fff;
}
button.danger:hover { background: #8c0019; }

/* ---- аналитика объекта ---------------------------------------------- */
/* Полоски и столбики — обычные блоки с шириной в процентах: экран
   открывают с телефона на стройке, скрипты и библиотеки ему не нужны. */
.stat-note { font-size: 11px; color: var(--muted); line-height: 1.35; }
.crumbs-extra { margin: -6px 0 10px; }

.fill-list { display: flex; flex-direction: column; gap: 8px; }
.fill-row {
  display: grid;
  grid-template-columns: 160px 1fr 48px 120px;
  align-items: center;
  gap: 10px;
  font-size: 13px;
}
.fill-name { color: var(--ink); }
.fill-bar {
  display: block;
  height: 8px;
  background: var(--line);
  border-radius: 4px;
  overflow: hidden;
}
.fill-bar.small { width: 90px; display: inline-block; vertical-align: middle; }
.fill-done { display: block; height: 100%; background: var(--accent); }
.fill-num { text-align: right; font-variant-numeric: tabular-nums; }
.fill-num.warn { color: var(--warn); }
.fill-note { font-size: 12px; }

.rhythm {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  height: 170px;
  padding: 8px 0 0;
  overflow-x: auto;
}
.rhythm-col {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  gap: 4px;
  min-width: 34px;
  height: 100%;
}
.rhythm-bar {
  display: block;
  width: 100%;
  min-height: 2px;
  background: var(--accent);
  border-radius: 3px 3px 0 0;
}
.rhythm-num { font-size: 11px; font-variant-numeric: tabular-nums; }
.rhythm-day { font-size: 10px; color: var(--muted); white-space: nowrap; }

@media (max-width: 640px) {
  .fill-row { grid-template-columns: 120px 1fr 44px; }
  .fill-note { display: none; }
}

/* ---- очередь проверки ------------------------------------------------ */
/* Причина словами, а не значками: человек должен понять строку с одного
   взгляда, не расшифровывая пометки. */
.reason-cell { max-width: 460px; }
.reason-cell .chip { white-space: normal; }

/* Замечания в карточке пробы: важное — красным, прочее — спокойным. */
.attention-list { margin: 0; padding-left: 18px; }
.attention-list li { margin: 4px 0; }
.attention-bad  { color: var(--bad); }
.attention-warn { color: var(--warn); }
.attention-info { color: var(--muted); }
.attention-ok   { color: var(--ok); }

/* Сообщение из группы разворачивается прямо в строке — без перехода. */
.full-text { white-space: pre-wrap; margin-top: 6px; }
.raw-text details summary { cursor: pointer; }
.linklike { color: var(--accent); }

/* ---- прихожая: сводка по лаборатории --------------------------------- */
/* Администратор видит всю лабораторию сразу, не заходя в каждую стройку. */
.select-new { margin: 10px 0 0; font-size: 13px; color: var(--muted); }
.select-new a { color: var(--accent); }
.lab-summary { margin: 32px 0 8px; }
.lab-summary h2 { font-size: 16px; margin: 0 0 12px; }
.lab-summary .stats { margin-bottom: 16px; }

/* ---- поле выбора объекта со стрелкой ---------------------------------- */
/* Стрелка живёт внутри поля: человек ищет список там же, где вводит имя. */
.select-field { position: relative; }
.select-field input { width: 100%; padding-right: 44px; }
.select-arrow {
  position: absolute;
  top: 0;
  right: 0;
  height: 100%;
  width: 40px;
  border: 0;
  background: none;
  color: var(--muted);
  font-size: 18px;
  cursor: pointer;
}
.select-arrow:hover { color: var(--accent); }
/* Заведение стройки — первой строкой списка, но не спутать с объектом. */
.object-card-add { border-left: 3px solid var(--accent); }
.object-card-add .object-card-name { color: var(--accent); }

/* Выпадающее окно списка: ложится поверх страницы и не двигает сводку. */
.select-field .object-cards {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 6px);
  z-index: 30;
  max-height: 60vh;
  overflow-y: auto;
  margin: 0;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 12px 28px rgba(0, 0, 0, .14);
}
.select-field .empty {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 6px);
  z-index: 30;
  padding: 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
}

/* Плитка-ссылка: нажал число — увидел, из чего оно сложилось. */
a.stat { text-decoration: none; color: inherit; transition: background .12s; }
a.stat:hover { background: var(--accent-soft); }
a.stat .stat-label { text-decoration: none; }

/* Строка-ссылка: целятся в строку, а не в двенадцать букв названия. */
tr.row-link { cursor: pointer; }
tr.row-link:hover { background: var(--accent-soft); }

/* Сообщение прораба переносится по словам и не растягивает таблицу:
   «Temperatura 33,5» уезжала за край экрана (08.09.2026). */
.msg-cell {
  max-width: 34ch;
  white-space: normal;
  word-break: break-word;
  line-height: 1.35;
}

/* Таблица «стройки ждут проверки»: доли колонок заданы, иначе длинное
   сообщение прораба растягивает её шире экрана, а кнопки наезжают на текст
   (08.09.2026). */
.objects-wait { table-layout: fixed; width: 100%; }
.objects-wait th:nth-child(1), .objects-wait td:nth-child(1) { width: 22%; }
.objects-wait th:nth-child(2), .objects-wait td:nth-child(2) { width: 7%; }
.objects-wait th:nth-child(3), .objects-wait td:nth-child(3) { width: 13%; }
.objects-wait th:nth-child(4), .objects-wait td:nth-child(4) { width: 33%; }
.objects-wait th:nth-child(5), .objects-wait td:nth-child(5) { width: 25%; }
/* Общее правило `table.journal td { white-space: nowrap }` сильнее
   класса `.msg-cell`, поэтому перенос разрешаем здесь — на той же
   специфичности, но ниже по файлу. */
table.journal.objects-wait td {
  vertical-align: top;
  white-space: normal;
  word-break: break-word;
}
/* Действия — столбиком: «подтвердить» и «слить» это разные решения. */
.objects-wait .actions-cell { display: flex; flex-direction: column; gap: 6px; align-items: stretch; }
.objects-wait .actions-cell form { display: flex; gap: 6px; flex-wrap: wrap; }
.objects-wait .actions-cell select { max-width: 100%; }

/* Печать пачкой: причина, объяснение и ссылка в одной строке. */
table.journal.blocked-table td { white-space: normal; vertical-align: top; }
.gap-row { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; margin: 3px 0; }

/* Поле, к которому пришли по ссылке: видно, куда смотреть. */
.field-called {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  background: var(--accent-soft);
}
