/* Язык облика — из §12 архитектуры: один графит, один синий, тёплый контровой
   отсвет снизу, плотность по краям и воздух в центре. Шрифт только моноширинный
   и только системный: машина работает без сети, качать нечего. */
:root{
  --ink:#07080a;            /* почти-чёрный, не #000 */
  --ink-2:#0b0d11;
  --line:#171b22;
  --dim:#4a5566;
  --text:#93a0b3;
  --bright:#d6dde8;
  --blue:#3d7ff2;           /* единственный акцент */
  --blue-dim:rgba(61,127,242,.22);
  --warm:#c8783a;           /* контровой свет комнаты, только свечением */
  --mono:ui-monospace,"Cascadia Mono","Consolas","JetBrains Mono",monospace;
}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{
  background:var(--ink);
  color:var(--text);
  font:400 12px/1.5 var(--mono);
  font-variant-numeric:tabular-nums;
  letter-spacing:.02em;
  overflow:hidden;
}
/* тёплый отсвет снизу — единственное тёплое пятно на экране */
body::after{
  content:"";position:fixed;inset:auto 0 -18vh 0;height:44vh;pointer-events:none;
  background:radial-gradient(60% 100% at 50% 100%,rgba(200,120,58,.16),transparent 70%);
}
body::before{
  content:"";position:fixed;inset:0;pointer-events:none;opacity:.5;
  background:repeating-linear-gradient(180deg,transparent 0 3px,rgba(255,255,255,.012) 3px 4px);
}

.room{position:relative;height:100dvh;display:grid;
  grid-template-columns:minmax(220px,17vw) 1fr minmax(220px,17vw);
  grid-template-rows:auto 1fr auto;
  gap:0 clamp(16px,4vw,72px);padding:18px clamp(16px,2.4vw,34px) 20px}
.core{position:fixed;inset:0;width:100%;height:100%;z-index:0}

.bar{grid-column:1/-1;display:flex;align-items:center;gap:10px;z-index:1}
.mark{color:var(--bright);letter-spacing:.34em;font-size:11px}
.sep{color:var(--line)}
.link{font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--dim)}
.link::before{content:"";display:inline-block;width:5px;height:5px;margin-right:7px;
  border-radius:50%;background:var(--dim);vertical-align:middle}
.link[data-ok="1"]{color:var(--text)}
.link[data-ok="1"]::before{background:var(--blue);box-shadow:0 0 10px var(--blue)}
.link[data-ok="0"]::before{background:var(--warm);box-shadow:0 0 10px rgba(200,120,58,.6)}

.col{z-index:1;display:flex;flex-direction:column;gap:26px;min-height:0;padding-top:26px}
.col-r{grid-column:3}
.col-r .block h2,.col-r .list{text-align:right}
.block{min-height:0;display:flex;flex-direction:column}
.block.grow{flex:1;overflow:hidden}
h2{font:400 10px/1 var(--mono);letter-spacing:.22em;text-transform:uppercase;
  color:var(--dim);padding-bottom:9px;border-bottom:1px solid var(--line);margin-bottom:11px}
h2 b{font-weight:400;color:var(--blue)}

/* dt и dd лежат парами в потоке: любой order здесь развалит строки на
   «все подписи, потом все значения» — проверено рендером. */
.rows{display:grid;grid-template-columns:auto 1fr;gap:5px 14px;align-items:baseline}
.rows dt{color:var(--dim);font-size:11px;text-align:left}
.rows dd{color:var(--bright);font-size:11px;text-align:right}

.list{list-style:none;overflow-y:auto;overscroll-behavior:contain;
  display:flex;flex-direction:column;gap:11px;padding-right:2px}
.list::-webkit-scrollbar{width:2px}
.list::-webkit-scrollbar-thumb{background:var(--line)}
.list li{font-size:11px;line-height:1.45}
.list .t{color:var(--bright);display:block;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.list .m{color:var(--dim);font-size:10px;letter-spacing:.06em}
.list .m i{font-style:normal;color:var(--blue)}
.list li[data-live="1"] .t{color:#fff}
.list li[data-live="1"] .m i{color:var(--warm)}
.empty{color:var(--line);font-size:11px}

/* Терминал: настоящие вызовы инструментов, самый свежий сверху. Строки гаснут
   вниз по возрасту — так видно, где кончилась работа, без единой анимации. */
.term{list-style:none;display:flex;flex-direction:column;gap:3px;overflow:hidden}
.term li{font-size:10.5px;line-height:1.4;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;color:var(--dim)}
.term li:nth-child(1){color:var(--text)}
.term li:nth-child(n+5){opacity:.62}
.term li:nth-child(n+7){opacity:.4}
.term .ts{color:var(--dim);opacity:.6}
.term .tool{color:var(--blue)}
.term li:nth-child(1) .tool{color:var(--bright)}
.term .arg{color:var(--dim)}

/* центр: воздух, ядро и приборы */
.stage{grid-column:2;grid-row:2;z-index:1;align-self:end;justify-self:center;
  display:flex;flex-direction:column;align-items:center;gap:12px;padding-bottom:2vh;text-align:center}
.state{font-size:11px;letter-spacing:.42em;text-transform:uppercase;color:var(--blue);
  text-shadow:0 0 18px var(--blue-dim)}
.clock{color:var(--bright);font-size:clamp(26px,3.4vw,44px);letter-spacing:.06em;line-height:1}
.clock i{font-style:normal;font-size:.42em;color:var(--dim);margin-left:4px;letter-spacing:.1em}
.pulse{width:min(46vw,420px);height:34px;opacity:.9}

/* карта миссии: ярусы плана сверху вниз, ядро остаётся видно за ней */
/* Затемнение под картой — не «стекло» ради красоты: за ней крутится ядро, и
   без него мелкий текст читается по точкам сферы (видно на снимке). */
.map{grid-column:2;grid-row:2;z-index:2;align-self:start;justify-self:center;
  width:min(52vw,620px);max-height:56vh;overflow:auto;overscroll-behavior:contain;
  padding:26px 14px 14px;margin:0 -14px;
  background:linear-gradient(180deg,rgba(7,8,10,.92) 62%,rgba(7,8,10,0))}
.map::-webkit-scrollbar{width:2px}
.map::-webkit-scrollbar-thumb{background:var(--line)}
.map-h{display:flex;align-items:baseline;gap:10px;
  padding-bottom:9px;border-bottom:1px solid var(--line)}
.map-t{color:var(--bright);font-size:12px;flex:1;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.map-s{font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--blue)}
.map[data-live="0"] .map-s{color:var(--dim)}
.map[data-bad="1"] .map-s{color:var(--warm)}
.map-b{background:none;border:0;color:var(--dim);cursor:pointer;
  font:400 10px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;padding:2px 4px}
.map-b:hover{color:var(--blue)}
.map-b:active{transform:translateY(1px)}
.map-goal{color:var(--text);font-size:11px;line-height:1.5;margin:10px 0 14px;
  text-wrap:pretty}
.map-note{color:var(--warm);font-size:10.5px;margin-top:10px}

.lv{list-style:none;display:flex;flex-direction:column;gap:0}
.lv > li{position:relative;padding:0 0 14px 16px;border-left:1px solid var(--line)}
.lv > li:last-child{border-left-color:transparent}
.lv > li::before{content:"";position:absolute;left:-3px;top:5px;width:5px;height:5px;
  border-radius:50%;background:var(--line)}
.lv > li[data-live="1"]::before{background:var(--blue);box-shadow:0 0 9px var(--blue)}
.lv .step{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--dim);
  display:block;margin-bottom:6px}
.lv .node{display:flex;align-items:baseline;gap:9px;font-size:11px;padding:2px 0}
.lv .node .who{color:var(--bright);min-width:9.5em}
.lv .node .st{color:var(--dim);font-size:10px;letter-spacing:.08em}
.lv .node[data-st="running"] .who{color:#fff}
.lv .node[data-st="running"] .st{color:var(--blue)}
.lv .node[data-st="failed"] .st,.lv .node[data-st="cancelled"] .st{color:var(--warm)}
.lv .node .num{color:var(--dim);font-size:10px;margin-left:auto;white-space:nowrap}

.say{grid-column:1/-1;grid-row:3;z-index:1;display:flex;flex-direction:column;
  align-items:center;gap:10px;padding-top:12px}
.heard{max-width:74ch;text-align:center;color:var(--dim);font-size:10px;
  letter-spacing:.16em;text-transform:uppercase;margin-bottom:-4px}
.reply{max-width:74ch;text-align:center;color:var(--text);font-size:12.5px;line-height:1.6;
  text-wrap:pretty;min-height:2.4em}
#form{display:flex;align-items:center;gap:0;width:min(560px,80vw);
  border:1px solid var(--line);background:rgba(11,13,17,.72);backdrop-filter:blur(6px)}
#form:focus-within{border-color:var(--blue-dim)}
/* min-width:0 обязателен: у input своя внутренняя ширина, и без него третья
   кнопка (микрофон) выдавливает строку за край экрана — проверено снимком. */
#q{flex:1;min-width:0;background:none;border:0;outline:0;color:var(--bright);
  font:400 12px/1 var(--mono);padding:11px 13px;letter-spacing:.03em}
#q::placeholder{color:var(--dim);letter-spacing:.14em}
#go,#voice,#mic{background:none;border:0;border-left:1px solid var(--line);color:var(--dim);
  font:400 13px/1 var(--mono);padding:11px 15px;cursor:pointer;transition:color .2s,background .2s}
#voice,#mic{font-size:10px;letter-spacing:.18em;text-transform:uppercase}
#go:hover,#voice:hover,#mic:hover{color:var(--blue);background:rgba(61,127,242,.06)}
#go:active,#voice:active,#mic:active{transform:translateY(1px)}
#voice[aria-pressed="true"]{color:var(--blue);background:rgba(61,127,242,.08)}

/* Микрофон говорит о себе состоянием, а не значком: слушает — синий, слышит
   голос — белый с отсветом, разбирает сказанное — тёплый. Так видно, дошла ли
   фраза, без единой лишней подписи. */
#mic[data-st="wait"]{color:var(--dim);opacity:.6}
#mic[data-st="on"]{color:var(--blue);background:rgba(61,127,242,.08)}
#mic[data-st="hear"]{color:#fff;background:rgba(61,127,242,.16);
  box-shadow:inset 0 0 0 1px var(--blue-dim)}
#mic[data-st="busy"]{color:var(--warm);background:rgba(200,120,58,.08)}
/* Пока он думает, строка притушена, но микрофон живой: перебить и переспросить
   надо уметь именно в этот момент. */
#form[data-busy="1"]{opacity:.7}
#form[data-busy="1"] #q,#form[data-busy="1"] #go{pointer-events:none}
.err{color:var(--warm);font-size:11px}

/* связи нет — цифры на экране устарели, и это должно быть видно */
body.stale .col,body.stale .stage .clock{opacity:.42}
body.stale .state{color:var(--warm);text-shadow:0 0 18px rgba(200,120,58,.25)}

/* Узкий экран: одна колонка сверху вниз, страница прокручивается. Первый экран
   — ядро и строка ввода, ниже приборы. Прятать миссии и терминал на телефоне
   нельзя: ради них экран и открывают, а в строку их нерасторжимые строки не
   помещаются и раздвигают раскладку (проверено снимком). Без явных grid-row
   форма ввода уезжает наверх. */
@media (max-width:900px){
  .room{grid-template-columns:1fr;grid-template-rows:auto auto auto auto auto;
    height:auto;min-height:100dvh;gap:14px;padding-bottom:30px}
  .bar{grid-row:1}
  /* На телефоне ядро занимает весь экран, и часы ложатся прямо на сферу —
     затемнение снизу возвращает им читаемость (тот же приём, что под картой). */
  .stage{grid-column:1;grid-row:2;align-self:end;justify-self:stretch;
    min-height:52vh;justify-content:flex-end;padding-bottom:1vh;
    background:radial-gradient(130% 52% at 50% 100%,rgba(7,8,10,.94) 46%,rgba(7,8,10,0))}
  .say{grid-row:3}
  /* Три кнопки в строке ввода на телефоне помещаются только во всю ширину и с
     ужатыми полями. */
  #form{width:calc(100vw - 28px)}
  #go,#voice,#mic{padding:11px 10px}
  #voice,#mic{letter-spacing:.1em}
  .col{flex-direction:column;gap:22px;padding-top:4px}
  .col-l{grid-column:1;grid-row:4}
  .col-r{grid-column:1;grid-row:5}
  .col-r .block h2,.col-r .list{text-align:left}
  /* На прокручиваемой странице своя прокрутка внутри списков только мешает. */
  .col .block.grow{flex:none;overflow:visible}
  .col .list{overflow:visible}
  .map{grid-column:1;grid-row:2;align-self:start;width:100%;max-height:46vh}
}
@media (prefers-reduced-motion:reduce){.core{opacity:.7}}
