:root{
  --bg:#f6f7f9; --panel:#fff; --line:#e3e6ea; --ink:#151a21; --muted:#6b7480;
  --accent:#2b5fd9; --accent-soft:#eaf0ff; --danger:#c0362c; --danger-soft:#fdecea;
  --ok:#1c7a4a; --warn:#8a6100; --warn-soft:#fff6e0;
  --row:#fff; --row-alt:#fafbfc; --shadow:0 8px 30px rgba(16,22,32,.14);
  --field:#fff; --field-line:#c8ced6; --scroll:#c4cad3;
  /* Высота ячейки с фото в таблице элементов. Ширину каждая ячейка берёт из
     пропорций своего кадра — см. .thumb. */
  --photo-h:120px;
}
@media (prefers-color-scheme:dark){
  :root{
    --bg:#14181d; --panel:#1b2027; --line:#2b323b; --ink:#e6eaef; --muted:#98a2ae;
    --accent:#6c9bff; --accent-soft:#1e2a45; --danger:#ff8479; --danger-soft:#3a1e1b;
    --ok:#5fd39b; --warn:#e0b45c; --warn-soft:#3a2f16;
    --row:#1b2027; --row-alt:#1f252d; --shadow:0 8px 30px rgba(0,0,0,.5);
    --field:#12161b; --field-line:#3a434f; --scroll:#39424e;
  }
}
*{box-sizing:border-box}
[hidden]{display:none !important}
html,body{height:100%}
body{
  margin:0; background:var(--bg); color:var(--ink);
  font:14px/1.45 -apple-system,BlinkMacSystemFont,"Segoe UI",Inter,Roboto,sans-serif;
  display:flex; flex-direction:column;
}
#view-list,#view-project,#view-admin{flex:1; min-height:0; display:flex; flex-direction:column}
#pane-overview{overflow:auto; display:block}

/* ---- полосы прокрутки ----
   Системные в тёмной теме выглядят чужеродно и занимают много места.
   Тонкие, полупрозрачные, проявляются при наведении. */
*{scrollbar-width:thin; scrollbar-color:var(--scroll) transparent}
*::-webkit-scrollbar{width:10px; height:10px}
*::-webkit-scrollbar-track{background:transparent}
*::-webkit-scrollbar-thumb{
  background:var(--scroll); border-radius:8px;
  border:3px solid transparent; background-clip:content-box;
}
*::-webkit-scrollbar-thumb:hover{border-width:2px}
*::-webkit-scrollbar-corner{background:transparent}

/* ---- шапка ---- */
.top{
  display:flex; align-items:center; gap:16px; padding:10px 16px;
  background:var(--panel); border-bottom:1px solid var(--line); flex:none;
}
.brand{font-weight:650; letter-spacing:.2px; white-space:nowrap}
.search{flex:1; max-width:620px}
.search input{
  width:100%; padding:7px 12px; border:1px solid var(--field-line); border-radius:8px;
  background:var(--field); color:var(--ink); font:inherit;
}
.search input:focus{outline:2px solid var(--accent-soft); border-color:var(--accent)}
.who{display:flex; align-items:center; gap:8px; margin-left:auto}
.badge{
  padding:3px 9px; border-radius:99px; background:var(--accent-soft);
  color:var(--accent); font-size:12px; font-weight:600; white-space:nowrap;
}

/* ---- вкладки ---- */
.tabs{
  display:flex; align-items:flex-end; gap:4px; padding:8px 16px 0;
  background:var(--panel); flex:none; border-bottom:1px solid var(--line);
}
.tabs-inner{display:flex; gap:4px}
.tab{
  padding:8px 16px; border:0; border-radius:8px 8px 0 0; background:transparent;
  color:var(--muted); font:inherit; font-weight:550; cursor:pointer; margin-bottom:-1px;
}
.tab:hover{color:var(--ink); background:var(--bg)}
.tab[aria-selected="true"]{
  background:var(--bg); color:var(--ink); box-shadow:inset 0 -2px 0 var(--accent);
}
.tab .n{
  display:inline-block; margin-left:7px; padding:0 6px; border-radius:99px;
  background:var(--line); color:var(--muted); font-size:11.5px; font-weight:600;
}
.tab[aria-selected="true"] .n{background:var(--accent); color:#fff}
button.new{margin:0 0 6px 8px; padding:6px 14px}
#filters-btn{margin:0 0 6px auto; padding:6px 14px}
#filters-btn.on{border-color:var(--accent); color:var(--accent)}

/* ---- фильтры ---- */
.filters{
  display:flex; flex-wrap:wrap; gap:10px; align-items:center;
  padding:12px 16px; background:var(--panel); border-bottom:1px solid var(--line);
}
.filters select{min-width:150px; max-width:230px; padding:6px 9px}
.filters .reset{margin-left:auto}
.list-foot{
  display:flex; align-items:center; gap:12px; justify-content:center;
  padding:12px 0 2px; color:var(--muted); font-size:13px; flex:none;
}
.saved{margin-left:auto; color:var(--muted); font-size:12.5px; padding-bottom:8px; transition:color .15s}
.saved.flash{color:var(--ok); font-weight:600}
.tabs .primary{margin:0 0 6px 10px; padding:6px 16px}

main{flex:1; min-height:0; display:flex; flex-direction:column; padding:12px 16px 16px}
.state{padding:24px 4px; color:var(--muted)}
.state.hide{display:none}

/* ---- таблица ---- */
.table-wrap{
  flex:1; min-height:0; overflow:auto; background:var(--panel);
  border:1px solid var(--line); border-radius:10px;
}
table{border-collapse:separate; border-spacing:0; width:max-content; min-width:100%}
th,td{
  padding:8px 12px; text-align:left; white-space:nowrap; border-bottom:1px solid var(--line);
  max-width:280px; overflow:hidden; text-overflow:ellipsis;
}
thead th{
  position:sticky; top:0; z-index:2; background:var(--panel); color:var(--muted);
  font-size:11.5px; font-weight:650; text-transform:uppercase; letter-spacing:.4px;
}
tbody tr{background:var(--row); cursor:pointer}
tbody tr:nth-child(even){background:var(--row-alt)}
tbody tr:hover{background:var(--accent-soft)}
td.num{text-align:right; font-variant-numeric:tabular-nums}
td.muted{color:var(--muted)}
.pill{
  display:inline-block; padding:1px 8px; border-radius:99px;
  font-size:12px; font-weight:600; background:var(--line); color:var(--muted);
}
.pill.ok{background:color-mix(in srgb,var(--ok) 18%,transparent); color:var(--ok)}
.pill.warn{background:var(--warn-soft); color:var(--warn)}
.pill.off{background:var(--line); color:var(--muted)}
.stop{
  display:inline-block; margin-right:6px; padding:1px 7px; border-radius:5px;
  background:var(--danger-soft); color:var(--danger); font-size:11px; font-weight:700;
}
td.img{padding:2px 6px}
img.cover{width:38px; height:38px; border-radius:6px; object-fit:cover; display:block}

/* ---- страница проекта ---- */
.p-head{
  display:flex; align-items:flex-start; gap:14px; padding:12px 16px 10px;
  background:var(--panel); flex:none;
}
.p-title{min-width:0; flex:1}
.p-title h1{margin:0; font-size:17px; font-weight:650; line-height:1.3}
.p-sub{color:var(--muted); font-size:13px; margin-top:3px}
.p-actions{display:flex; flex-wrap:wrap; gap:8px; justify-content:flex-end}
button.back{flex:none}

/* Обычный поток, а не флекс-колонка: во флексе блоки сводки сжимались
   до нулевой высоты, потому что всё место забирала сетка полей. */
/* Баннеры живут под шапкой, а не внутри вкладки: причина, по которой
   кнопка неактивна, нужна и на вкладке с таблицей. */
#p-banners{padding:0 16px; background:var(--panel)}
#p-banners:empty{display:none}
#p-banners .banner{margin:0 0 10px}

#pane-card{overflow:auto; display:block}
#pane-card > *{width:100%; max-width:1280px; margin-left:auto; margin-right:auto}

/* ---- сводка: то, ради чего открывают карточку ----
   Крупные цифры вместо строки в общем ряду: глаз находит их сразу,
   не читая подписи. */
.summary{
  display:flex; flex-wrap:wrap; gap:1px;
  background:var(--line); border:1px solid var(--line);
  border-radius:12px; overflow:hidden; margin-bottom:16px;
}
/* Ячейки тянутся и заполняют строку: одинокая «сирота» на второй строке
   растягивается, а не оставляет пустой блок. */
.summary .cell{background:var(--panel); padding:12px 16px 13px; flex:1 1 150px; min-width:0}
.summary .s{color:var(--muted); font-size:12px; margin-top:3px}
.summary .k{color:var(--muted); font-size:11.5px; margin-bottom:5px}
.summary .v{font-size:19px; font-weight:600; font-variant-numeric:tabular-nums; line-height:1.2}
.summary .v.small{font-size:15px; font-weight:550}
.summary .v.dim{color:var(--muted); font-weight:400}
.summary .cell.accent .v{color:var(--accent)}
.summary .cell.danger .v{color:var(--danger)}

.card-toolbar{display:flex; justify-content:flex-end; margin-bottom:10px}
.toggle{
  display:inline-flex; align-items:center; gap:7px;
  color:var(--muted); font-size:12.5px; cursor:pointer;
}
.toggle input{width:15px; height:15px; padding:0; accent-color:var(--accent); cursor:pointer}

.form-grid{
  display:grid; grid-template-columns:repeat(auto-fill,minmax(520px,1fr));
  gap:16px; align-content:start; padding-bottom:24px;
}
.group{
  background:var(--panel); border:1px solid var(--line); border-radius:12px;
  padding:4px 18px 12px;
}
.group h3{
  margin:0; padding:13px 0 10px; font-size:13px; font-weight:650;
  color:var(--ink); border-bottom:1px solid var(--line);
}
/* Разделители между строками: без них подписи сливаются в стену текста. */
.row{
  display:grid; grid-template-columns:minmax(150px,38%) 1fr; gap:16px;
  padding:9px 0; align-items:center; border-bottom:1px solid var(--line);
}
.group .row:last-child{border-bottom:0}
.row > label{color:var(--muted); font-size:13px; line-height:1.35}
.row .val{
  min-width:0; word-break:break-word; white-space:pre-wrap;
  font-weight:500; font-variant-numeric:tabular-nums;
}
.row .val.empty{color:var(--muted); font-weight:400}
/* Пустые нередактируемые строки и целиком пустые группы скрыты,
   пока не включён переключатель. */
.row[data-empty]{display:none}
.group[data-empty]{display:none}
html.show-empty .row[data-empty]{display:grid}
html.show-empty .group[data-empty]{display:block}
.row.tall{align-items:start}
.row.tall > label{padding-top:9px}

/* ---- поля ввода ----
   Главное: заполняемое поле должно быть видно как поле. Без рамки и фона
   человек не понимает, что сюда можно писать. */
input,select,textarea{
  font:inherit; color:var(--ink); background:var(--field);
  border:1px solid var(--field-line); border-radius:7px; padding:7px 10px;
}
.row input,.row select,.row textarea{width:100%}
.row textarea{min-height:64px; resize:vertical}
input:hover,select:hover,textarea:hover{border-color:var(--accent)}
input:focus,select:focus,textarea:focus{
  outline:2px solid var(--accent-soft); border-color:var(--accent);
}
input[type="date"]{min-height:34px}
select{cursor:pointer}

.primary{
  padding:7px 16px; border:0; border-radius:8px; background:var(--accent); color:#fff;
  font:inherit; font-weight:600; cursor:pointer;
}
.primary:disabled{opacity:.4; cursor:default}
/* Не button.ghost, а .ghost: тот же вид нужен и ссылке в шапке. */
.ghost{
  padding:7px 13px; border:1px solid var(--field-line); border-radius:8px;
  background:var(--panel); color:var(--ink); font:inherit; font-weight:550; cursor:pointer;
}
.ghost:hover{border-color:var(--accent); color:var(--accent)}
a.ghost{text-decoration:none; display:inline-block; white-space:nowrap}

.banner{
  margin:0 0 14px; padding:10px 13px; border-radius:9px;
  background:var(--danger-soft); color:var(--danger); font-weight:600; font-size:13px;
}
.banner.warn{background:var(--warn-soft); color:var(--warn); font-weight:500}
.banner.info{background:var(--accent-soft); color:var(--ink); font-weight:400}

/* ---- элементы ---- */
.el-bar{display:flex; align-items:center; gap:10px; padding:0 0 12px}
.el-files{display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin-right:auto}
.el-files .sep{width:1px; height:22px; background:var(--line); margin:0 4px}
.bar-hint{color:var(--muted); font-size:13px}
.el-foot{padding:10px 2px; color:var(--muted); font-size:13px}
#el-grid th,#el-grid td{padding:3px 6px; font-size:13px}
#el-grid tbody tr{cursor:default}
#el-grid tbody tr:hover{background:var(--row)}
#el-grid tbody tr:nth-child(even):hover{background:var(--row-alt)}
th.zone{
  text-align:left; border-bottom:1px solid var(--line);
  background:var(--accent-soft); color:var(--accent); font-size:11px;
}
/* Зона шириной в 23 колонки: подпись липнет к левому краю, иначе при
   горизонтальной прокрутке она уезжает за экран и не видно, где ты. */
th.zone span{position:sticky; left:12px; display:inline-block}
th.zone.collapsed{text-align:center}
th.collapsed,td.collapsed{width:34px; min-width:34px; text-align:center; color:var(--muted)}
th.zone.z-FACTORY{background:var(--warn-soft); color:var(--warn)}
th.zone.z-EXECUTOR{background:color-mix(in srgb,var(--ok) 14%,transparent); color:var(--ok)}
#el-grid thead tr:first-child th{top:0}
#el-grid thead tr:last-child th{top:24px}

/* Ячейка-поле: видно, что в неё пишут. */
.cell-in{
  width:100%; min-width:76px; padding:4px 7px; border-radius:6px;
  border:1px solid var(--field-line); background:var(--field);
}
select.cell-in{min-width:120px}
/* Обязательное и пустое: видно прямо в таблице, а не только в тексте сверху. */
.cell-in.required{border-color:var(--danger); background:var(--danger-soft)}
.cell-in.required::placeholder{color:var(--danger); opacity:.75}
td.calc{
  color:var(--muted); text-align:right; font-variant-numeric:tabular-nums;
  background:var(--row-alt);
}
td.pos{position:sticky; left:0; z-index:1; background:var(--panel); font-weight:600; text-align:center}
button.del{border:0; background:transparent; color:var(--muted); cursor:pointer; font-size:15px}
button.del:hover{color:var(--danger)}
/* Ячейка с картинкой подстраивается под кадр.
   Высота задана, ширину диктует само фото: вертикальный снимок даёт узкую
   ячейку, горизонтальный — широкую. Раньше здесь был жёсткий квадрат 44px с
   object-fit:cover, и у горизонтального кадра срезало треть ширины — это и
   читалось как «плохое качество», хотя резкость была ни при чём. */
.thumb{
  height:var(--photo-h, 120px);
  width:auto; min-width:44px; max-width:calc(var(--photo-h, 120px) * 1.8);
  border-radius:6px; overflow:hidden; cursor:pointer;
  display:flex; align-items:center; justify-content:center; background:var(--field);
  border:1px solid var(--field-line);
}
/* contain, а не cover: показываем кадр целиком, ничего не срезая. */
.thumb img{
  width:auto; height:100%; max-width:100%; object-fit:contain; display:block;
}
/* Пока фото не загрузилось, ширина неизвестна — держим место, чтобы колонка
   не прыгала на глазах. */
.thumb:not(.empty){min-width:calc(var(--photo-h, 120px) * .75)}
.thumb.empty{
  width:44px; height:44px; color:var(--muted); font-size:18px; border-style:dashed;
}
.thumb.empty:hover{border-color:var(--accent); color:var(--accent)}
.thumb.busy{opacity:.4}

/* ---- фабрики на запросе ----
   Карточки в ряд, а не таблица: сравнивают их глазами, и цифр немного.
   Подсветки «самой дешёвой» здесь намеренно нет — выбор не по одному числу. */
#el-factories{
  display:flex; flex-wrap:wrap; gap:10px; align-items:flex-start;
  padding:0 16px 12px;
}
.fx-head{
  flex-basis:100%; display:flex; align-items:center; gap:10px;
  font-size:13px; color:var(--muted);
}
.fx{
  flex:1 1 260px; max-width:360px; padding:10px 12px;
  border:1px solid var(--line); border-radius:10px; background:var(--panel);
  display:flex; flex-direction:column; gap:7px;
}
.fx-win{border-color:var(--ok); box-shadow:0 0 0 1px var(--ok) inset}
.fx-name{font-weight:650; font-size:14px}
.fx-state{font-size:12px; color:var(--muted)}
.fx-nums{display:flex; flex-wrap:wrap; gap:4px 14px; font-variant-numeric:tabular-nums}
.fx-nums span{font-size:14px; font-weight:600}
.fx-nums i{display:block; font-style:normal; font-size:11px; font-weight:400; color:var(--muted)}
.fx-note{width:100%; font-size:12px}
.fx-acts{display:flex; flex-wrap:wrap; gap:6px; margin-top:2px}
.fx-acts button{padding:5px 10px; font-size:12px}
.dlg-pick{width:100%; margin:12px 0 4px}
/* Форма внутри диалога: подпись над полем — так читается быстрее, чем в строку. */
.dlg-form{display:flex; flex-direction:column; gap:10px; margin:14px 0 4px}
.dlg-row{display:flex; flex-direction:column; gap:4px}
.dlg-row > span{font-size:12px; color:var(--muted)}
.dlg-row .cell-in{width:100%}
/* Логин и пароль: показываются один раз, поэтому крупно и с кнопкой копирования. */
.creds{display:flex; flex-direction:column; gap:8px; margin:14px 0 4px}
.creds-note{font-size:12px; color:var(--muted); line-height:1.5}
.creds-value{
  width:100%; font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:15px; font-weight:600;
}
/* Колонка выбора строк в реестре. Узкая и по центру: она служебная и не
   должна тянуть на себя внимание. */
th.pick, td.pick{width:34px; text-align:center; padding-left:10px; padding-right:4px}
td.pick input, th.pick input{cursor:pointer; margin:0}

/* ---- удаление проекта ----
   Отдельным блоком внизу карточки: наверху живут ходы по работе, и
   необратимому действию рядом с ними не место. */
.danger-zone{border-color:var(--danger)}
.danger-zone h3{color:var(--danger)}
.danger-note{margin:0 0 10px; color:var(--muted); font-size:13px; line-height:1.5}
button.danger{
  border:1px solid var(--danger); background:transparent; color:var(--danger);
  padding:7px 14px; border-radius:8px; cursor:pointer; font-size:13px; font-weight:600;
}
button.danger:hover{background:var(--danger); color:#fff}

.banner-go{margin-left:10px; padding:3px 10px; font-size:12px; vertical-align:1px}
/* Сортировка реестра. Стрелка только у активной колонки: значок у всех
   пятнадцати превратил бы шапку в частокол. */
th.sortable{cursor:pointer; user-select:none}
th.sortable:hover{color:var(--accent)}
th.sorted{color:var(--accent)}
th.sorted::after{content:' ↓'; font-size:11px}
th.sorted.asc::after{content:' ↑'}
/* Куда именно вела подсказка — видно секунду, чтобы взгляд зацепился. */
.row-hi{
  outline:2px solid var(--accent); outline-offset:3px; border-radius:6px;
  transition:outline-color .4s;
}

/* ---- подтверждение ----
   Свой диалог вместо системного confirm(): браузер его подавляет, если
   человек однажды выбрал «блокировать диалоги», и удаление тогда молча
   отменяется — выглядит как «кнопка не работает». */
#ask-dlg{
  border:1px solid var(--line); border-radius:12px; padding:20px 22px 16px;
  max-width:420px; background:var(--panel); color:var(--ink); box-shadow:var(--shadow);
}
#ask-dlg::backdrop{background:rgba(10,14,20,.45)}
.ask-text{font-size:15px; line-height:1.5; margin-bottom:4px}

/* ---- диалог нового проекта ---- */
#new-dlg{
  border:1px solid var(--line); border-radius:12px; padding:0; max-width:560px; width:92%;
  background:var(--panel); color:var(--ink); box-shadow:var(--shadow);
}
#new-dlg::backdrop{background:rgba(10,14,20,.45)}
#new-form{padding:18px 20px 16px}
#new-form h2{margin:0 0 14px; font-size:17px}
.dlg-foot{display:flex; justify-content:flex-end; gap:8px; margin-top:18px}
#new-fields .row{grid-template-columns:170px 1fr}
.hint{color:var(--muted); font-size:12px; margin-top:8px; line-height:1.45}

/* ---- вход ---- */
body.auth{align-items:center; justify-content:center; padding:20px}
.auth-box{
  width:100%; max-width:380px; padding:26px 26px 22px; border-radius:14px;
  background:var(--panel); border:1px solid var(--line); box-shadow:var(--shadow);
  flex:none; display:block;
}
.auth-box h1{margin:0 0 18px; font-size:19px}
.auth-box .lead{margin:0 0 16px; color:var(--muted); font-size:13px; line-height:1.5}
.auth-box label{display:block; margin-bottom:12px; color:var(--muted); font-size:12.5px}
.auth-box input{width:100%; margin-top:5px; padding:9px 11px}
.auth-box button{width:100%; margin-top:6px; padding:10px}
.err{color:var(--danger); font-size:13px; min-height:18px; margin:2px 0 6px}

/* ---- администрирование ---- */
.off-row{opacity:.5}
.chip{
  display:inline-block; padding:1px 8px; border-radius:99px; font-size:11.5px;
  font-weight:600; background:var(--line); color:var(--muted);
}
.chip.on{background:color-mix(in srgb,var(--ok) 18%,transparent); color:var(--ok)}
.chip.wait{background:var(--warn-soft); color:var(--warn)}
#a-status-list{
  margin-top:16px; background:var(--panel); border:1px solid var(--line);
  border-radius:12px; padding:4px 18px 12px; max-width:1280px;
}
td .act{border:0; background:transparent; color:var(--accent); cursor:pointer; font:inherit; padding:0 6px}
td .act:hover{text-decoration:underline}
td .act.danger{color:var(--danger)}

/* ---- всплывающие сообщения ----
   alert() блокирует страницу и теряет контекст: человек не видит, к какой
   строке относится замечание. */
.toasts{
  position:fixed; right:16px; bottom:16px; z-index:50;
  display:flex; flex-direction:column; gap:8px; max-width:min(460px,92vw);
}
.toast{
  padding:11px 14px; border-radius:10px; box-shadow:var(--shadow);
  background:var(--panel); border:1px solid var(--line); color:var(--ink);
  font-size:13.5px; line-height:1.45; white-space:pre-wrap;
  animation:toast-in .16s ease-out;
}
.toast.err{border-color:var(--danger); background:var(--danger-soft); color:var(--danger)}
.toast.ok{border-color:var(--ok); background:color-mix(in srgb,var(--ok) 12%,var(--panel))}
.toast .x{float:right; margin-left:12px; cursor:pointer; opacity:.55}
.toast .x:hover{opacity:1}
@keyframes toast-in{from{opacity:0; transform:translateY(6px)}to{opacity:1; transform:none}}

/* ---- узкое окно ----
   Не мобильная вёрстка: телефон не поддерживаем сознательно. Это про
   десктоп в половину экрана — так работают, когда рядом открыт Excel. */
@media (max-width:900px){
  .top{flex-wrap:wrap; gap:8px 12px; padding:8px 12px}
  .search{order:3; flex-basis:100%; max-width:none}
  .brand{font-size:14px}
  main{padding:10px 12px 12px}
  .tabs{padding:6px 12px 0; overflow-x:auto}
  .tab{padding:7px 12px; white-space:nowrap}
  .p-head{flex-wrap:wrap; padding:10px 12px 8px}
  .p-actions{width:100%; justify-content:flex-start}
  .form-grid{grid-template-columns:1fr; gap:12px}
  .row{grid-template-columns:1fr; gap:4px; padding:8px 0}
  .row > label{font-size:12px}
  .row.tall > label{padding-top:0}
  .summary .cell{flex-basis:120px; padding:10px 12px}
  .summary .v{font-size:17px}
  .filters{padding:10px 12px}
  .filters select{min-width:0; flex:1 1 140px; max-width:none}
  #pane-card > *{max-width:none}
  .toasts{left:12px; right:12px; bottom:12px; max-width:none}
  /* В узком окне таблица и так тесная: фото поменьше, иначе строки
     превращаются в простыню и таблицу приходится листать вдвое дольше. */
  :root{--photo-h:76px}
}
