/* ══════════ TileLay прототип · тема «Інструмент» ══════════
   Токени-наступники планера (той самий акцент/шрифти/радіуси) + структура шкал за design-system/tilelay/MASTER.md.
   Mobile-first: база ≤767px, брейкпоінти 768 / 1120. */

:root{
  --bg:#eef0f3; --surface:#ffffff; --surface-2:#f7f8fa;
  /* --muted затемнено 2026-09-08 з #6b7280: на тлі сторінки (--bg) воно давало 4.23:1 при
     потрібних 4.5, і це був не окремий недогляд, а 21 вузол по всьому застосунку — уся
     другорядна типографіка, що лежить не на картці, а на столі. #666d7a дає 4.56 на --bg,
     5.21 на аркуші, 4.90 на притіненому. Мінімальне затемнення, яке чистить AA: далі воно
     починає з'їдати різницю з --ink, тобто саму ієрархію. */
  --ink:#1b1e23; --muted:#666d7a; --faint:#9aa1ab;
  --line:#d6dbe2; --line-2:#b9c1cb;
  --accent:#c0522b; --accent-d:#a8471f; --accent-soft:#f6e3da; /* accent злегка притемнено від планерного #c4582f → білий текст на кнопці/чипі дає 4.7:1 (WCAG AA) */
  --ok:#2f7d4f; --ok-soft:#e2f0e8;
  /* --warn затемнено 2026-09-08 з #8a6508 з тієї ж причини: 4.29:1 на --accent-soft (підпис
     «3 тонкі» на ОБРАНІЙ картці візерунка) і всього 4.79 на власному --warn-soft. #7d5b07 дає
     5.02 / 5.61, а на аркуші 6.23. Тон, який каже «є що виправити», мусить читатись першим —
     затемнення тут працює на його роботу, а не проти неї. */
  --warn:#7d5b07; --warn-soft:#faf3dc; --warn-line:#e8d9a8;
  --danger:#b33427; --danger-soft:#f7e2df;
  /* info — ХОЛОДНИЙ тон, єдиний у палітрі, що не сигналізує ані «добре», ані «увага».
     Потрібен саме тому, що --accent(#c0522b) і --danger(#c0392b) різняться лише зеленим каналом:
     будь-яка підказка в акцентних кольорах читалась як помилка. Тільки навчальні підказки (tips.js). */
  --info:#3d5a80;
  /* Другорядний текст НА КОЛЬОРОВІЙ поверхні — тінтований із її ж відтінку, а не сірий.
     `--muted` (#666d7a) — холодний сірий: на теплому `--danger-soft` він давав 4,19:1 при
     потрібних 4,5. Кожен тон банда отримує власний підпис на тій самій вазі, що `--muted` на
     аркуші (≈5,2:1), тож ієрархія «заголовок → текст» не змінилась. Токена для `info` тут
     немає: `.tipbox` веде текст на `--ink`, тобто споживача не існує. */
  --danger-ink:#785652; --warn-ink:#70654e; --ok-ink:#4b6859;
  --info-soft:#eaeff6; --info-line:#c2d1e4;
  /* Три кроки за РОЛЛЮ, а не за смаком: 10 — аркуш (картка, шухляда, панель),
     7 — орган керування (кнопка, поле, рядок), 4 — дрібний індикатор до ~30px
     (свотч, іконкова плитка). Крок xs існує тому, що 7px на свотчі 14×14 —
     майже коло: на такому розмірі радіус органа керування читається як пігулка. */
  --radius:10px; --radius-s:7px; --radius-xs:4px;
  --shadow-sm:0 1px 2px rgba(27,30,35,.06);
  --shadow-md:0 4px 10px rgba(27,30,35,.08);
  --shadow-lg:0 10px 24px rgba(27,30,35,.14);
  --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px; --space-5:24px; --space-6:32px;
  --mono:"IBM Plex Mono",ui-monospace,Menlo,Consolas,monospace;
  --sans:"Space Grotesk",system-ui,-apple-system,"Segoe UI",sans-serif;
  --tap:44px;
  --tabbar-h:56px;
  /* класи плитки на екрані розкладки: цілі нейтральні, підрізи акцентні, тонкі — тривожні */
  /* --tile-sliver-ink тримається В ПАРІ з --warn: тонка смуга на кресленні й слово «тонкі»
     в тексті — це одна сутність, і розійтись вони не сміють. */
  --tile-full:#ffffff; --tile-cut:#f6e3da; --tile-sliver:#faf3dc; --tile-sliver-ink:#7d5b07;
  /* СІМʼЯ «ПО ТЕМНОМУ». Акцент і увага на графітовому тлі мусять СВІТЛІШАТИ — інакше вони
     тонуть. Доти ці три значення жили літералами по файлу, тобто наступна темна поверхня
     вигадала б свій відтінок; аудит 2026-09-07 назвав це недокументованою палітрою.
     --on-ink-accent 9.68:1 на --ink (дія тоста), --on-ink-warn 8.18:1 на бейджі сцени.
     Для дії danger-тоста окремого тону НЕМАЄ свідомо: #ffd9d4 давав там 4.18, тобто провал,
     а білий дає 5.44 — підпорядкованість там несе вага, а не колір. */
  --on-ink-accent:#f0b9a2; --on-ink-warn:#ffd9a8; --tint-hover:rgba(27,30,35,.06);
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
/* ПОДВІЙНЕ ТОРКАННЯ НЕ ЗБІЛЬШУЄ СТОРІНКУ — на всьому застосунку (2026-09-28). Без цього iOS Safari
   читав два швидкі тапи по ТІЙ САМІЙ клавіші вбудованого цифрового блоку як жест збільшення:
   сторінка «пливла», а один дотик ковтався — «1111» ставало «111», «4005» — «400». Для замірів це
   найгірше місце: повторювані цифри (5000, 4000, 1100) там норма. Знайдено повтором робота-
   майстра на симуляторі iPhone (Chromium цього не бачить за побудовою). `manipulation` лишає пан і
   ПІНЧ (збільшити дрібний текст можна), знімає лише double-tap-zoom; полотна з `touch-action:none`
   (редактор, план, сцена) і далі перекривають це своїм. */
html{touch-action:manipulation}
/* Екран — один fixed-шар (редактор кімнати, спільний план): вікну прокручуватись нема чого.
   Без цього WebKit прокручував корінь під клавіатуру, і Chrome iOS цього не відкочував —
   весь шар їхав угору (див. unshiftFixedScreen у viewport.js). */
html:has(.zed),html:has(.pln),body:has(.zed),body:has(.pln){overflow:hidden}
body{background:var(--bg);color:var(--ink);font:15px/1.45 var(--sans);-webkit-font-smoothing:antialiased}
button{font:inherit;color:inherit}
/* 16px на полях — НЕ естетика, а закон iOS: Safari зумить сторінку при фокусі поля з
   font-size < 16px і НЕ відкочує зум після blur. Наслідок не косметичний — `position:fixed`
   панелі обрізаються зліва (сума кошторису читалась «01 857,86 грн» замість «101 857,86»),
   а в зануреному екрані шапка з кнопкою «назад» їде за верхній край, тобто виходу не видно.
   Ставимо на ЕЛЕМЕНТИ, а не на класи: нове поле безпечне, нічого не роблячи, — той самий
   принцип, що в законі товщини ліній. Заведено 2026-08-25 після e2e на iPhone 16 Pro. */
input,select,textarea{font:inherit;color:inherit;font-size:16px}
img,svg{display:block;max-width:100%}
a{color:var(--accent-d)}

:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-radius:var(--radius-s);box-shadow:0 0 0 4px var(--accent-soft)}
::placeholder{color:var(--faint)}

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.01ms !important;transition-duration:.01ms !important}
}

/* ── Каркас ── */
.app{min-height:100dvh;display:flex;flex-direction:column}
.screen{flex:1;width:100%;max-width:1120px;margin:0 auto;padding:var(--space-4) var(--space-4) calc(var(--tabbar-h) + var(--space-6))}
@media(min-width:768px){.screen{padding:var(--space-5) var(--space-5) var(--space-6)}}

.screen-head{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap;margin:0 0 var(--space-4)}
.screen-head h1{font-size:22px;font-weight:700;margin:0;letter-spacing:-.01em}
.screen-head .spacer{flex:1}
.backlink{display:inline-flex;align-items:center;gap:6px;color:var(--muted);text-decoration:none;font-size:13px;min-height:var(--tap);padding:0 var(--space-2) 0 0}
@media (hover:hover){.backlink:hover{color:var(--ink)}}
.sub{color:var(--muted);font-size:13px;margin:2px 0 0}

/* ── Шапка в ОДИН рядок (.lhead — #/layout, .zhead — #/zones, .phead — «Спільний план») ──
   Спільний .screen-head лишається на решті екранів, де назва екрана несе сенс. На цих трьох
   її несе сам інтерфейс, тож рядок віддано ЗМІННІЙ частині: назві кімнати / назві проєкту /
   назві плану.
   Ціна: зі стрілки зникло слово («Кімнати»/«Проєкти») — на мобільному стрілка = назад за
   конвенцією, а другий вихід підписаний явно («Зберегти» / «Готово» / кнопка таббара).
   Було на #/zones: backlink 44 + шапка 53+16 + .zbar 44+16 = 189px до першої картки (22%
   екрана 844). Стало 44+12: «Імпорт PDF» — іконка в рядку (.zhead-act), «Розставити кімнати»
   — пунктирна картка .zghost на початку списку.
   Було на «Спільному плані»: backlink 44 + .screen-head 69 = 113px, і обидва виходи
   («← Кімнати» та «Готово») були підписані й вели в те саме місце. */
.lhead,.zhead,.phead{display:flex;align-items:center;gap:6px}
.lhead{margin:0 0 var(--space-2)}
.zhead,.phead{margin:0 0 var(--space-3)}
/* Стрілка «назад» — ОДНА на всі чотири шапки, включно з редактором кімнати (`.zed-back`).
   Доти редактор мав свою: 34×34 кружечок із заливкою, тобто і менша за мінімум дотику 44px,
   і єдина сіра «пігулка» там, де решта екранів показує голу стрілку (знайдено e2e 2026-08-25). */
.lhead-back,.zhead-back,.phead-back,.zed-back{flex:none;width:var(--tap);height:var(--tap);margin-left:-10px;
  display:flex;align-items:center;justify-content:center;
  background:none;border:0;cursor:pointer;
  color:var(--muted);text-decoration:none;border-radius:var(--radius-s)}
@media (hover:hover){.lhead-back:hover,.zhead-back:hover,.phead-back:hover,.zed-back:hover{color:var(--ink)}}
.lhead-back:active,.zhead-back:active,.phead-back:active,.zed-back:active{background:var(--surface-2)}
.lhead h1,.zhead h1,.phead h1{margin:0;font-size:18px;font-weight:700;letter-spacing:-.01em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lhead h1{flex:1;min-width:0}
.lhead h1 span{font-weight:500;color:var(--muted)}
/* Назва проєкту тапається (перейменування) — олівець ВСЕРЕДИНІ h1, після тексту, тож
   при довгій назві крапками зрізає саме назву, а не афорданс. flex:0 1 auto в назви й у
   мети: обидві стискаються, і мета не викидає назву з рядка на 360px. */
.zhead h1{flex:0 1 auto;min-width:0;display:flex;align-items:center;gap:6px;
  cursor:pointer;border-radius:var(--radius-s)}
.zhead h1 .zhead-nm{min-width:0;overflow:hidden;text-overflow:ellipsis}
.zhead h1 svg{flex:none;color:var(--faint)}
.zhead h1:active{background:var(--surface-2)}
.zhead-meta{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:12.5px;color:var(--muted)}
/* Права іконка — «Імпорт PDF» напряму, а не меню: дія одна, тож шторка «⋯» була б зайвим
   кроком між тапом і файловим діалогом. Підпис несуть aria-label/title + кнопка з текстом
   у порожньому стані, де імпорт і зустрічають уперше. */
.zhead-act{flex:none;margin-left:auto;margin-right:-10px;width:var(--tap);height:var(--tap);
  display:flex;align-items:center;justify-content:center;
  background:none;border:0;color:var(--muted);border-radius:var(--radius-s);cursor:pointer}
@media (hover:hover){.zhead-act:hover{color:var(--ink);background:var(--surface-2)}}
/* «Кошторис» (`.ehead`): назва не тапається, а номер і дата — другим рядком у тій самій висоті. */
.ehead h1{cursor:default;flex-direction:column;align-items:flex-start;gap:0;line-height:1.15}
.ehead h1:active{background:none}
.ehead h1 small{font-size:12px;font-weight:400;color:var(--muted);letter-spacing:0;
  max-width:100%;overflow:hidden;text-overflow:ellipsis}
/* Назва плану тапається так само, як назва проєкту — олівець усередині h1 після тексту.
   Правий хвіст (чип стану / площа) не стискається: він короткий, а зрізати треба назву. */
/* Ціль перейменування — на всю висоту шапки (44px). Сам рядок тексту 26px, а шапка й так
   `--tap`, тож розтягнути `h1` до її висоти нічого не коштує: жодного пікселя в плану не
   забирає, а тап перестає бути на 18px нижчим за мінімум. */
.phead h1{flex:0 1 auto;min-width:0;display:flex;align-items:center;gap:6px;align-self:stretch;
  min-height:var(--tap);cursor:default;border-radius:var(--radius-s)}
.phead h1[role="button"]{cursor:pointer}
.phead h1 .phead-nm{min-width:0;overflow:hidden;text-overflow:ellipsis}
.phead h1 svg{flex:none;color:var(--faint)}
.phead h1[role="button"]:active{background:var(--surface-2)}
.phead-meta{flex:none;font-size:12.5px;color:var(--muted)}
.phead .chip{flex:none}

/* ── Верхня панель (десктоп) ── */
.topbar{display:none}
@media(min-width:768px){
  .topbar{position:sticky;top:0;z-index:40;display:flex;align-items:center;gap:var(--space-4);
    background:var(--surface);border-bottom:1px solid var(--line);padding:0 var(--space-5);min-height:52px;box-shadow:var(--shadow-sm)}
  .topbar .brand{display:flex;align-items:center;gap:8px;font-weight:700;font-size:16px;letter-spacing:-.01em;text-decoration:none;color:var(--ink)}
  .topbar nav{display:flex;gap:var(--space-2);flex:1}
  .topbar nav a{display:inline-flex;align-items:center;gap:7px;padding:6px 12px;min-height:36px;border-radius:var(--radius-s);
    text-decoration:none;color:var(--muted);font-size:14px;font-weight:500;transition:background .15s,color .15s}
  @media (hover:hover){.topbar nav a:hover{color:var(--ink);background:var(--surface-2)}}
  .topbar nav a.active{color:var(--accent-d);background:var(--accent-soft)}
  .topbar .who{color:var(--muted);font-size:13px;font-family:var(--mono)}
}

/* ── Нижній таб-бар (мобільний) ── */
.tabbar{position:fixed;left:0;right:0;bottom:0;z-index:40;display:flex;background:var(--surface);
  border-top:1px solid var(--line);padding-bottom:env(safe-area-inset-bottom);box-shadow:0 -2px 8px rgba(27,30,35,.06)}
.tabbar a{position:relative;flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
  min-height:var(--tabbar-h);text-decoration:none;color:var(--muted);font-size:11px;font-weight:500;transition:color .15s}
.tabbar a.active{color:var(--accent-d);font-weight:600}
/* активний таб не лише кольором — ще й індикатор зверху + жирність (не покладаємось на колір) */
.tabbar a.active::before{content:"";position:absolute;top:0;left:50%;transform:translateX(-50%);
  width:26px;height:3px;border-radius:0 0 3px 3px;background:var(--accent)}
.tabbar a svg{width:22px;height:22px}
@media(min-width:768px){.tabbar{display:none}}

/* ── Кнопки ── */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:var(--tap);
  padding:0 var(--space-4);border:1px solid var(--line-2);border-radius:var(--radius-s);
  background:var(--surface);color:var(--ink);font-weight:500;font-size:14px;cursor:pointer;
  transition:background .15s,border-color .15s,box-shadow .15s;text-decoration:none;white-space:nowrap}
/* ЗАКОН: кожне :hover — лише в @media (hover:hover). На iOS тапнутий елемент лишається в :hover
   до наступного тапу деінде, тож незагейтована кнопка ЗАСТИГАЄ «натиснутою» (скріншот
   власника 2026-09-08: «Підібрати зсув» сіра --line після підбору, читалась як «спробуй ще»).
   Клас дефекту закрили для .lroom 2026-09-08 і того ж дня знайшли на 48 із 49 правил —
   по одному не працює, тож тепер усі 49 і леґ 1c у check.sh, який не пускає нових. */
@media (hover:hover){.btn:hover{background:var(--surface-2);border-color:var(--faint)}}
.btn--wide{width:100%}
.btn--primary{background:var(--accent);border-color:var(--accent);color:#fff}
@media (hover:hover){.btn--primary:hover{background:var(--accent-d);border-color:var(--accent-d)}}
.btn--danger{color:var(--danger);border-color:var(--danger)}
@media (hover:hover){.btn--danger:hover{background:var(--danger-soft)}}
.btn--ghost{border-color:transparent;background:transparent}
@media (hover:hover){.btn--ghost:hover{background:var(--surface-2)}}
.btn--sm{min-height:34px;padding:0 var(--space-3);font-size:13px}
/* Крапка «є незбережені зміни». Не бейдж із числом: рахувати правки нема сенсу,
   важливий лише факт «натисни Зберегти». */
.btn--dot{position:relative}
.btn--dot::after{content:'';position:absolute;top:5px;right:5px;width:6px;height:6px;
  border-radius:999px;background:#fff;box-shadow:0 0 0 2px var(--accent-d)}
.btn:disabled{opacity:.5;cursor:not-allowed}
.btn--block{width:100%}

/* ── Картки ── */
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-sm)}
.card--pad{padding:var(--space-4)}
.card h2{font-size:15px;font-weight:600;margin:0 0 var(--space-3)}

/* ── Форми ── */
/* Будь-який display у наших класах (.field — flex) перебиває стандартний [hidden]{display:none}
   з UA-стилів, і елемент лишався видимим. Тримаємо hidden робочим глобально. */
[hidden]{display:none!important}
.field{display:flex;flex-direction:column;gap:5px;margin-bottom:var(--space-3)}
.field>label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
.input,.select,textarea.input{min-height:var(--tap);padding:8px 12px;border:1px solid var(--line-2);border-radius:var(--radius-s);
  background:var(--surface);width:100%;transition:border-color .15s}
@media (hover:hover){.input:hover,.select:hover{border-color:var(--faint)}}
textarea.input{min-height:72px;resize:vertical;line-height:1.4}
.input--mono{font-family:var(--mono)}
.input--err{border-color:var(--danger)}
.err{color:var(--danger);font-size:12.5px;margin-top:2px}
.hint{color:var(--muted);font-size:12.5px}
/* Підказка, яка цієї миті каже про НЕДОСЯЖНЕ (набране число не виходить): тон warn —
   є що виправити користувачеві, за реєстром тонів над .tipbox. Не .err: помилки ще немає,
   бо нічого не застосовано — це прев'ю, яке чесно каже, що застосувати не вийде. */
.hint--warn{color:var(--warn)}
.row{display:flex;gap:var(--space-3);flex-wrap:wrap}
.row>.field{flex:1;min-width:140px}

/* Сегментований перемикач */
.seg{display:flex;border:1px solid var(--line-2);border-radius:var(--radius-s);overflow:hidden;width:max-content;max-width:100%}
.seg button{min-height:var(--tap);padding:0 var(--space-4);border:0;background:transparent;color:var(--muted);cursor:pointer;font-weight:500;font-size:14px;transition:background .15s,color .15s}
.seg button+button{border-left:1px solid var(--line)}
.seg button.active{background:var(--accent-soft);color:var(--accent-d);font-weight:600}

/* Чипи (пікер одиниць тощо) */
.chips{display:flex;gap:var(--space-2);flex-wrap:wrap}
.chip{display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:0 var(--space-3);
  border:1px solid var(--line-2);border-radius:999px;background:var(--surface);font-size:13.5px;cursor:pointer;
  transition:background .15s,border-color .15s,color .15s}
@media (hover:hover){.chip:hover{border-color:var(--faint)}}
.chip.active{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600}
.chip--static{cursor:default;background:var(--surface-2);border-color:var(--line);color:var(--muted);min-height:26px;font-size:12px}
@media (hover:hover){.chip--static:hover{border-color:var(--line)}}

.badge{display:inline-flex;align-items:center;min-height:20px;padding:1px 8px;border-radius:999px;font-size:11px;font-weight:600;letter-spacing:.03em}
.badge--user{background:var(--accent-soft);color:var(--accent-d)}
.badge--warn{background:var(--warn-soft);color:var(--warn)}
.badge--auto{background:var(--ok-soft);color:var(--ok);cursor:pointer;border:0}
.badge--manual{background:var(--surface-2);color:var(--muted);cursor:pointer;border:0}
.badge--region{background:var(--surface-2);color:var(--muted);font-family:var(--mono)}
.badge--stale{background:var(--warn-soft);color:var(--warn)}
/* тапабельний бейдж регіону (екран Цін) → відкриває шіт вибору регіону */
.badge--tap{border:0;cursor:pointer;min-height:26px;gap:1px;padding-right:5px;transition:background .15s}
@media (hover:hover){.badge--tap:hover{background:var(--line-2)}}
.badge--tap svg{margin-left:-1px;opacity:.7}

/* ── Радіо/чекбокси ── */
.check{display:flex;align-items:center;gap:10px;min-height:var(--tap);cursor:pointer;font-size:14.5px}
.check input{width:18px;height:18px;accent-color:var(--accent);flex:none}
.check .note{color:var(--muted);font-size:12.5px}

/* ── Таблиці (десктоп) → картки-рядки (мобільний) ── */
.table{width:100%;border-collapse:collapse;font-size:14px}
.table th{font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:600;
  text-align:left;padding:8px 10px;border-bottom:1.5px solid var(--line-2)}
.table td{padding:9px 10px;border-bottom:1px solid var(--line);vertical-align:middle}
.table .num,.table th.num{text-align:right;font-family:var(--mono);white-space:nowrap}
.table tr:last-child td{border-bottom:0}
.money{font-family:var(--mono);white-space:nowrap}

/* мобільний колапс таблиць у картки */
@media(max-width:767px){
  .table--cards thead{display:none}
  .table--cards,.table--cards tbody,.table--cards tr,.table--cards td{display:block;width:100%}
  .table--cards tr{border:1px solid var(--line);border-radius:var(--radius-s);margin-bottom:var(--space-2);background:var(--surface);padding:var(--space-2) var(--space-3)}
  .table--cards td{border:0;padding:3px 0;text-align:left}
  .table--cards td.num{text-align:left}
  .table--cards td[data-l]::before{content:attr(data-l) ": ";font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}
  .table--cards td[data-l]:empty{display:none} /* напр., порожній «Коеф.» не лишає висячого лейбла в картці */
}

/* ── Список цін ── */
.pricegroup{margin:0 0 var(--space-4)}
.pricegroup>h3{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);margin:var(--space-4) 0 var(--space-2)}
/* Липкі заголовки груп — не губимося в довгому каталозі. Mobile: скрол — вікно, топбар прихований, тож top:0. */
@media(max-width:767px){
  .pricegroup>h3{position:sticky;top:0;z-index:2;background:var(--bg);margin:0 0 var(--space-2);padding:var(--space-3) 0 var(--space-2)}
}
.pricerow{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-2) var(--space-3);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-s);margin-bottom:6px}
.pricerow .nm{flex:1;min-width:0}
.pricerow .nm .t{font-size:14px}
.pricerow .nm .n{font-size:12px;color:var(--muted)}
.pricerow .nm .n.warn{color:var(--warn)}
.pricerow .pricecol{flex:none;display:flex;flex-direction:column;align-items:flex-end;gap:1px}
.pricerow .priceline{display:flex;align-items:baseline;gap:3px}
.pricerow .priceline input{width:60px;min-height:34px;padding:2px 4px;text-align:right;font-family:var(--mono);
  font-size:16px;font-weight:700;color:var(--ink);
  border:1px solid transparent;border-radius:var(--radius-s);background:transparent;transition:border-color .15s,background .15s}
@media (hover:hover){.pricerow .priceline input:hover{border-color:var(--line-2);background:var(--surface)}}
.pricerow .priceline input:focus{border-color:var(--accent);background:var(--surface)}
.pricerow .priceline .cur{font-family:var(--mono);font-size:12.5px;color:var(--muted)}
.pricerow .pmeta{display:flex;align-items:baseline;gap:6px;font-family:var(--mono)}
.pricerow .pmeta .unit{color:var(--faint);font-size:11.5px;white-space:nowrap}
.pricerow .pmeta .range{color:var(--faint);font-size:11px;white-space:nowrap}
.pricerow.placeholder .priceline input{color:var(--warn)}
.pricerow .rm{display:none;width:34px;height:34px;flex:none;align-items:center;justify-content:center;border:0;
  background:transparent;color:var(--faint);border-radius:var(--radius-s);cursor:pointer}
@media (hover:hover){.pricerow .rm:hover{color:var(--danger);background:var(--danger-soft)}}
.editing .pricerow .rm{display:inline-flex}
.edit-toggle{width:44px;min-height:44px;flex:none;display:inline-flex;align-items:center;justify-content:center;
  border:1px solid var(--line);border-radius:var(--radius-s);background:var(--surface);color:var(--muted);cursor:pointer}
.edit-toggle[aria-pressed="true"]{background:var(--accent-soft);border-color:transparent;color:var(--accent-d)}

/* ── Сітка проєктів ── */
.projgrid{display:grid;grid-template-columns:1fr;gap:var(--space-3)}
@media(min-width:768px){.projgrid{grid-template-columns:1fr 1fr}}
@media(min-width:1120px){.projgrid{grid-template-columns:1fr 1fr 1fr}}
.projcard{position:relative;display:flex;flex-direction:column;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);box-shadow:var(--shadow-sm);overflow:hidden;cursor:pointer;transition:box-shadow .2s,border-color .2s}
@media (hover:hover){.projcard:hover{box-shadow:var(--shadow-md);border-color:var(--line-2)}}
.projcard .thumb{background:var(--surface-2);border-bottom:1px solid var(--line);height:130px;display:flex;align-items:center;justify-content:center}
.projcard .thumb svg{max-height:110px}
.projcard .meta{padding:var(--space-3) var(--space-3) var(--space-3)}
.projcard .meta .t{font-weight:600;font-size:15px;margin:0 0 2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.projcard .meta .t a{color:inherit;text-decoration:none;outline-offset:2px}
.projcard .meta .t a::after{content:"";position:absolute;inset:0;z-index:1} /* тайтл-лінк накриває всю картку (крім кебаба) — доступний та клікабельний */
.projcard .meta .d{color:var(--muted);font-size:12.5px;margin:0 0 8px}
.projcard .chips{gap:6px}
.projcard .kebab{position:absolute;z-index:2;top:8px;right:8px;width:36px;height:36px;display:flex;align-items:center;justify-content:center;
  border:1px solid var(--line);border-radius:var(--radius-s);background:var(--surface);color:var(--muted);cursor:pointer;transition:background .15s}
@media (hover:hover){.projcard .kebab:hover{background:var(--surface-2);color:var(--ink)}}

/* ── Меню дій з проєктом (нижня шухляда) ── */
.menuhead{margin:-4px 0 4px}
.menuhead h2{margin:0}
.menuhead .hint{margin:2px 0 0}
.actionlist{display:flex;flex-direction:column;border-top:1px solid var(--line);
  margin:0 calc(-1 * var(--space-4));padding:6px var(--space-4)}
.actionrow{display:flex;align-items:center;gap:12px;min-height:48px;padding:0 4px;border:0;background:transparent;
  border-radius:var(--radius-s);cursor:pointer;font-size:15px;text-align:left;color:inherit;transition:background .12s}
@media (hover:hover){.actionrow:hover{background:var(--surface-2)}}
.actionrow svg{color:var(--muted);flex:none}
.actionrow.danger{color:var(--danger)}
.actionrow.danger svg{color:var(--danger)}
@media (hover:hover){.actionrow.danger:hover{background:var(--danger-soft)}}
.actionrow-div{height:1px;background:var(--line);margin:6px 4px}

/* ── Порожній стан ── */
.empty{border:1.5px dashed var(--line-2);border-radius:var(--radius);padding:var(--space-6) var(--space-4);
  text-align:center;color:var(--muted)}
.empty .ic{margin:0 auto var(--space-3);width:44px;height:44px;color:var(--faint)}
.empty h3{color:var(--ink);font-size:16px;margin:0 0 4px}
.empty p{margin:0 0 var(--space-4);font-size:13.5px}
.empty .actions{display:flex;gap:var(--space-2);justify-content:center;flex-wrap:wrap}

/* ── Модалка / bottom-sheet ── */
/* top/height за visualViewport (viewport.js) — щоб екранна клавіатура не ховала
   інпут шухляди за собою на iOS; --vvt/--vvh мають дефолти на випадок, поки JS не стартував */
/* Коробка `.overlay` міряється ВИДИМОЮ областю (щоб шухляда сіла над клавіатурою), а
   затемнення малює ::before на ВЕСЬ екран. Доти фон висів на самій коробці, тож під шухлядою
   лишалась незатемнена смуга живої сторінки — крізь модалку читалось «Розкладка плану…»
   (знято на iPhone 2026-08-25). ::before не стає флекс-елементом саме тому, що position:fixed
   виводить його з потоку; `fadeIn` анімує лише opacity, тож containing block не зміщується. */
.overlay{position:fixed;left:0;right:0;top:var(--vvt,0);height:var(--vvh,100dvh);z-index:70;
  display:flex;align-items:flex-end;justify-content:center;animation:fadeIn .15s ease}
.overlay::before{content:"";position:fixed;inset:0;background:rgba(27,30,35,.42)}
@media(min-width:768px){.overlay{align-items:center;padding:var(--space-5)}}
.sheet{position:relative;background:var(--surface);width:100%;max-height:min(86dvh, calc(var(--vvh,100dvh) - 8px));overflow:auto;
  border-radius:var(--radius) var(--radius) 0 0;padding:var(--space-4);animation:sheetUp .2s ease}
@media(min-width:768px){.sheet{max-width:520px;border-radius:var(--radius);box-shadow:var(--shadow-lg);animation:fadeIn .15s ease}}

/* ── Відкрита екранна клавіатура (клас ставить viewport.js за --kb) ──
   Знято на живому iPhone 2026-08-25 — симулятор клавіатуру не піднімає, тож обидва випадки
   до того були невидимі.
   1) Нижній хром ховаємо. `.tabbar`/`.stickybar` — fixed;bottom:0 відносно LAYOUT-viewport,
      який під клавіатуру не стискається, тож Safari лишав їх посеред екрана з видимою
      сторінкою під ними. Тапнути їх при відкритій клавіатурі однаково не можна.
      display:none тут нічого не зсуває: смуги — fixed, а місце під них тримає
      padding-bottom на `.has-stickybar`, який лишається на місці.
   2) Шухляду ПІДІЙМАЄМО над дном. iOS кладе СВОЮ плаваючу панель (пігулка автозаповнення
      зліва + кнопка «сховати клавіатуру» справа) поверх сторінки, і `visualViewport.height`
      її НЕ віднімає — тож ряд дій шухляди опинявся рівно під нею, а «Зберегти» був
      наполовину накритий. 64px — виміряна висота тієї панелі.
      Саме MARGIN, а не padding: із padding запас був БІЛОЮ порожнечею всередині шухляди
      (видно на iPhone 2026-08-25 — «дірка» під кнопками), а з margin те саме місце показує
      затемнення й читається як навмисно піднята шухляда. Тому ж заокруглюємо всі кути:
      відірвана від низу шухляда з квадратним низом виглядала б обрізаною. */
:root.kb-open .tabbar,
:root.kb-open .stickybar{display:none}
/* 64px — лише там, де панель справді НЕ віднята з visualViewport (Safari; `kb-pad` ставить
   viewport.js). У Chrome iOS цей запас подвоювався — див. коментар там. */
:root.kb-open.kb-pad .sheet{margin-bottom:64px;border-radius:var(--radius);
  max-height:min(86dvh, calc(var(--vvh,100dvh) - 8px - 64px))}
.sheet h2{font-size:16px;margin:0 0 var(--space-3);padding-right:48px}
/* закриття шухляди: × завжди (клавіатура/десктоп) + грабер зверху на мобільному */
.sheet-x{position:absolute;top:8px;right:8px;z-index:1;width:36px;height:36px;display:flex;align-items:center;justify-content:center;
  border:0;background:transparent;color:var(--muted);border-radius:var(--radius-s);cursor:pointer;transition:background .15s,color .15s}
/* Мінімальна ціль 44 — але лише в справжній шухлядці: `.zed-entry-head .sheet-x` живе в
   потоці редактора, і роздувати його там нема потреби (там він у ряду 44px сам по собі). */
.sheet>.sheet-x{width:var(--tap);height:var(--tap)}
@media (hover:hover){.sheet-x:hover{background:var(--surface-2);color:var(--ink)}}
.sheet-grab{display:none}
@media(max-width:767px){
  .sheet-grab{display:block;width:40px;height:4px;border-radius:999px;background:var(--line-2);margin:-4px auto 12px;cursor:pointer}
}
.sheet .actions{display:flex;gap:var(--space-2);justify-content:flex-end;margin-top:var(--space-4)}
/* Три дії в один ряд не влазять на 375px, а стос ще й розводить «зберегти» і «втратити» по
   вертикалі. Порядок DOM = порядок згори: головна дія, руйнівна, відмова. */
.sheet .actions--stack{flex-direction:column;align-items:stretch}
.sheet .actions--stack .btn{width:100%}
/* Підвал шухляди ЛИПНЕ до її низу. Заміряно на 402×874: у шухляді «Новий елемент» видиме
   закінчувалось на полі відступу, а ряд із «Готово» лежав під фолдом — тобто єдиною видимою
   завершальною ціллю лишався ✕ у куті, який СКАСОВУЄ (`onClose(committed=false)` відкочує
   правки до знімка). Завершення дії не сміє бути під фолдом, коли скасування не під ним.
   Помилка їде разом із рядом навмисно: причина стоїть поруч із вимкненою кнопкою, а не за
   екран вище. Відʼємні поля — щоб фон і рамка йшли на всю ширину аркуша попри padding
   `.sheet`; нижнє ще й зʼїдає його нижній відступ, тож підвал сідає врівень із краєм.
   `bottom` ВІД'ЄМНИЙ на той самий відступ: липке зміщення рахується від краю ВМІСТУ шторки
   (без її padding), і з `bottom:0` прокручена шторка тримала підвал на 16 px вище краю, а під
   ним просвічував вміст — помітно стало на «Зʼєднати кімнати?», першій шторці з підвалом, яка
   справді гортається (2026-10-16). */
.sheetfoot{position:sticky;bottom:calc(-1 * var(--space-4));z-index:2;background:var(--surface);
  margin:var(--space-4) calc(-1 * var(--space-4)) calc(-1 * var(--space-4));
  padding:var(--space-3) var(--space-4) max(var(--space-4), env(safe-area-inset-bottom));
  border-top:1px solid var(--line)}
/* Над клавіатурою смужки «додому» під підвалом немає — безпечний відступ (34 pt на iPhone) там
   був зайвою білою смугою під «Готово» (iPhone-знахідка №5, 03.10). */
:root.kb-open .sheetfoot{padding-bottom:var(--space-4)}
.sheetfoot .actions{margin-top:0}
.sheetfoot .err{margin:0 0 var(--space-2)}
.sheetfoot .err:empty{display:none}
/* Вбудований цифровий блок (numpadHTML) — заміна нативній клавіатурі, див. коментар у app.js.
   52px на клавішу: вище мінімальних 44px, бо в цей блок цілять швидко й наосліп, дивлячись
   на план, а не на кнопки. Моноширинний шрифт — той самий, що в числових полях. */
.npad{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--space-2);margin-top:var(--space-3)}
.npad-k{min-height:52px;display:flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-size:20px;font-weight:600;color:var(--ink);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-s);
  cursor:pointer;user-select:none;-webkit-user-select:none;transition:background .1s}
.npad-k:active{background:var(--surface-2)}
.npad-k--muted{color:var(--muted);font-size:22px}
.npad-k--ok{background:var(--accent);border-color:var(--accent);color:#fff;font-size:22px}
.npad-k--ok:active{background:var(--accent-d)}
/* Вимкнена ✓ — НЕ приглушена теракота (та сама причина, що в `.zed-close:disabled`):
   бліда заливка читається як «наполовину активна». Поки число невалідне, клавіша мовчить,
   а причину називає рядок помилки під блоком. */
.npad-k--ok:disabled{background:var(--surface-2);border-color:var(--line);color:var(--faint);cursor:not-allowed}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
@keyframes sheetUp{from{transform:translateY(24px);opacity:.6}to{transform:none;opacity:1}}

/* ── Тости ── */
/* left:0;right:0, а не left:50% + transform: у fixed-боксу з left:50% доступна ширина —
   ПОЛОВИНА вьюпорту, тож тост шринкувався до ~200px попри max-width:92vw і йшов у 4 рядки
   (заміряно: тост «Стик» 98px заввишки накривав ряд «ЗСУВ Y» цілком). */
.toasts{position:fixed;left:0;right:0;bottom:calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 12px);
  z-index:90;display:flex;flex-direction:column;gap:8px;align-items:center;pointer-events:none}
@media(min-width:768px){.toasts{bottom:20px}}
/* Тост НЕ сміє накривати дію, до якої веде. Базовий відступ рахує лише таббар, але над
   таббаром стоїть ще й липка панель — і «Кімнату збережено» лягало рівно на «Додати
   кімнату» / «Кошторис →», тобто підтвердження успіху закривало наступний крок. Гірше:
   тост із дією «Скасувати» перехоплював тап, призначений кнопці під ним.
   Заміряно на 375×812: таббар 57, липка панель 61 (top 695), тост стояв на 68 → його
   край на 744, усередині панелі. 129 = 56 + 61 + 12 просвіту. */
body:has(.has-stickybar) .toasts{bottom:calc(var(--tabbar-h) + 61px + 12px + env(safe-area-inset-bottom))}
/* Занурений редактор: таббара немає, натомість знизу смуга «Елементи», а над нею — кнопки
   фази малювання. 88px клали тост рівно на них (заміряно: .zed-acts top 648, край тоста 724).
   164 = смуга 78 + два ряди кнопок 74 + 12. Підказку над кнопками тост накрити може —
   вона текст, не ціль дотику; кнопки — ні. */
body:has(.app.immersive) .toasts{bottom:calc(164px + env(safe-area-inset-bottom))}
/* #/layout із розгорнутою панеллю зсуву: тост НЕ сміє лягати на степери, з якими саме
   працюють (tox/toy правлять серіями тапів, а тост має pointer-events:auto й ковтав тап).
   325 = липка панель 61 + відступ 8 + картка 244 + 12 просвіту. */
body:has(.lnudge:not(.lnudge--closed)) .toasts{bottom:calc(325px + env(safe-area-inset-bottom))}
.toast{display:flex;align-items:center;gap:12px;background:var(--ink);color:#fff;border-radius:var(--radius-s);
  padding:10px 16px;font-size:13.5px;box-shadow:var(--shadow-lg);pointer-events:auto;animation:sheetUp .2s ease;max-width:min(92vw,360px)}
.toast button{border:0;background:transparent;color:var(--on-ink-accent);font-weight:600;cursor:pointer;min-height:32px;white-space:nowrap}
/* Єдиний випадок danger-тоста: дія НЕ відбулась і виправляти це користувачеві (сховище
   переповнене). Звичайний результат дії лишається --ink — див. РЕЄСТР ТОНІВ нижче. */
/* Тост БЕЗ дії («Кімнату збережено») дотиків не ловить: ловити йому нічого, а лежить він рівно
   там, куди тапають далі (картки списку кімнат) — і тап губився на 5 с. Тост ІЗ дією («Скасувати»,
   «Змінити») свій дотик тримає. Знайшов робот-майстер (e2e/), рішення власника 2026-09-28. */
.toast:not(:has(button)){pointer-events:none}
.toast--danger{background:var(--danger)}
.toast--danger button{color:#fff}


/* ── Проєкт / прев'ю плану ── */
/* .plansvg прибрано: превʼю плану переїхало в картку (.zc-hero), окремого блоку більше нема. */
.zonerow{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-2) 0;border-bottom:1px solid var(--line);flex-wrap:wrap}
.zonerow:last-child{border-bottom:0}
.zonerow .sw{width:14px;height:14px;border-radius:var(--radius-xs);background:var(--accent-soft);border:1.5px solid var(--accent);flex:none}
.zonerow .nm{font-weight:600;min-width:90px}
.zonerow .ti{color:var(--muted);font-size:12.5px;font-family:var(--mono)}
.zonerow .ar{margin-left:auto;font-family:var(--mono);font-size:13px}

.projlayout{display:grid;grid-template-columns:1fr;gap:var(--space-4)}
@media(min-width:768px){.projlayout{grid-template-columns:3fr 2fr;align-items:start}}

/* ── Кошторис ── */
.estline .nm{font-size:14px}
.estline .scope{font-size:11.5px;color:var(--muted)}
/* 92px, а не 84: поля успадкували 16px із закону полів угорі, і mono-гліф виріс на ~7% —
   на 84px «101857.86» обрізалось би. */
.estline input.qty,.estline input.uprice{width:92px;min-height:36px;padding:4px 8px;text-align:right;font-family:var(--mono);
  border:1px solid transparent;border-radius:var(--radius-s);background:transparent;transition:border-color .15s,background .15s}
@media (hover:hover){.estline input.qty:hover,.estline input.uprice:hover{border-color:var(--line-2);background:var(--surface)}}
.estline input.qty:focus,.estline input.uprice:focus{border-color:var(--accent);background:var(--surface)}
.estline .rm{width:34px;height:34px;display:inline-flex;align-items:center;justify-content:center;border:0;background:transparent;
  color:var(--faint);border-radius:var(--radius-s);cursor:pointer}
@media (hover:hover){.estline .rm:hover{color:var(--danger);background:var(--danger-soft)}}
.estline.stale{background:var(--warn-soft)}
.estline input.uprice.is-zero{border-color:var(--warn-line);background:var(--warn-soft)}

/* КОШТОРИС ЗГРУПОВАНИЙ ПО КІМНАТАХ (2026-09-30). Група = картка: заголовок-кнопка (назва, площа,
   скільки позицій, сума) + тіло, яке зʼявляється лише в розгорнутій. Заголовок ЛИПКИЙ: у рядках
   назви кімнати більше немає, а розгорнута кімната довша за екран — без нього, прокрутивши до
   пʼятої позиції, вже не видно, чия вона. Через це картка не сміє мати `overflow` (липкість
   рахується від найближчого предка, що гортається). */
.estgroup{margin-bottom:var(--space-2)}
.estg-head{position:sticky;top:0;z-index:2;display:flex;align-items:center;gap:var(--space-2);width:100%;
  min-height:60px;padding:var(--space-2) var(--space-3);border:0;border-radius:var(--radius);
  background:var(--surface);color:inherit;font:inherit;text-align:left;cursor:pointer}
@media(min-width:768px){.estg-head{top:52px}}        /* під липкою .topbar */
.estgroup.is-open .estg-head{border-bottom:1px solid var(--line);border-radius:var(--radius) var(--radius) 0 0}
.estg-chev{flex:none;display:inline-flex;color:var(--muted);transition:transform .15s}
.estgroup.is-open .estg-chev{transform:rotate(90deg)}
.estg-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.estg-name{font-size:15px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.estg-meta{display:flex;flex-wrap:wrap;align-items:center;gap:2px 6px;font-size:12px;color:var(--muted)}
.estg-sum{flex:none;font-size:15px;font-weight:600}
.estgroup--stale .estg-head{background:var(--warn-soft)}
/* Цілі дотику кошторису не виділяються як текст. Знято на симуляторі iPhone 17 Pro 2026-09-30: затримка
   пальця на картці кімнати починала системне виділення — синя заливка через пів екрана й лупа
   замість розгортання. Полям у розкритій позиції виділення ПОВЕРТАЄМО явно: у WebKit поле
   всередині предка з `user-select:none` інакше може не приймати курсор. */
.estg-head,.estclient,.estset,.esttable tr.estline,.esttable tr.estkind{user-select:none;-webkit-user-select:none}
.estline input{user-select:text;-webkit-user-select:text}
@media (hover:hover){.estg-head:hover{background:var(--surface-2)}}

/* Замовник — один рядок-кнопка над кімнатами; налаштування підсумку — рядок у картці підсумків.
   Обидва відкривають шторку (див. коментар над `clientRowHTML` в estimate.js). */
.estclient{display:flex;align-items:center;gap:var(--space-3);width:100%;min-height:56px;margin:0 0 var(--space-3);
  padding:var(--space-2) var(--space-3);color:inherit;font:inherit;text-align:left;cursor:pointer}
.estclient .m{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.estclient .a{font-size:14.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.estclient .a--empty{font-weight:500;color:var(--muted)}
.estclient .b{font-size:12.5px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.estclient .i,.estset .i{flex:none;display:inline-flex;color:var(--muted)}
.estset{display:flex;align-items:center;gap:var(--space-2);width:100%;min-height:var(--tap);margin-top:var(--space-3);
  padding:var(--space-2) 0 0;border:0;border-top:1px solid var(--line);background:none;color:inherit;font:inherit;
  font-size:14px;text-align:left;cursor:pointer}
.estset .v{flex:1;min-width:0;text-align:right;font-size:13px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (hover:hover){.estclient:hover{background:var(--surface-2)}}

.esttable{width:100%}
/* «Роботи» / «Матеріали» — смугою на всю ширину: дрібний сірий підпис без тла губився між рядками. */
.estkind th{padding:7px var(--space-3);border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  background:var(--surface-2);font-size:11px;letter-spacing:.05em;text-transform:uppercase;color:var(--ink);font-weight:600}
.esttable tbody:first-of-type .estkind th{border-top:0}
.estkind th>div{display:flex;justify-content:space-between;gap:var(--space-3)}
.estkind .money{letter-spacing:0;font-weight:500;color:var(--muted)}
.estline .u{font-size:12.5px;color:var(--muted)}
.estline button.nm{display:block;width:100%;padding:0;border:0;background:none;color:inherit;font:inherit;font-size:14px;text-align:left;cursor:pointer}
.estsrc{display:inline-flex;align-items:center;gap:6px;padding:0;border:0;background:none;color:inherit;font:inherit;cursor:pointer}
.estsrc .badge{cursor:inherit}
.estline .rm-t{display:none}
/* клітинки, які існують лише для телефона */
.esttable .c-meta,.esttable .c-src,.esttable .c-done{display:none}
/* «Який клей» на широкому екрані — під назвою, у тій самій клітинці не вміщується; ховаємо (правиться на телефоні). */
.esttable .c-kind{display:none}
.estwarn p{margin:0}
.estwarn>:not(:first-child){margin-top:8px}   /* (0,2,0) — інакше перемагає `.estwarn p{margin:0}` */
.estwarn a{color:inherit;font-weight:600}
/* Рядок попередження з дією («Прибрати позиції», «Додати в кошторис»): кнопка на білому, бо на
   жовтому тлі прозора .btn читалась би як ще один рядок тексту. */
.estwarn-i .btn{margin-top:6px;background:var(--surface);color:var(--ink)}
@media (hover:hover){.estwarn-i .btn:hover{background:var(--surface-2)}}

/* Шторка «Нова кімната»: назва з позначкою «включити», під нею — атрибути, відступлені під чекбокс
   (18 px + проміжок 10 px), щоб читались як властивості саме цієї кімнати. */
.estnew+.estnew{border-top:1px solid var(--line);margin-top:var(--space-2);padding-top:var(--space-2)}
.estnew-a{padding-left:28px}
.estnew.is-off .estnew-a{opacity:.45}

/* «Останній PDF»: другий рядок-кнопка картки підсумків і шторка зі знімками. */
.estset+.estset{margin-top:0}
.estset .v--warn{color:var(--warn)}
.estsent-r{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-2) 0;border-top:1px solid var(--line)}
.estsent-r:first-child{border-top:0}
.estsent-r .m{flex:1;min-width:0}
.estsent-r .a{font-size:14.5px;font-weight:600}
.estsent-r .b{font-size:12.5px;color:var(--muted)}

/* ПОЗИЦІЯ НА ТЕЛЕФОНІ — РЯДОК ТЕКСТУ; ПОЛЯ ЗʼЯВЛЯЮТЬСЯ В РЯДКУ, ЯКОГО ТОРКНУЛИСЬ (чому — коментар над
   `formulaHTML` в estimate.js):
     назва ……………………………………………… 4 968,62
     4,86 м² × 889 грн × 1,15
   `tr` — flex-контейнер із примусовими переносами: `::before` після першого рядка і (лише в
   розкритому) `::after` перед рядком дій. Клітинки з полями ті самі, що на широкому екрані
   стоять таблицею; тут вони сховані, доки рядок не дістане `.is-edit`. */
@media(max-width:767px){
  .esttable,.esttable tbody{display:block}
  .esttable thead{display:none}
  .esttable tr.estkind,.esttable .estkind th{display:block}
  .esttable tr.estline{display:flex;flex-wrap:wrap;align-items:flex-start;gap:2px 6px;
    padding:10px var(--space-3);border-top:1px solid var(--line);cursor:pointer}
  .esttable .estkind+tr.estline{border-top:0}
  .esttable tr.estline::before{content:"";order:3;flex-basis:100%;height:0}
  .esttable .estline td{display:block;padding:0;border:0}
  .esttable .estline .c-qty,.esttable .estline .c-unit,.esttable .estline .c-price,
  .esttable .estline .c-coef,.esttable .estline .c-rm,.esttable .estline .c-src,.esttable .estline .c-done,.esttable .estline .c-kind{display:none}
  .estline .c-nm{order:1;flex:1 1 0;min-width:0}
  .estline .nm{line-height:21px}
  .estline .c-sum{order:2;font-size:14px;font-weight:600;line-height:21px}
  .esttable .estline .c-meta{display:block;order:4;flex-basis:100%;font-size:14px;line-height:21px;color:var(--muted)}
  .estline .c-meta .n{color:var(--ink)}
  .estline .c-meta .g{white-space:nowrap}
  .estline .c-meta .w{color:var(--warn);font-weight:600}
  .estman{display:inline-block;margin-left:8px;padding:0 7px;border-radius:999px;background:var(--surface-2);
    font-size:11px;font-weight:600;line-height:18px;color:var(--muted);vertical-align:1px}

  /* розкритий рядок */
  .esttable tr.estline.is-edit{background:var(--surface-2);cursor:default;row-gap:0}
  .esttable tr.estline.is-edit::after{content:"";order:7;flex-basis:100%;height:0}
  .esttable .estline.is-edit .c-meta{display:none}
  .esttable .estline.is-edit .c-qty,.esttable .estline.is-edit .c-price{display:block;flex:1 1 0;min-width:0;margin-top:6px;text-align:left}
  .estline.is-edit .c-qty{order:4}
  .estline.is-edit .c-price{order:5}
  .estline.is-edit .c-qty::before,.estline.is-edit .c-price::before{content:attr(data-l);display:block;margin-bottom:3px;
    font-family:var(--sans);font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--muted)}
  .estline.is-edit input.qty,.estline.is-edit input.uprice{width:100%;min-height:var(--tap);padding:8px 12px;text-align:left;
    border-color:var(--line-2);background:var(--surface)}
  .estline.is-edit input.uprice.is-zero{border-color:var(--warn-line);background:var(--warn-soft)}
  .esttable .estline.is-edit .c-src{display:flex;order:6;flex-basis:100%;align-items:center;gap:var(--space-3);
    min-height:30px;margin-top:2px;font-size:12.5px;color:var(--muted)}
  .esttable .estline.is-edit .c-src:empty{display:none}
  /* «Який клей» — над «з плану», на всю ширину (клей мішками, 2026-10-23) */
  .esttable .estline.is-edit .c-kind{display:block;order:6;flex-basis:100%;margin-top:var(--space-2)}
  .estkind-l{display:block;margin-bottom:3px;font-size:11px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--muted)}
  .estline.is-edit .c-kind select{width:100%;min-height:var(--tap);background:var(--surface)}
  .estplan{display:inline-flex;align-items:center;gap:5px;min-height:30px;padding:0;border:0;background:none;
    color:var(--accent-d);font:inherit;font-weight:600;cursor:pointer}
  .estk{margin-left:auto}
  .esttable .estline.is-edit .c-rm,.esttable .estline.is-edit .c-done{display:block;margin-top:var(--space-2)}
  .estline.is-edit .c-rm{order:8}
  .estline.is-edit .c-done{order:9;margin-left:auto}
  .estline.is-edit .rm{width:auto;height:34px;padding:0 var(--space-3);gap:6px;border:1px solid var(--danger);
    border-radius:var(--radius-s);background:var(--surface);color:var(--danger);font:inherit;font-size:13px;font-weight:500}
  .estline.is-edit .rm-t{display:inline}
  .estline.is-edit .c-done .btn{background:var(--surface)}
}

/* На дотик немає :hover — inline-поля (к-сть/ціна) інакше виглядають як статичний текст.
   Тому на touch-пристроях завжди показуємо межу+фон, щоб було видно, що це редаговане поле. */
@media (hover:none){
  .pricerow .priceline input,
  .estline input.qty,
  .estline input.uprice{border-color:var(--line-2);background:var(--surface-2)}
}

.totals{margin-left:auto;max-width:360px;width:100%}
.totals .tr{display:flex;justify-content:space-between;gap:var(--space-3);padding:5px 0;font-size:14px}
.totals .tr .k{color:var(--muted)}
.totals .tr.grand{border-top:1.5px solid var(--ink);margin-top:6px;padding-top:10px;font-size:17px;font-weight:700}
.totals .tr.grand .k{color:var(--ink)}

.stickybar{position:fixed;left:0;right:0;bottom:calc(var(--tabbar-h) + env(safe-area-inset-bottom));z-index:35;
  background:var(--surface);border-top:1px solid var(--line);box-shadow:0 -2px 8px rgba(27,30,35,.06);
  display:flex;align-items:center;gap:var(--space-3);padding:var(--space-2) var(--space-4)}
@media(min-width:768px){.stickybar{bottom:0}}
/* Занурений екран (розкладка): таббара немає — панель сідає на самий низ */
.app.immersive .stickybar{bottom:env(safe-area-inset-bottom)}
.stickybar .sum{font-family:var(--mono);font-weight:600;font-size:16px}
.stickybar .lbl{color:var(--muted);font-size:12px}
.stickybar .spacer{flex:1}
.has-stickybar{padding-bottom:calc(var(--tabbar-h) + 84px) !important}
/* Рівно висота панелі + відступ. 84px (запас під таббар) лишали 37px фантомного скролу на
   екрані, під яким уже нічого немає — а сенс розкладки саме в тому, щоб не скролити. */
/* 61, а не 55: панель виросла, коли «Зберегти» стала повними 44px (прохід A). Це резерв
   МІСЦЯ під fixed-панель — розійдись він із її висотою, останній елемент потоку заліз би під неї. */
.app.immersive .has-stickybar{padding-bottom:calc(61px + var(--space-2)) !important}
/* Список кімнат: головна повторювана дія — під пальцем, перехід на наступний крок — поруч
   вторинним. Два акценти в шапці (Кошторис + Додати кімнату) конкурували за увагу. */
.stickybar--zones{gap:var(--space-2)}
.stickybar--zones .btn{flex:none}
.stickybar--zones .btn--primary{flex:1 1 auto;min-width:0}
/* На широкому екрані кнопка на пів-екрана виглядає як помилка — там вона по контенту. */
@media(min-width:768px){.stickybar--zones .btn--primary{flex:0 0 auto}}

/* каталог-пікер у кошторисі */
.catpick .item{display:flex;align-items:center;gap:var(--space-3);min-height:var(--tap);padding:4px var(--space-2);
  border-radius:var(--radius-s);cursor:pointer;border:0;background:transparent;width:100%;text-align:left}
@media (hover:hover){.catpick .item:hover{background:var(--surface-2)}}
.catpick .item .u{color:var(--muted);font-size:12px;white-space:nowrap}
.catpick .item .p{margin-left:auto;font-family:var(--mono);font-size:13px;white-space:nowrap}

/* ── Налаштування ── */
.brandlogo{width:120px;height:64px;border:1px dashed var(--line-2);border-radius:var(--radius-s);display:flex;
  align-items:center;justify-content:center;color:var(--faint);font-size:12px;overflow:hidden;background:var(--surface-2)}
.brandlogo img{max-width:100%;max-height:100%;object-fit:contain}

/* Хаб-налаштування: згруповані списки рядків */
.set-group{margin-bottom:var(--space-4)}
.set-group-label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;
  color:var(--muted);margin:0 0 var(--space-2);padding:0 var(--space-1)}
.set-group-label:empty{display:none}
.set-list{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow-sm);overflow:hidden}
.set-row{display:flex;align-items:center;gap:var(--space-3);min-height:56px;padding:8px var(--space-4);
  width:100%;text-align:left;background:transparent;border:0;color:var(--ink);font:inherit;text-decoration:none}
.set-row+.set-row{border-top:1px solid var(--line)}
.set-row--tap{cursor:pointer}
@media (hover:hover){.set-row--tap:hover{background:var(--surface-2)}}
.set-row__ic{flex:none;width:24px;color:var(--muted);display:inline-flex;align-items:center;justify-content:center}
.set-row--danger .set-row__ic{color:var(--danger)}
.set-row--danger .set-row__title{color:var(--danger)}
.set-row__title{flex:1 1 auto;min-width:0;font-size:15px;font-weight:500}
.set-row__lbl{flex:1 1 auto;display:flex;flex-direction:column;gap:1px;min-width:0}
.set-row__lbl .set-row__title{flex:none;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.set-row__sub{font-size:12.5px;color:var(--muted)}
.set-row__val{flex:none;color:var(--muted);font-size:14px;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;max-width:52%}
.set-row__chev{flex:none;color:var(--faint);display:inline-flex}
.set-avatar{flex:none;width:44px;height:44px;border-radius:999px;background:var(--accent-soft);
  color:var(--accent-d);font-weight:700;font-size:15px;display:flex;align-items:center;justify-content:center;letter-spacing:.02em}
.set-foot{color:var(--muted);font-size:12.5px;margin:calc(-1 * var(--space-2)) var(--space-1) 0;line-height:1.4}
@media(min-width:768px){.set-group,.set-foot{max-width:640px}}

/* Перемикач (switch) */
.switch{appearance:none;-webkit-appearance:none;flex:none;position:relative;width:44px;height:26px;
  border-radius:999px;background:var(--line-2);cursor:pointer;transition:background .15s;border:0}
.switch::after{content:"";position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:999px;
  background:#fff;box-shadow:var(--shadow-sm);transition:transform .15s}
.switch:checked{background:var(--accent)}
.switch:checked::after{transform:translateX(18px)}

/* Підекран профілю: пласка форма + секції */
.set-form{max-width:520px}
.set-section-label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;
  color:var(--muted);margin:var(--space-4) 0 var(--space-2)}
.set-form>.set-section-label:first-child{margin-top:0}
.set-logorow{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap}
.set-logoacts{display:flex;gap:var(--space-2);flex-wrap:wrap}

/* ── Дрібниці ── */
.toolrow{display:flex;gap:var(--space-2);align-items:center;flex-wrap:wrap;margin-bottom:var(--space-4)}
.toolrow .grow{flex:1;min-width:160px}
.divider{height:1px;background:var(--line);margin:var(--space-4) 0}
/* Нотатка-пояснення. ДЕФОЛТ — info (нема що виправляти); --warn лише коли є конкретна дія користувача. */
.note-callout{background:var(--info-soft);border:1px solid var(--info-line);border-radius:var(--radius-s);
  padding:var(--space-2) var(--space-3);font-size:13px;color:var(--info)}
.note-callout--warn{background:var(--warn-soft);border-color:var(--warn-line);color:var(--warn)}
.kv{display:flex;justify-content:space-between;gap:var(--space-3);padding:6px 0;font-size:14px}
.kv .k{color:var(--muted)}
details.adv{border:1px solid var(--line);border-radius:var(--radius-s);padding:0 var(--space-3);margin-bottom:var(--space-3)}
details.adv summary{min-height:var(--tap);display:flex;align-items:center;cursor:pointer;font-weight:500;font-size:14px;color:var(--muted)}
details.adv[open] summary{border-bottom:1px solid var(--line)}
details.adv .inner{padding:var(--space-3) 0}

/* ══════════ Екран «Зони» ══════════ */
/* — Список зон — */
/* align-items:start — інакше в дві колонки картка-план (з великою схемою) розтягує сусідню
   картку кімнати на свою висоту, і поруч зі схемою зяє порожнеча. */
.zlist{display:grid;grid-template-columns:1fr;gap:var(--space-3);align-items:start}
@media(min-width:768px){.zlist{grid-template-columns:1fr 1fr}}
/* Картка спільного плану — на ВСЮ ширину сітки. Сітка звичайна (не масонрі), тож висота ряду
   дорівнює найвищій картці: план із превʼю це 412px проти 98px у картки кімнати, і сусідня
   клітинка лишалась порожньою на 314px (заміряно). Це ж робить план явно головною сутністю
   екрана — кімнати під ним читаються як його склад, а не як рівноправні сусіди. */
.zcard--plan{grid-column:1/-1}
/* Превʼю плану на всю ширину роздувалось до 510px заввишки (заміряно): viewBox героя сталий
   640×400, тож висота = ширина картки / 1.6. Це ПРЕВʼЮ, а не робоче полотно — повний план за
   один тап. Стеля тримає його в межах двох карток кімнати; для витягнутого плану лишаються
   поля з боків, і це чесніше, ніж половина екрана під один малюнок. */
@media(min-width:768px){.zcard--plan .zc-hero svg{max-height:clamp(180px, 30vh, 280px)}}
/* Картка — колонка: верхній рядок (мініатюра/текст/дії) + смуга «Плитка» на всю ширину.
   Смуга мусить бути поза .zc-open, бо <a> не можна вкладати в <button>. */
.zcard{position:relative;display:flex;flex-direction:column;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius);box-shadow:var(--shadow-sm);overflow:hidden}
.zc-row{display:flex;align-items:stretch}
.zcard--ro{flex-direction:row;padding:var(--space-3) var(--space-4);align-items:center}
.zc-open{flex:1;display:flex;align-items:center;gap:var(--space-3);padding:var(--space-3);border:0;background:transparent;
  text-align:left;cursor:pointer;min-height:var(--tap);transition:background .12s}
@media (hover:hover){.zc-open:hover{background:var(--surface-2)}}
.zc-mini{width:96px;height:72px;flex:none;background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-s);
  display:flex;align-items:center;justify-content:center;padding:6px}
/* Картка спільного плану: великий контур ВСЕРЕДИНІ картки, а не окремим блоком над списком —
   інакше план і його підпис читаються як два різні елементи. Мініатюри .zc-mini тут немає. */
.zc-hero{background:var(--surface-2);padding:var(--space-3);border-bottom:1px solid var(--line)}
.zc-hero svg{display:block}
.zc-heroBtn{display:block;padding:0;flex:none;align-items:stretch}
.zc-main{flex:1;min-width:0}
.zc-nm{font-weight:600;font-size:15px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.zc-dim{font-family:var(--mono);font-size:12.5px;color:var(--ink);margin-top:2px}
.zc-sub{color:var(--muted);font-size:12.5px;margin-top:2px}
.zc-metric{flex:none;text-align:right;font-family:var(--mono);font-size:12px;color:var(--muted);display:flex;flex-direction:column;justify-content:center;padding-right:var(--space-2)}
.zc-metric b{font-size:16px;color:var(--ink)}
.zc-del,.zc-unlink{flex:none;width:var(--tap);border:0;border-left:1px solid var(--line);background:transparent;color:var(--faint);cursor:pointer;transition:color .12s,background .12s}
@media (hover:hover){.zc-del:hover{color:var(--danger);background:var(--danger-soft)}}
/* Розчеплення нічого не видаляє — тому акцент, а не danger. */
@media (hover:hover){.zc-unlink:hover{color:var(--accent);background:var(--accent-soft)}}
/* Дії картки — ОДНА вузька колонка (44px), кнопки одна над одною: два окремі
   стовпці по 44px з'їдали ширину .zc-main і текст картки починав налазити. */
.zc-acts{flex:none;width:var(--tap);display:flex;flex-direction:column;border-left:1px solid var(--line)}
.zc-acts>*{flex:1;min-height:38px;border-left:0}
.zc-acts>*+*{border-top:1px solid var(--line)}
/* Смуга «Плитка» — підписаний вхід у розкладку й водночас статус формату.
   Замінила німу іконку-сітку: її ніхто не знаходив. */
.zc-tile{display:flex;align-items:center;gap:8px;min-height:var(--tap);padding:0 var(--space-3);
  border-top:1px solid var(--line);background:var(--surface);color:var(--accent-d);
  font-size:13px;text-decoration:none;transition:background .12s}
.zc-tile>span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Та сама смуга, але кнопкою: «Розставити кімнати» в картці спільного плану. */
button.zc-tile{width:100%;border-left:0;border-right:0;border-bottom:0;font:inherit;font-size:13px;cursor:pointer;text-align:left}
/* Ховер — лише в того, хто веде кудись: німий рядок-факт підсвічуватись не сміє. */
@media (hover:hover){a.zc-tile:hover,button.zc-tile:hover{background:var(--accent-soft)}}
.zc-tile svg{flex:none}
/* Німий рядок-факт: кімната, чия сітка спільна з сусідками. Тон --muted за реєстром
   (виправляти користувачеві нічого — це стан, а не завдання), курсор і ховер відсутні,
   шеврона немає: усе, що відрізняє факт від дії. */
.zc-tile--mute{color:var(--muted);background:var(--surface-2);cursor:default}
/* «Плитку не обрано» — ГОЛОВНИЙ CTA флоу (кімнати → плитка → розкладка), тож не просто
   жовтий фон: жирний текст, рамка й стрілка-шеврон, що тягне око вправо. Тон warn правильний
   за реєстром (є що виправити користувачеві), тому колір лишається. */
.zc-tile--unset{color:var(--warn);background:var(--warn-soft);
  border-top-color:var(--warn-line);font-weight:600}
@media (hover:hover){.zc-tile--unset:hover{filter:brightness(.97)}}
/* На 375px мініатюра 96px + метрика 87px + дії 44px лишали .zc-main лише ~66px,
   і текст картки налазив сам на себе. Тиснемо мініатюру й метрику, не текст. */
@media(max-width:430px){
  .zc-mini{width:64px;height:52px}
  .zc-open{gap:var(--space-2);padding:var(--space-2)}
  .zc-metric{font-size:13px}
  .zc-metric b{font-size:15px}
}

/* — Редактор — */
/* Чотири числа шторки «Плитка» в ОДИН рядок. На 375px це ~77px на колонку — підпис 11px
   («Ширина, мм») і трицифрове значення влазять, а сітка 2×2 коштувала вдвічі більше висоти
   на шторці, яка накриває план. Проміжок вужчий за --space-3: він тут іде ×3. */
.dimgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--space-2)}
/* 11px, а не 10: це були найдрібніші літери в усьому застосунку — і стояли над чотирма
   найважливішими полями екрана (детектор ловив їх як undersized-ui-text ×4). Один рядок
   тримає ТІСНІШИЙ ТРЕКІНГ, а не менший кегль: «ШИРИНА, ММ» у звичайному .06em просить 85px
   на 80 доступних і переноситься, ламаючи вирівнювання сітки. Заміряно на 360 і 375px.
   Коментар тут ще й розходився з кодом — обіцяв 11px, а правило ставило 10. */
.dimgrid .numfield label{font-size:11px;letter-spacing:.01em;white-space:nowrap}
@media(min-width:520px){.dimgrid{gap:var(--space-3)}
  .dimgrid .numfield label{letter-spacing:.06em}}
.numfield{display:flex;flex-direction:column;gap:5px}
.numfield>label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
/* Шторка плитки: поки відкритий цифровий блок (`.tsheet--pad`), картки «Укладання» і «Готово» згорнуті
   в один рядок `.patsum` («Укладання: прямо · 90 шт», число живе на кожну цифру), а блок стоїть на їхньому
   місці — висоти він займає майже стільки ж, тож шторка не стрибає. Активне поле — `.is-active`: фокус
   з `inputmode="none"` на iOS не малює каретки, тож чиє число набирається, каже рамка. */
.tsheet:not(.tsheet--pad) .patsum,
.tsheet:not(.tsheet--pad) .tpadwrap,
.tsheet--pad .tsheet-pat,
.tsheet--pad .tsheet-act,
/* Шторка «Зʼєднати кімнати?» (`.jsheet`) — той самий устрій: блок на місці дій, вибір плитки — рядком. */
.jsheet:not(.jsheet--pad) .patsum,
.jsheet:not(.jsheet--pad) .tpadwrap,
.jsheet--pad .jsheet-mode,
.jsheet--pad .jsheet-act{display:none}
.tsheet .numfield.is-active .input,
.jsheet .field.is-active .input{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent)}
.jsheet .patsum{margin:0 0 var(--space-3)}
/* Числа прорізу — рядком-підсумком, поки їх не розгорнули (`.jsheet--nums`, iPhone-знахідка №2);
   у режимі блоку рядок не потрібен — поля вже на виду. Вибір плитки — дві кнопки в один ряд. */
.jsheet:not(.jsheet--pad) .jnums{display:flex}
.jsheet.jsheet--pad .jnums,.jsheet.jsheet--nums .jnums{display:none}
.jsheet:not(.jsheet--nums) .jnumbox{display:none}
.jsheet #jrMode{display:grid;grid-template-columns:1fr 1fr}
.jsheet #jrMode .chip{justify-content:center}
.jrshift{display:flex;gap:var(--space-2);align-items:stretch}
.jrshift .input{flex:1;min-width:0}
.jrshift .seg{flex:none}
.patsum{display:flex;align-items:center;gap:var(--space-2);width:100%;min-height:var(--tap);margin-top:var(--space-2);
  padding:0 var(--space-3);border:1px solid var(--line);border-radius:var(--radius-s);background:var(--surface-2);
  color:var(--ink);font:inherit;text-align:left;cursor:pointer;touch-action:manipulation}
.patsum-l{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
.patsum b{font-weight:600}
.patsum-n{color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}
.patsum svg{margin-left:auto;flex:none;color:var(--muted)}
.tpadwrap .npad{margin-top:var(--space-2)}
.numctl{display:flex;align-items:stretch;gap:var(--space-2)}
.numctl .input{flex:1;min-width:0;text-align:center;font-family:var(--mono)} /* 16px — із закону полів угорі */
.nbtn{flex:none;width:var(--tap);min-height:var(--tap);border:1px solid var(--line-2);border-radius:var(--radius-s);
  background:var(--surface);color:var(--ink);font-size:22px;line-height:1;cursor:pointer;touch-action:manipulation;
  display:flex;align-items:center;justify-content:center;transition:background .12s,border-color .12s}
/* Крок підписаний числом («−60»), а не знаком: 13px моно на 44px кнопці лишає запас до 3 цифр. */
.nbtn--n{font-family:var(--mono);font-size:13px;letter-spacing:-.03em}
@media (hover:hover){.nbtn:hover{background:var(--surface-2);border-color:var(--faint)}}
.nbtn:active{background:var(--accent-soft)}

.zpreview{padding:var(--space-3)}
.zsvg{width:100%;background:var(--surface-2);border-radius:var(--radius-s);touch-action:manipulation}
/* max-width тримає схему компактною на широкому екрані — інакше картка тягнеться
   на всю ширину, а план губиться посеред порожнечі */
.zsvg svg{display:block;max-height:44vh;max-width:min(100%,620px);margin:0 auto}

/* Вибір способу замикання при розбіжності (G1) */
.closeopt{display:flex;align-items:center;gap:var(--space-3);width:100%;min-height:var(--tap);
  padding:var(--space-3);margin-bottom:var(--space-2);text-align:left;cursor:pointer;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-s)}
.closeopt:last-child{margin-bottom:0}
.closeopt--primary{border-color:var(--accent);background:var(--accent-soft)}
.closeopt-nm{font-weight:600;font-size:14px;display:flex;flex-direction:column;gap:2px}
.closeopt-go{margin-left:auto;color:var(--muted);font-family:var(--mono)}

.zsection{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:var(--space-3) var(--space-4)}
.zsec-head{display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-2)}
.zsec-head h2{font-size:15px;font-weight:600;margin:0}
.zsec-head .btn{margin-left:auto}
/* ряд пресет-чіпсів (швидкі типові значення) під числовим полем */
.chiprow{margin-top:6px}
/* 32px були нижчі за мінімальну ціль (--tap 44) — і це ряди, у які цілять швидко, тримаючи
   телефон однією рукою над кімнатою. Кегль лишається 13px: 44 дає палець, а не гучність. */
.chiprow .chip{min-height:var(--tap);font-size:13px}

.modrow{display:flex;align-items:center;gap:var(--space-3);min-height:var(--tap);padding:var(--space-2) 0;
  border-bottom:1px solid var(--line);cursor:pointer}
.modrow:last-child{border-bottom:0}
.modrow-ic{width:26px;height:26px;flex:none;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-xs);font-size:11px}
.modrow-ic.bump{background:var(--accent-soft);color:var(--accent-d)}
.modrow-ic.notch{background:var(--surface-2);color:var(--muted);border:1px solid var(--line-2)}
.modrow-nm{font-weight:500;font-size:14px;display:flex;flex-direction:column}
.modrow-sub{font-size:12px;color:var(--muted);font-weight:400}
.modrow-dim{margin-left:auto;font-family:var(--mono);font-size:13px;color:var(--muted)}
/* Рядок кімнати з дією: тап-зона — справжня <button> на всю ширину, «Відʼєднати» — окрема
   кнопка поруч. Раніше роль кнопки несла сама .modrow, тож дію не було куди покласти, не
   вкладаючи інтерактивне в інтерактивне — і вона висіла в рядку ПРОРІЗУ, підписана «Проріз N».
   Іконка — розірваний ланцюг, не кошик: кімната не зникає, а виходить із плану. */
.modrow--act{gap:0;padding:0}
.modrow-main{flex:1;min-width:0;display:flex;align-items:center;gap:var(--space-3);
  min-height:var(--tap);padding:var(--space-2) 0;
  background:none;border:0;cursor:pointer;font:inherit;color:inherit;text-align:left}
.modrow-rm{flex:none;width:var(--tap);height:var(--tap);display:flex;align-items:center;justify-content:center;
  background:none;border:0;cursor:pointer;color:var(--faint);border-radius:var(--radius-s);
  transition:color .12s,background .12s}
@media (hover:hover){.modrow-rm:hover{color:var(--accent);background:var(--accent-soft)}}

.doorrow{display:flex;align-items:center;gap:var(--space-3);min-height:var(--tap);padding:var(--space-1) 0}
.doorrow-l{flex:1;font-size:14px}
.doorctl{align-items:center;gap:6px}
.doorctl .input{width:96px;text-align:right;font-family:var(--mono)}
.doorrow-u{color:var(--muted);font-size:12.5px}
.doorrow-rm{flex:none;width:var(--tap);height:var(--tap);border:0;background:transparent;color:var(--faint);cursor:pointer;border-radius:var(--radius-s)}
@media (hover:hover){.doorrow-rm:hover{color:var(--danger);background:var(--danger-soft)}}

/* ── Редактор кімнати · canvas-first (design/pencil «1. Canvas-First Editor») ──
   Занурений екран: план — головний обʼєкт, усе інше тулиться до країв. Таббар
   ховається, бо редагування кімнати — окремий режим, а не сторінка в навігації. */
.app.immersive .tabbar{display:none}
.zed{position:fixed;inset:0;z-index:30;display:flex;flex-direction:column;background:var(--bg)}
@media(min-width:768px){.zed{top:52px}}   /* не перекривати десктопний .topbar (z-index 40) */

.zed-top{flex:none;display:flex;flex-direction:column;gap:var(--space-2);background:var(--surface);
  padding:14px var(--space-4) 12px;box-shadow:0 2px 8px rgba(27,30,35,.06);
  padding-top:calc(14px + env(safe-area-inset-top))}
.zed-head{display:flex;align-items:center;gap:var(--space-2)}
.zed-name{flex:1;min-width:0;display:flex;align-items:center;gap:var(--space-2);min-height:var(--tap);
  border:0;background:transparent;padding:0;text-align:left;cursor:pointer;color:var(--ink)}
/* 18px — той самий рядок, що в .lhead/.zhead/.phead h1: усі занурені екрани звуть себе однаково. */
.zed-name b{font-size:18px;font-weight:700;letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.zed-name span{flex:none;display:flex;color:var(--muted)}
@media (hover:hover){.zed-name:hover span{color:var(--accent-d)}}

.zed-stats{display:grid;grid-template-columns:1fr 1fr 1fr;gap:var(--space-2)}
.statchip{display:flex;flex-direction:column;align-items:center;gap:2px;background:var(--surface-2);
  border-radius:var(--radius-s);padding:8px 6px}
.statchip i{font-style:normal;font-size:10px;font-weight:600;letter-spacing:.4px;text-transform:uppercase;color:var(--muted)}
.statchip b{display:flex;align-items:flex-end;gap:2px;font-family:var(--mono);font-size:18px;font-weight:600;line-height:1.1}
.statchip b s{text-decoration:none;font-size:11px;font-weight:400;color:var(--muted);padding-bottom:2px}

/* колонка: план забирає всю вільну висоту, підвал (підказка + кнопки фази) — скільки треба.
   Так рейки з розмірами ніколи не ховаються під текстом, хоч би скільки рядків він зайняв. */
.zed-canvas{flex:1;position:relative;min-height:0;display:flex;flex-direction:column;
  background:var(--surface-2);overflow:hidden;touch-action:manipulation}
.zed-plan{flex:1;min-height:0;touch-action:none}
/* Зум креслення редактора (2026-09-17). touch-action:none на самому кресленні — інакше браузер забирає
   пінч собі й масштабує СТОРІНКУ. Скролити тут нічого: .zed — fixed на весь екран. Кнопки — у шапці
   (див. `zoomUIHTML`): над кресленням вони накривали б числа. */
.zed-zoom{flex:none;display:flex;align-items:center;gap:4px}
.zed-zoom .zbtn{box-shadow:none;background:var(--surface)}
.zed-zoom .zbtn--wide{padding:0 10px}
.zed-zoom [hidden]{display:none}
.zed-plan svg{width:100%;height:100%}
.zed-plan [data-arrow]{transition:opacity .12s}
.zed-plan [data-arrow]:active{opacity:.55}
.zed-plan.pick-wall svg .rp-guide.guide--hot{opacity:1}
.zed-plan.pick-wall svg{cursor:crosshair}
/* підвал полотна: праворуч лишаємо колію під FAB, щоб текст і кнопки під нього не залазили */
.zed-foot{flex:none;display:flex;flex-direction:column;gap:8px;padding:0 84px 12px 12px}

.zed-hint{margin:0;text-align:center;font-size:13px;color:var(--muted)}
.zed-hint--danger{color:var(--danger);font-weight:500}   /* лише коли «Зберегти» справді заблоковано */
.zed-hint--accent{color:var(--accent-d);font-weight:600}
/* Керування фазою малювання — макет його не показує, але це живі функції редактора
   (крок назад / перемикач кінця / замкнути), тож вони живуть у підвалі полотна. */
/* Підвал фази малювання: два яруси за ВАГОЮ, а не рівний ряд однакових кнопок.
   Верхній — корекція (undo, привид) і стан (сегмент «звідки будуємо»); нижній — головна
   дія фази на всю ширину. Доти три різні жанри стояли однаковими `.btn--sm`, і жоден не
   читався правильно. */
.zed-acts{display:flex;flex-direction:column;gap:6px}
.zed-acts-row{display:flex;align-items:center;gap:var(--space-2)}
.zed-acts .btn{box-shadow:var(--shadow-sm)}
.zed-undo{flex:none;box-shadow:none !important}      /* корекція не конкурує з дією */
.zed-acts .seg{flex:none;margin-left:auto;background:var(--surface)}
.seg--sm button{min-height:34px;padding:0 var(--space-3);font-size:13px}
/* «Інші способи» у шторці замикання — розкриття. Показуємо лише тоді, коли поруч стоїть
   прямокутник: решта способів дороблює стіну, якої майстер не міряв, тобто це запасний вихід,
   а не рівноцінний вибір (заміри — над `WALK_AUTO_RECT`). */
.closemore{margin-top:var(--space-3)}
.closemore>summary{list-style:none;cursor:pointer;color:var(--muted);font-size:13px;
  min-height:var(--tap);display:flex;align-items:center;gap:6px}
.closemore>summary::-webkit-details-marker{display:none}
.closemore>summary::after{content:"▾";font-size:11px;transition:transform .15s}
.closemore[open]>summary::after{transform:rotate(180deg)}
/* Головна дія фази. Вимкнена — НЕ приглушена теракота: `opacity:.5` на заливці дає блідий
   акцент, який читається як «наполовину активна». Поки замикати нема чого, кнопка нейтральна
   й мовчить, а причину називає підказка над нею. */
.zed-close{width:100%}
.zed-close:disabled{opacity:1;background:var(--surface-2);border-color:var(--line);color:var(--faint)}
.zed-acts #wFlip[aria-pressed="true"]{background:var(--accent-soft);border-color:var(--accent);color:var(--accent-d)}
.zed-fab{position:absolute;right:16px;bottom:12px;width:56px;height:56px;display:flex;align-items:center;justify-content:center;
  border:0;border-radius:var(--radius-s);background:var(--accent);color:#fff;cursor:pointer;box-shadow:var(--shadow-lg);
  transition:background .15s,transform .1s}
@media (hover:hover){.zed-fab:hover{background:var(--accent-d)}}
.zed-fab:active{transform:scale(.96)}
.zed-fab:disabled{background:var(--line-2);color:var(--surface);cursor:not-allowed;box-shadow:none}

/* Радіус і тінь — ті самі, що в .stickybar/.tabbar: це смуга при нижньому краї, під яку
   заходить контент, а не модалка поверх сторінки. */
/* Ввід довжини стіни — панель У ПОТОЦІ, не шухляда. Заміряно 2026-09-05 на стані «дві
   стіни намальовано»: шухляда накривала 302 з 434pt полотна (70%), і у видимій смузі
   не лишалось ЖОДНОЇ стіни — план фітиться по центру повної коробки, тобто цілком під
   нею. Стеля 52dvh це лікувала, але зсувала нумпад під фолд, тобто ламала рівно те,
   заради чого нумпад і заведено. У потоці полотно стискається (flex:1 + min-height:0),
   `watchCanvas` перефітить SVG сам, і креслення з усіма 12 клавішами видно одночасно.
   Радіус і тінь — смуги при нижньому краї, як у .zed-peek і .stickybar, а не модалки. */
/* Під час вводу ця панель — НАЙНИЖЧИЙ елемент екрана (смугу «Елементи» знято), тож інсет
   безпечної зони обовʼязковий: у standalone-режимі з домашнього екрана (manifest має
   display:standalone) нижньої панелі Safari немає, і клавіша ✓ сідала б на смугу
   home-indicator. Усі сім інших нижніх поверхонь таблиці стилів інсет мають. */
.zed-entry{flex:none;background:var(--surface);border-radius:var(--radius) var(--radius) 0 0;
  box-shadow:0 -2px 8px rgba(27,30,35,.06);
  padding:12px var(--space-4) max(8px, env(safe-area-inset-bottom))}
.zed-entry-head{display:flex;align-items:center;gap:var(--space-2);margin-bottom:var(--space-2)}
.zed-entry-head b{flex:1;min-width:0;font-size:16px;font-weight:600}
/* При редагуванні місце заголовка займає сегмент типу: заголовок і так казав лише тип,
   а сегмент його ще й міняє — один рядок замість двох, які кажуть те саме. */
.zed-entry-head .seg{flex:none;margin-right:auto}
/* `.sheet > .sheet-x` навмисно обмежене прямим нащадком шухляди, тож 44px сюди не діставали. */
.zed-entry-head .sheet-x{position:static;flex:none;width:var(--tap);height:var(--tap)}

/* Панель — `flex:none`, полотно — `flex:1`, тож на низькому екрані все стиснення бере на
   себе креслення: заміряно на 375×553 (SE у Safari з обома смугами) панель 420px і полотно
   РІВНО 63px, тобто виграш від переносу вводу в потік там дорівнював нулю. Тому на низьких
   екранах коротшає сама панель: клавіші сідають на мінімум `--tap` замість 52 (−32px),
   гапи −6, відступи −12, а рядок про прямі кути ховається (−26). Разом ~76px, і полотно
   з 63 стає 139. Нижче 44px клавіші не опускаємо за жодних умов — це підлога цілі дотику,
   а не стильова величина. */
@media (max-height:640px){
  .zed-entry{padding-top:8px}
  .zed-entry-head{margin-bottom:4px}
  .zed-entry .field{margin-bottom:4px}
  .zed-entry-ang{display:none}
  .zed-entry .npad{gap:6px}
  .zed-entry .npad-k{min-height:var(--tap)}
  /* Панель елемента коротшає тим самим прийомом: клавіші на мінімум цілі, комірки нижчі
     на висоту одного відступу. Нижче 44px клавіші не опускаємо за жодних умов. */
  .elentry .eldisp{padding:3px 8px 5px}
  .elentry .elmore{margin-top:4px}
  .elentry .elmore-f{min-height:38px}
}
.zed-entry .field{margin-bottom:var(--space-2)}
.zed-entry-ang{margin:0 0 var(--space-2)}
/* Панель лишається смугою при нижньому краї на будь-якій ширині, але КОНТРОЛИ на широкому
   екрані не розтягуються: заміряно на 1100px — клавіші й комірки виходили по 351px кожна,
   тобто цифровий блок ставав стіною, а трійка чисел — трьома банерами. 520px — та сама
   міра, що в `.sheet` на десктопі, тож обидві оболонки вводу міряються однаково. */
@media(min-width:768px){ .zed-entry>*{max-width:520px;margin-left:auto;margin-right:auto} }

/* ── Панель елемента: три числа в ряд + цифровий блок ──
   Оболонку бере в `.zed-entry` (поверхня, тінь, safe-area, ущільнення на низьких екранах);
   тут — лише те, чого у вводу стіни немає: ряд із трьох цілей замість одного поля.
   Кожна комірка — ПІДПИС НАД ЧИСЛОМ, а не збоку: на 360px три колонки дають ~104px, і
   «Праворуч 2750» в один рядок не влазить ніколи. `<label>`, тож тап по підпису теж
   фокусує число. */
.elrow3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:var(--space-2)}
.eldisp{display:flex;flex-direction:column;gap:1px;min-width:0;cursor:pointer;
  background:var(--surface);border:1px solid var(--line-2);border-radius:var(--radius-s);
  padding:5px 9px 7px;transition:border-color .12s,background .12s,box-shadow .12s}
.eldisp-cap{font-size:11px;line-height:1.3;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* 20px, моноширинні: це число їде в кошторис (Правило рахунку). Порожня рамка й прозоре
   тло — коробка вже намальована самою коміркою, друга рамка робила б поле в полі. */
.eldisp-v{width:100%;min-width:0;border:0;background:transparent;padding:0;
  font-family:var(--mono);font-size:20px;font-weight:600;line-height:1.25;color:var(--ink)}
/* Стан фокуса малює САМА КОМІРКА (`.is-active`: рамка + заливка + темніший підпис), тож
   кільце браузера всередині неї — другий індикатор на ту саму подію. Гасимо і `:focus`, і
   `:focus-visible`: заміряно на iPhone 17 Pro 2026-09-06 — Safari рахує тап по текстовому
   полю за `:focus-visible` (поле ж приймає клавіатуру), і на пристрої в активній комірці
   малювалась ВКЛАДЕНА заокруглена рамка. У десктопному браузері цього не видно: там
   `:focus-visible` від миші не стріляє. Доступність не страждає — власний індикатор
   комірки помітніший за системний і працює однаково для миші, пальця й таба. */
.eldisp-v:focus,.eldisp-v:focus-visible{outline:none;box-shadow:none}
/* Ширина отвору теракотова тим самим кольором, що проріз на кресленні, а «ліво/право» —
   сірі, як стіна. Панель говорить словником плану, а не власним. */
.eldisp--main .eldisp-v{color:var(--accent-d)}
/* Активна ціль цифрового блоку — рамка ПЛЮС заливка: один лише колір рамки на 1px губиться
   на витягнутій руці, а без явної цілі клавіші не мають куди писати. */
.eldisp.is-active{border-color:var(--accent);background:var(--accent-soft);box-shadow:inset 0 0 0 1px var(--accent)}
/* Підпис на теракотовій заливці мусить потемніти: `--muted` на `--accent-soft` дає 3.71:1
   при потрібних 4.5 для 11px, `--accent-d` — 4.80. Заміряно 2026-09-06. */
.eldisp.is-active .eldisp-cap{color:var(--accent-d)}

/* Тихий рядок під трійкою: глибина (у дверей — товщина стіни) і, при редагуванні,
   «Видалити». Дві різні речі на протилежних кінцях рядка: факт, який зрідка правлять,
   і руйнівна дія, яка не сміє стояти поруч із «Готово». */
.elmore{display:flex;align-items:center;gap:var(--space-2);margin-top:var(--space-2)}
.elmore-f{flex:1;min-width:0;display:flex;align-items:center;gap:var(--space-2);min-height:var(--tap);cursor:pointer}
/* Підпис тулиться до свого числа, а порожнє місце йде МІЖ групами (`margin-left:auto` на
   кнопці): «Глибина 100 мм» — одна річ, «Видалити» — інша, і розрив мусить стояти між
   ними, а не всередині. Стискається при тісноті підпис, не кнопка. */
.elmore-cap{flex:0 1 auto;min-width:0;font-size:13px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.elmore-v{flex:none;width:68px;text-align:right;color:var(--ink);
  border:1px solid var(--line-2);border-radius:var(--radius-s);background:var(--surface);
  padding:5px 8px;font-family:var(--mono);font-size:16px;font-weight:600;
  transition:border-color .12s,background .12s,box-shadow .12s}
.elmore-v:focus,.elmore-v:focus-visible{outline:none;box-shadow:none}
.elmore-f.is-active .elmore-v{border-color:var(--accent);background:var(--accent-soft);box-shadow:inset 0 0 0 1px var(--accent)}
.elmore-u{flex:none;font-size:12px;color:var(--muted)}
.elmore .btn{flex:none;margin-left:auto}
/* Заміряно 2026-09-06: підписана кнопка (111px) лишає підпису «Товщина стіни» 81px на 340px
   ширини при потрібних 95 — тобто нижче ~355px рядок обрізав саме те слово, що пояснює
   число. Правило мовчазного підпису забороняє обрізку, тож ріжемо КНОПКУ, а не підпис:
   нижче 360 вона стає іконкою (aria-label лишається), і підпис має запас навіть на 320.
   Так само вчиняє решта системи — не влазить, отже не показуй. */
@media(max-width:359px){
  .elmore .btn>span{display:none}
  .elmore .btn{width:var(--tap);padding:0;justify-content:center}
}
/* Сегмент типу в шухляді (у панелі він живе в голові) */
.elhead{margin-bottom:var(--space-3)}
/* Рядок помилки РЕЗЕРВУЄ свій рядок. Заміряно на iPhone 17 Pro: без резерву поява
   «Мінімум 300 мм» робила панель на 17px вищою → полотно (flex:1) на 17px нижчим →
   `watchCanvas` за порогом 8px перемальовував редактор, і план стрибав та перефічувався
   щоразу, коли число перетинало межу валідності. 17px тиші дешевші за стрибок креслення. */
/* Рядок повідомлення РЕЗЕРВУЄ свій рядок — і тепер це не комфорт, а вимога. Він стоїть НАД
   цифровим блоком, тож без резерву поява «Мінімум 300 мм» зсувала б усі 12 клавіш на 17px
   УНИЗ рівно тієї миті, коли по них влучають: натиснув «0» — отримав «⌫». Доки рядок жив
   під блоком, резерв був лише проти стрибка плану, і на низьких екранах його знімали заради
   17px полотна; після переїзду такий обмін неможливий. Заміряно 375×553: полотно 84 → 67. */
.elentry .err,.elform .err{margin:5px 0 0;min-height:17px}
/* Прив'язка повідомлення до комірки — вирівнюванням, бо рядок один на всі чотири числа.
   Глибина живе в рядку НИЖЧЕ, тож її повідомлення тримаємо ліворуч, як і саме поле. */
.err--l{text-align:left}
.err--c{text-align:center}
.err--r{text-align:right}

.zed-peek{flex:none;background:var(--surface);border-radius:var(--radius) var(--radius) 0 0;box-shadow:0 -2px 8px rgba(27,30,35,.06);
  padding:10px 20px calc(14px + env(safe-area-inset-bottom))}
.zed-grab{width:40px;height:4px;margin:0 auto 6px;border-radius:999px;background:var(--line-2)}
.zed-peekrow{display:flex;align-items:center;gap:var(--space-2)}
.zed-peekbtn{flex:1;min-width:0;display:flex;align-items:center;gap:8px;min-height:var(--tap);
  border:0;background:transparent;padding:0;text-align:left;cursor:pointer;color:var(--ink);font-size:14px;font-weight:600}
.zed-dots{display:flex;align-items:center;gap:4px}
.zed-dot{width:8px;height:8px;border-radius:999px;background:var(--line-2)}
.zed-dot--door{background:var(--accent)}
.zed-dot--bump{background:var(--ok)}
.zed-dot--notch{background:var(--warn)}
.zed-chev{margin-left:auto;display:flex;color:var(--muted)}
/* 44 — підлога цілі дотику (--tap), не стильова величина. Було 40. */
.zed-add{flex:none;width:var(--tap);height:var(--tap);display:flex;align-items:center;justify-content:center;
  border:1px solid var(--line);border-radius:999px;background:var(--accent-soft);color:var(--accent-d);cursor:pointer;
  transition:background .15s,color .15s,border-color .15s}
@media (hover:hover){.zed-add:hover{background:var(--accent);color:#fff;border-color:var(--accent)}}
/* Озброєно: та сама кнопка тепер знімає режим, тож і виглядає натиснутою. */
.zed-add--armed{background:var(--accent);color:#fff;border-color:var(--accent)}
@media (hover:hover){.zed-add--armed:hover{background:var(--accent-d);border-color:var(--accent-d)}}
/* Поки контур не замкнено, елементи додавати нема куди — обидві кнопки смуги вимкнені. */
.zed-peekbtn:disabled,.zed-add:disabled{opacity:.45;cursor:not-allowed}
.zed-add:disabled{background:var(--surface-2);color:var(--muted);border-color:var(--line)}
@media (hover:hover){.zed-peekbtn:disabled:hover,.zed-add:disabled:hover{background:var(--surface-2)}}

/* Шторка «Елементи» */
.elrow{display:flex;align-items:center;gap:var(--space-3);width:100%;min-height:var(--tap);padding:var(--space-2) 0;
  border:0;border-bottom:1px solid var(--line);background:transparent;text-align:left;cursor:pointer;color:var(--ink)}
.elrow:last-of-type{border-bottom:0}
.el-ic{flex:none;width:34px;height:34px;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-s)}
/* Меню стіни: іконка НЕЙТРАЛЬНА. «Виступ» і «Виріз» — це категорії, а не сигнали, тож
   сигнальні тони (--ok / --warn) тут не вживаються: жовтий «Виріз» читався б як
   попередження про виріз. Реєстр тонів, DESIGN.md. */
.el-ic--menu{background:var(--surface-2);color:var(--muted)}
@media (hover:hover){.elrow:hover .el-ic--menu{color:var(--accent-d)}}
.el-ic--door{background:var(--surface-2);color:var(--accent)}
.el-ic--bump{background:var(--ok-soft);color:var(--ok)}
.el-ic--notch{background:var(--warn-soft);color:var(--warn)}
.el-tx{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.el-tx b{font-size:15px;font-weight:600}
.el-tx span{font-size:13px;color:var(--muted)}
.el-dim{flex:none;font-family:var(--mono);font-size:14px}

/* Шторка «Додати елемент» — три чипи типу, більше нічого (міні-план «Рекомендовано: стіна N»
   прибрано, див. openAddSheet у screens/zones.js).
   margin-top, а не gap на `.sheet`: шторка — звичайний блок (`.sheet` не flex), тож кнопки
   стикались рамками — три різнокольорові чипи читались як один смугастий блок. */
.addchip{display:flex;align-items:center;gap:var(--space-3);width:100%;min-height:var(--tap);
  margin-top:var(--space-2);
  padding:var(--space-3);border:1px solid var(--line);border-radius:var(--radius-s);
  background:var(--surface);text-align:left;cursor:pointer;color:var(--ink)}
.addchip-ic{flex:none;width:34px;height:34px;display:flex;align-items:center;justify-content:center;
  border-radius:999px;color:#fff}
.addchip-tx{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.addchip-tx b{font-size:15px;font-weight:600}
.addchip-tx span{font-size:12px;color:var(--muted)}
.addchip-go{flex:none;display:flex;color:var(--muted)}
/* Картки НЕЙТРАЛЬНІ, колір лишається лише на іконці. Доти «Виступ» був зелений (--ok-soft),
   а «Виріз» жовтий (--warn-soft) — тобто сигнальні тони вживались як КАТЕГОРІЙНІ, і кімната
   з вирізом показувала жовту крапку, наче має проблему. Реєстр тонів (DESIGN.md) сортує за
   питанням «чи є що виправляти користувачеві?»; для типу елемента відповідь завжди «ні».
   Заодно теракотова картка «Двері» більше не читається як «рекомендовано» — вибір
   рівноправний. Та сама логіка, що в меню стіни (`.el-ic--menu`). */
.addchip{background:var(--surface)}
@media (hover:hover){.addchip:hover{background:var(--surface-2)}}
.addchip-ic{color:#fff}
.addchip--door .addchip-ic{background:var(--accent)}
.addchip--bump .addchip-ic{background:var(--ok)}
.addchip--notch .addchip-ic{background:var(--warn)}

/* — Спільні зони (обʼєднання) — */
.chip--state{min-height:22px;font-size:11px;font-weight:600;padding:0 8px}
.chip--through{background:var(--ok-soft);color:var(--ok);border-color:transparent}
/* split — свідомий вибір користувача, а не збій: нейтральний тон, не warn/danger */
.chip--split{background:var(--surface-2);color:var(--ink);border-color:var(--line-2)}
.chip--apart{background:var(--danger-soft);color:var(--danger);border-color:transparent}
.chip--offline{background:var(--warn-soft);color:var(--warn);border-color:transparent}   /* легасі: збережені проєкти + режим 'detector' */
.chip--error{background:var(--warn-soft);color:var(--warn);border-color:transparent}
.chip--pending{background:var(--surface-2);color:var(--muted)}
.doorrow-l .modrow-sub{display:block;font-size:12px;color:var(--muted);font-weight:400}

/* — Банд статусу спільного плану (through/apart/offline) — */
.statusband{display:flex;gap:var(--space-3);align-items:flex-start;padding:var(--space-3);margin-bottom:var(--space-3);
  border:1px solid var(--line);border-left-width:4px;border-radius:var(--radius-s);background:var(--surface)}
/* Тон = колір, який він називає (раніше --warn фарбувався в danger, а --info у warn — імена брехали). */
.statusband--ok{border-color:var(--ok);background:var(--ok-soft)}
.statusband--danger{border-color:var(--danger);background:var(--danger-soft)}
.statusband--warn{border-color:var(--warn);background:var(--warn-soft)}
.statusband--muted{border-color:var(--line-2);background:var(--surface-2)}
.statusband-ic{flex:none;display:flex;color:var(--ink);opacity:.75;margin-top:1px}
.statusband--ok .statusband-ic{color:var(--ok)}
.statusband--danger .statusband-ic{color:var(--danger)}
.statusband--warn .statusband-ic{color:var(--warn)}
.statusband-body{flex:1;min-width:0}
.statusband-t{font-weight:600;font-size:14px}
.statusband-p{font-size:13px;color:var(--muted);margin-top:2px;line-height:1.4}
.statusband--ok .statusband-p{color:var(--ok-ink)}
.statusband--danger .statusband-p{color:var(--danger-ink)}
.statusband--warn .statusband-p{color:var(--warn-ink)}
.statusband-actions{display:flex;flex-wrap:wrap;gap:var(--space-2);margin-top:var(--space-2);align-items:center}
/* Тон ok = виправляти нема чого → банд в один рядок, без тіла й дій (див. statusBandHTML).
   Сортувальний критерій реєстру тонів: «чи є що виправляти?». Кнопка «Перебудувати» на
   зеленому банді відповідала «так» там, де відповідь «ні». 38px замість ~157. */
.statusband--quiet{align-items:center;padding:var(--space-2) var(--space-3)}

/* — Прапорці готовності кімнати до стику (C1) — */
.chip--rd{min-height:22px;font-size:11px;font-weight:600;padding:0 8px}
.chip--rd-ok{background:var(--ok-soft);color:var(--ok);border-color:transparent}
.chip--rd-warn{background:var(--warn-soft);color:var(--warn);border-color:transparent}
.chip--rd-none{background:var(--danger-soft);color:var(--danger);border-color:transparent}

/* — Підвал полотна: режим дверей + живий фідбек драгу —
   Був рядок .plan-toolbar НАД полотном (кнопка + підказка режиму, 42px) і <p id="czHint">
   ПІД .czwrap. Обидва стосуються полотна, тож обидва переїхали в його підвал, за зразком
   .zed-foot у редакторі кімнати. Головне — не 42 зекономлені пікселі, а те, що #czHint несе
   snapFailReason («у «Кухня» немає дверей на цій стіні — додайте, тоді кімнати зчепляться»),
   а стояв під липкою панеллю або за фолдом: єдиний текст, який читають ПІД ЧАС драгу, лежав
   там, куди в цю мить не дивляться.
   Два рядки підказки зарезервовано (min-height 34) і закладено в chrome для --czh. Третій рядок
   діагнозу зростає ВНИЗ і полотно не рухає — висота .czsvg задана clamp'ом окремо. */
.czfoot{flex:none;display:flex;flex-direction:column;gap:6px;padding-top:var(--space-2)}
/* Повна кнопка, не `--sm`: DESIGN.md тримає малу «лише всередині карток і рядків», а ця стоїть
   окремим контролем у підвалі — і 34px були єдиною ціллю екрана нижче за мінімум 44. */
.czfoot-row{display:flex;align-items:center;gap:var(--space-2)}
.czfoot .btn{align-self:center;flex:none}
/* Зум полотна. Той самий словник, що `.lzoom` на #/layout — і та сама причина стояти в підвалі,
   а не над планом: накладка зʼїдає саме те, що оцінюють. Зʼявився разом із прибиранням драгу
   кімнат (2026-09-10): доки полотном тягали кімнати, пан сварився з драгом за той самий дотик. */
.czzoom{margin-left:auto;display:flex;gap:var(--space-1);flex:none}
.czzoom .zbtn{min-width:var(--tap);height:var(--tap)}
.czzoom .zbtn--wide{min-width:auto;padding:0 var(--space-3)}
/* На 360px «Додати двері» (149) і зум (182) переповнювали рядок 328 на 3px. Тісним рядок, а не
   переносимо: другий рядок коштував би полотну 44px, а це найдефіцитніший ресурс екрана. */
@media (max-width:400px){
  .czfoot-row{gap:var(--space-1)}
  .czzoom{gap:2px}
  .czzoom .zbtn--wide{padding:0 var(--space-2)}
}
/* Живий фідбек режиму, не помилка → нейтральний. «Увімкненість» несуть btn--primary і .czwrap--pick. */
.czfoot .hint{margin:0;min-height:34px}

/* ── Оболонка «Спільного плану» (той самий каркас, що .zed у редактора кімнати) ──
   Екран є РЕЖИМОМ прямого маніпулювання, а не сторінкою: полотно займає все, що лишив хром,
   а решта живе у шторках. Це не лише про висоту — це ще й лікує скрол.
   Було: полотно 307px усередині сторінки 1162px на вьюпорті 600 (заміряно) з touch-action:none.
   Тобто 51% екрана ковтав свайп, а під фолдом лежало 562px секцій, які дублювали те, що вже
   намальовано на полотні. У fixed-оболонці скролити НЕМА ЧОГО, тож touch-action:none знову
   коректний — той самий критерій, що записаний над .lstage.
   Полотно 408px при 600 і 620 при 812. Висоту дає flex, а НЕ формула: --czh із його виміряним
   `chrome` (шапка+банд+підвал+панель) видалено — коробку тепер міряють, а не вгадують. */
.pln{position:fixed;inset:0;z-index:30;display:flex;flex-direction:column;background:var(--bg);
  padding:var(--space-2) var(--space-4) calc(var(--space-2) + env(safe-area-inset-bottom))}
.pln .czwrap{flex:1;min-height:0;display:flex}
.pln .czsvg{flex:1;height:auto;min-height:0}
/* Карусель кімнат — замінила смугу-шторку «Кімнати · N». Смуга була лічильником, за яким
   ховався список; карусель показує ті самі кімнати відразу і дає МІСЦЕ кандидатам, яких
   полотно більше не малює (див. canvasItems у screens/zones.js). Горизонтальний скрол —
   єдиний у застосунку: сторінка під ним не скролить ніколи (правило безскрольного екрана).
   Кандидат пунктирний, як .zghost на #/home: та сама мова «цього ще немає, але може бути». */
.pcar{flex:none;display:flex;gap:var(--space-2);margin-top:var(--space-2);
  overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.pcar::-webkit-scrollbar{display:none}
.pcar-card{flex:none;width:84px;display:flex;flex-direction:column;align-items:center;gap:2px;
  padding:var(--space-1) 4px;background:var(--surface);border:1px solid var(--line);
  border-radius:var(--radius-s);font:inherit;color:inherit;cursor:pointer;
  transition:background .15s,border-color .15s}
.pcar-card--add{border-style:dashed;border-color:var(--accent);background:transparent}
@media (hover:hover){.pcar-card:hover{background:var(--surface-2)}}
@media (hover:hover){.pcar-card--add:hover{background:var(--accent-soft)}}
.pcar-fig{display:block;width:72px;height:44px;pointer-events:none}
.pcar-fig svg{display:block;width:100%;height:100%}
.pcar-nm{max-width:76px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:11px;line-height:1.2;color:var(--muted);pointer-events:none}
.pcar-card--add .pcar-nm{color:var(--accent-d)}
.pcar-sep{flex:none;width:1px;align-self:stretch;background:var(--line);margin:0 2px}
/* Мітки «куди стане кімната». Радіуси рахує renderPlan в екранних px через kPx — ціль дотику
   мусить бути пальцем (44px), а не часткою плану, яка росте й падає разом із масштабом. */
.cz-add{cursor:pointer}
.cz-add-hit{fill:transparent}
.cz-add-dot{fill:var(--accent);stroke:#fff;stroke-width:2;vector-effect:non-scaling-stroke;pointer-events:none}
@media (hover:hover){.cz-add:hover .cz-add-dot{fill:var(--accent-d)}}
/* Мітка, що ПРОРІЖЕ стіну кімнати без дверей (`cut`, zones-core.enumSnaps) — порожниста: доти вона
   виглядала так само, як мітка через власні двері кімнати, і лоджію приєднали до вхідних дверей
   коридору (симулятор власника 2026-10-03). Підказка під полотном і шторка кажуть це словами. */
/* Обрис майбутньої кімнати на мітці (варіант D, 2026-10-16): теракотовий — стане через свої двері,
   сірий — проріже стіну. Без цілі дотику: тапають мітку. */
.cz-ghostroom{pointer-events:none}
/* Дія в підказці режиму додавання (08 §7.1, п. 2): пари дверей немає — кнопка веде в редактор тієї кімнати. */
#czHint .czfix{display:flex;width:max-content;max-width:100%;align-items:center;margin-top:var(--space-2);gap:6px}
.czfix-list{display:flex;flex-direction:column;gap:var(--space-2)}
.cz-ghostroom path{fill:rgba(192,82,43,.06);stroke:var(--accent);stroke-width:1.5;stroke-dasharray:5 4;vector-effect:non-scaling-stroke}
.cz-ghostroom text{fill:var(--accent-d);font-weight:600;text-anchor:middle;font-family:inherit}
/* Стан плану — ПЛАВАЮЧОЮ карткою в полотні, а не бандом у потоці: у потоці він коштував
   50/157/217px висоти самому лише повідомленню. Тон ok сюди не потрапляє взагалі — про
   «плитка йде наскрізь» уже сказано чипом у шапці, і це був останній уцілілий дубль. */
.plnband{position:absolute;left:var(--space-2);right:var(--space-2);bottom:var(--space-2);z-index:3;
  box-shadow:var(--shadow-md);margin:0}

/* — Згортання секцій (мобільний довгий скрол) — */
.zsection--collapsible .zsec-head[data-sectoggle]{cursor:pointer;user-select:none;display:flex;align-items:center;justify-content:space-between}
.zsec-chevron{display:flex;color:var(--muted);transform:rotate(-90deg);transition:transform .15s ease}
.zsec-collapsed .zsec-chevron{transform:rotate(90deg)}
.zsec-collapsed .zsec-body{display:none}
@media (prefers-reduced-motion:reduce){.zsec-chevron{transition:none}}

/* — «Розставити кімнати» — пунктирна картка НА ПОЧАТКУ списку —
   Була кнопкою у .zbar під шапкою (разом з «Імпорт PDF»), тобто рядок над списком коштував
   60px завжди, а сама дія стосується кімнат, що лежать прямо під нею. Пунктир = «тут ще
   нічого немає, але може бути»: картка зникає, щойно спільний план створено (далі дія живе
   в його картці). Показуємо лише при ≥2 кімнатах, які полотно вміє тягати. */
.zghost{display:flex;align-items:center;gap:var(--space-3);width:100%;min-height:64px;
  padding:var(--space-3);border:1.5px dashed var(--line-2);border-radius:var(--radius);
  background:transparent;color:var(--ink);text-align:left;cursor:pointer;font:inherit;
  transition:background .12s,border-color .12s}
@media (hover:hover){.zghost:hover{background:var(--surface);border-color:var(--accent)}}
.zghost-ic{flex:none;width:34px;height:34px;display:flex;align-items:center;justify-content:center;
  border-radius:999px;background:var(--surface-2);color:var(--muted)}
.zghost-tx{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.zghost-tx b{font-size:15px;font-weight:600}
.zghost-tx span{font-size:12px;color:var(--muted)}
.zghost-go{flex:none;display:flex;color:var(--muted)}

/* — Зони кімнати (поверхні): Підлога / Стіни(v2) — */
.surf{border:1px solid var(--line);border-radius:var(--radius-s);padding:var(--space-3);margin-top:var(--space-2)}
.surf--active{border-color:var(--accent-soft);background:var(--surface)}
.surf--soon{opacity:.55}
.surf-head{display:flex;align-items:center;gap:8px;margin-bottom:var(--space-2)}
.surf-head b{font-size:14px}
.surf--soon .surf-head{margin-bottom:0}
.surf-sub{color:var(--muted);font-size:12px;font-weight:400}
/* Рядок-посилання на розкладку кімнати (split-план: у групи своєї плитки немає) */
.surf--link{display:block;text-decoration:none;color:inherit;background:var(--surface)}
@media (hover:hover){.surf--link:hover{background:var(--surface-2)}}
.surf--link .surf-head{margin-bottom:0}
.surf--link .surf-sub{margin-left:auto;margin-right:6px}
.surf--unset{border-color:var(--warn-line);background:var(--warn-soft)}
.surf--unset .surf-sub{color:var(--warn);font-weight:600}

/* — Полотно обʼєднання (drag-and-drop) — */
/* position:relative — якір для плаваючої підказки .tipchip (полотно не втрачає висоти) */
.czwrap{position:relative;background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-s);padding:var(--space-2);overflow:hidden}
/* Розмір полотна дає ФЛЕКС оболонки `.pln` (правило `.pln .czsvg` вище), а renderPlan його
   МІРЯЄ перед вставкою SVG — kPx потрібен до неї (товщина ліній, гейт двох меж шва).
   Було `--czh` із формули: аспект viewBox + підлога 320 + стеля «те, що лишив хром», де хром
   був сумою семи виміряних доданків, які зобовʼязували перемірювати їх після кожної правки
   розмітки. Формула існувала лише тому, що полотно жило в скрольованій сторінці; у fixed-
   оболонці коробку віддає браузер. Фолбек 44vh лишається для статичних копій без `.pln`. */
.czsvg{display:block;width:100%;height:44vh;
  touch-action:none;user-select:none;-webkit-user-select:none}
/* ══════════ ТІЛО КІМНАТИ · один словник на всі чотири поверхні ══════════
   Форми будує plan-draw.js (roomBodySVG / roomTilesSVG). Кімнату малюють сцена розкладки
   (#/layout — ЕТАЛОН, з якого взято вигляд), полотно спільного плану, редактор кімнати й
   герой картки — і доти кожна робила це своїм кодом, з двома кольорами стіни й трьома
   реалізаціями одного закону товщини. Розрізняти екрани має ЩО навколо кімнати, а не те,
   як намальована сама кімната.

   Товщина — у --rp-w / --rp-wa / --rp-seam: ЕКРАННІ px (бо non-scaling-stroke), число дає
   plan-draw.strokeLaw. Стала товщина була дефектом: склеєні кімнати стоять за товщину стіни
   одна від одної (100 мм ≈ 3.6px на типовому зумі), і два обводи по 3px лишали 0.6px
   просвіту — стіна читалась як одна товста лінія. Закон: між обводами ≥1px денного світла.
   Фолбеки в var() — щоб розмітка без змінних (тести, статичні копії) лишалась читною. */
/* Заливка — вона ж ціль тапа/драга кімнати, тому лишається в розмітці й тоді, коли її
   вкриває плитка: --under робить її прозорою, а не прибирає (плиткові шляхи діряві на швах,
   а обвід fill:none, тож без неї тап посеред кімнати пролітає повз). */
.rp-floor{fill:var(--accent-soft);stroke:none}
.rp-floor--under{fill:transparent}
/* СІРОЇ СМУГИ СТІНИ НЕМАЄ (2026-09-11, рішення власника: «сірі вставки, що імітують товщину
   стіни»). Між кімнатами товщину стіни показує зазор між двома обводами, прорізи — розриви
   обводу. Клас `.rp-wall` лишився носієм ЛИШЕ підсвітки обраної стіни (`--hot` нижче), яку
   будує та сама `wallBandPath`, тому й заливки тут немає. */
.rp-wall{stroke:none;pointer-events:none}
/* Обрана стіна — ТРАНЗИТНИЙ шар вибору, а не колір самої стіни: у спокої стіни тілом не
   малюються зовсім (див. вище), і креслення не міняється ні на піксель. Живе рівно доти, доки
   відкрите меню стіни або панель елемента.
   ЧОМУ САМЕ СМУГА. Підсвітку тут пробували тричі, і всі три рази клали її НА КОНТУР або на
   хіт-ціль: фарбовані хіт-лінії дали «товсті плити на пів-кімнати» (див. коментар нижче),
   напрямна завтовшки 9 — «неохайний товстий край», а тонка `.rp-guide` лягла точно під
   `.rp-edge` того ж кольору й не читалась узагалі. Смуга стіни — єдине місце поруч зі
   стіною, якого жодна з трьох спроб не займала: вона НАЗОВНІ від контуру, вже намальована,
   і геометрію їй дає та сама `wallBandPath`, тож проріз лишається розривом.
   ЄДИНИЙ АКЦЕНТ НА КРЕСЛЕННІ (рішення власника 2026-09-10): межі кімнат графітові (`.rp-edge`
   нижче), тож теракота на плані означає рівно одне — «цю стіну зараз обрано». Доти обвід теж
   був `--accent`, і обрану стіну доводилось відділяти від нього темнішим тоном; тепер її
   відділяє сам колір. `--accent-d` лишився свідомо: цим тоном говорять усі сигнали «ця
   стіна» — напрямні `.rp-guide`/`.cz-guide` і привид дверей під пальцем. */
.rp-wall--hot{fill:var(--accent-d)}
/* Стіни НАСЛІДКУ (2026-09-29): ті, що зміняться не з руки майстра — сусідка косої стіни, стіна
   навпроти, дві стіни, що зіллються. Та сама теракота, легша: роль інша, ніж у тапнутої стіни,
   але сімейство те саме («про цю стіну зараз мова»). Живе, поки відкрита шторка, що про них каже.
   Номерів стін на кресленні немає — тож показати стіну, про яку каже текст, можна лише так. */
.rp-wall--alt{fill:var(--accent);opacity:.7}
/* Незамкнений контур смуги стіни не має (сторони «назовні» ще немає) — там та сама підсвітка
   лягає лінією поверх ламаної. */
.wk-hot{fill:none;stroke:var(--accent-d);stroke-width:5;stroke-linecap:round;vector-effect:non-scaling-stroke;pointer-events:none}
.wk-hot--alt{stroke:var(--accent);opacity:.7}
/* Поки відкрита шторка, що говорить про стіни, креслення вписане в смугу НАД нею
   (`measurePlanBox` + `view.sheetOver`) і стоїть угорі полотна, а не посередині під шторкою. */
.zed-plan--over svg{height:auto}
/* Обвід — ОКРЕМИЙ шлях від заливки: у ньому прорізані двері (ringPathWithGaps), тож контур
   розривається сам, замість «гумки» кольору підкладки поверх стіни.
   ГРАФІТ, А НЕ ТЕРАКОТА (2026-09-10, рішення власника): межа кімнати — структура, а не вибір,
   тож акцент на кресленні лишено обраній стіні (`.rp-wall--hot`) і рамці підрізу плитки. Друга
   причина фізична: підрізи ЗАВЖДИ лежать уздовж периметра, і їхня теракотова рамка зливалась
   із теракотовим обводом у суцільну смугу — межа кімнати губилась рівно там, де вона є.
   ЧОМУ --muted, А НЕ --ink (2026-09-11, вибір власника з аркуша A–D на справжніх кадрах):
   `--ink` на білому дає 16.8:1 проти 4.7:1 у колишньої теракоти, тож та сама товщина читалась
   утричі важчою — і контур разом із рамками підрізів робив креслення «брудним». `--muted` дає
   5.2:1, тобто ВАГУ старої теракоти без її кольору. Товщину на полотнах не чіпали (закон). */
/* Фолбек 1 — це вага ПРЕВʼЮ, а не «на всяк випадок» (було 1.5 до 2026-09-11: на мініатюрі 96×72
   півтора пікселя контуру переважували всю плитку): змінну ставлять рівно три поверхні,
   де кімнати стоять поруч (полотно плану, #/layout, редактор), бо лише там закон має сенс і
   лише там масштаб виміряний у екранних px. Усі картки й мініатюри свідомо лишаються на
   фолбеку — інакше кожна отримує свій `k` зі свого viewBox і сусідні картки одного списку
   розходяться у вазі ліній (заміряно 0.68…1.80 px). Див. застереження над strokeLaw. */
.rp-edge{fill:none;stroke:var(--muted);stroke-width:var(--rp-w,1);vector-effect:non-scaling-stroke;
  stroke-linejoin:round;stroke-linecap:butt;pointer-events:none}
.rp-lbl{fill:var(--ink);font-weight:600;pointer-events:none;paint-order:stroke;
  stroke:var(--surface);stroke-width:.35em;stroke-linejoin:round}
.rp-tiles{pointer-events:none}
/* Цілі пальця й ручки редактора. Прозорі, бо це ЦІЛІ, а не графіка: на масштабі плану 44px
   накривають метр світу, і зафарбовані вони застелили б план. Видима підсвітка — окрема
   тонка напрямна, і горить ЛИШЕ наведена стіна. Товщина в CSS px завдяки non-scaling-stroke,
   тож 44px тап-ціль тримається за будь-якого масштабу. */
/* Каптури КРУГЛІ, а не butt (2026-09-16). З butt ціль стіни — прямокутник 44px × ДОВЖИНА
   СТІНИ, тож стіна завдовжки 3.4px (уступ 197 мм на телефоні) мала ціль 44×3.4 і не існувала
   для пальця: поза цією смужкою в 3.4px вона навіть не потрапляла в кандидати. Круглий каптур
   дає ≥44px у ВСІ боки будь-якій стіні — той самий прийом, що вже стояв на цілі числа рейки.
   Ціною є перекриття цілей на кутах, і саме тому цей рядок не можна було написати раніше:
   при виборі «верхній у порядку малювання» він віддав би кути останній намальованій стіні.
   Тепер ціль обирає `tapTarget` за ВІДСТАННЮ (screens/zones.js), тож на куті виграє та стіна,
   до якої палець ближче. Цілі живуть лише в редакторі кімнати — превʼю виходять із zoneSVG
   ще до шару цілей (гілка `plain`). */
.rp-hit{stroke:transparent;stroke-width:44;stroke-linecap:round;vector-effect:non-scaling-stroke;
  pointer-events:stroke;cursor:pointer}
.rp-hit--area{fill:transparent;pointer-events:all}
.rp-guide{stroke:var(--accent-d);stroke-width:3;stroke-linecap:butt;vector-effect:non-scaling-stroke;
  pointer-events:none;opacity:0;transition:opacity .1s ease}
.rp-guide.guide--hot{opacity:1}
/* Ручка виступу/вирізу — стримана крапка, а не бейдж: форму мод показує самим контуром.
   Тому й колір — контуру, якому вона належить: теракотове кільце на кожному виступі в спокої
   сперечалось би з обраною стіною за єдиний акцент креслення. */
.rp-mark{fill:var(--surface);stroke:var(--muted);stroke-width:2.5;
  vector-effect:non-scaling-stroke;cursor:pointer}
/* Розмірний ланцюжок активної стіни під панеллю елемента (`chain` у zoneSVG): ті самі три
   числа, що в панелі, біля кутів, від яких їх зміряно. Тон — розмірних підписів (`--muted`),
   акцент — лише відрізку АКТИВНОЇ комірки: той самий словник, що «обрана стіна теракотова,
   решта креслення сіра». Ореол числа — тло полотна, як у підписів на рейках. */
.dc-ext,.dc-seg{stroke:var(--muted);stroke-width:1;vector-effect:non-scaling-stroke;pointer-events:none}
.dc-num{fill:var(--muted);font-family:var(--mono);paint-order:stroke;stroke:var(--surface-2);
  stroke-width:4px;stroke-linejoin:round;pointer-events:none}
.dc--on .dc-seg{stroke:var(--accent-d);stroke-width:2}
.dc--on .dc-num{fill:var(--accent-d);font-weight:700}
.dc-hit{stroke:transparent;stroke-width:44;stroke-linecap:round;vector-effect:non-scaling-stroke;
  pointer-events:stroke;cursor:pointer}

.cz--drag{cursor:grab}

/* — Сторінка проєкту: кімнати окремо + спільний план — */
.proomlist{display:flex;flex-direction:column;gap:var(--space-2)}
.pcard{border:1px solid var(--line);border-radius:var(--radius-s);padding:var(--space-2) var(--space-3);background:var(--surface)}
.pcard--group{padding:var(--space-3)}
.pcard-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-2)}
.pcard-head h3{font-size:14px}
.pgroup{display:flex;gap:var(--space-3);align-items:flex-start;flex-wrap:wrap}
.pgroup-svg{flex:0 0 200px;max-width:200px;background:var(--surface-2);border-radius:var(--radius-s)}
.pgroup-rooms{flex:1;min-width:180px;display:flex;flex-direction:column;gap:2px}
.proom{display:flex;align-items:center;gap:var(--space-2);min-height:32px}
.proom-sw{width:14px;height:14px;flex:none;border-radius:var(--radius-xs);border:1.5px solid}
.proom-nm{font-weight:500;font-size:14px}
.proom-ti{font-size:12px;color:var(--muted);font-family:var(--mono)}
.proom-ar{margin-left:auto;font-family:var(--mono);font-size:13px;color:var(--muted);white-space:nowrap}
.doorctls{display:flex;gap:var(--space-3);flex-wrap:wrap}
/* Режим встановлення елемента.
   ХІТ-ЛІНІЇ [data-wall] лишаються ПРОЗОРИМИ — це 44px тап-ціль, не графіка.
   Раніше їх фарбували (stroke-opacity:.28) → товсті плити на пів-кімнати,
   подвійне затемнення на кутах і закритий план. Тепер підсвітка — окремі тонкі напрямні. */
/* Підсвічується ЛИШЕ та стіна, на яку наведено. Підсвічувати всі чотири безглуздо
   (тапати можна будь-яку), а смуги поверх лінії стіни давали подвійний брудний контур.
   Режим і так позначено акцентною підказкою під схемою + курсором. */
/* правила живуть у блоці .zed-canvas (редактор кімнати · canvas-first) */

/* — Підказки: одноразові tipbox/tipchip + анімована заставка «кімната обводиться» (tips.js) —

   РЕЄСТР ТОНІВ (хто чим говорить). Порушувати = вчити користувача, що колір нічого не значить:
     .statusband--danger  --danger   блокуюча проблема       зникає, коли усунуто
     .statusband--warn    --warn     стан / деградація       зникає, коли усунуто
     .statusband--ok      --ok       успіх / готово          зникає, коли усунуто
     .tipbox / .tipchip   --info     НАВЧАЛЬНА ПІДКАЗКА      «Зрозуміло» → назавжди
     .hint / .zed-hint    --muted    живий фідбек режиму     зі зміною стану
     .toast               --ink      результат дії           5с / undo
     .toast--danger       --danger   ДІЯ НЕ ВІДБУЛАСЬ        8с (лише відмова запису)
   Сортувальний критерій: чи є що виправляти користувачеві? Так → warn/danger. Ні, це пояснення → info.
   `.toast--danger` — виняток, що підтверджує критерій: сховище переповнене, дані НЕ збережено,
   і виправити це може лише користувач. Для попереджень у потоці лишається .statusband--warn.

   Підказка НЕ носить border-left-width:4px — смуга зліва це підпис «стан документа» (.statusband).
   Однакове шасі + майже однакові --accent(#c0522b)/--danger(#c0392b) робили пораду схожою на помилку. */
.tipbox{display:flex;align-items:center;gap:var(--space-3);padding:10px var(--space-3);margin-bottom:var(--space-3);
  background:var(--info-soft);border:1px solid var(--info-line);border-radius:var(--radius-s);
  color:var(--ink);font-size:13.5px}
.tipbox p{margin:0;flex:1}
.tipbox-ic{flex:none;display:flex;color:var(--info);margin-top:1px}

/* Плаваючий варіант для екранів-полотен: висить НАД канвасом, у потоці займає 0px.
   Якорі — .czwrap і .zed-canvas (обидва position:relative). */
.tipchip{position:absolute;top:8px;left:8px;right:8px;z-index:3;
  display:flex;align-items:flex-start;gap:var(--space-2);padding:8px 10px;
  background:var(--info-soft);border:1px solid var(--info-line);border-radius:var(--radius-s);
  box-shadow:var(--shadow-md);color:var(--ink);font-size:13px;line-height:1.35;
  pointer-events:none}   /* полотно під чипом лишається перетягуваним */
.tipchip p{margin:0;flex:1;min-width:0}
.tipchip .tipbox-ic{margin-top:0}
.tipchip-x{flex:none;pointer-events:auto;display:flex;align-items:center;justify-content:center;
  width:28px;height:28px;margin:-4px -4px -4px 0;padding:0;
  background:none;border:0;border-radius:var(--radius-s);color:var(--info);font-size:15px;cursor:pointer}
@media (hover:hover){.tipchip-x:hover{background:var(--tint-hover)}}
@media (prefers-reduced-motion:no-preference){
  .tipchip{animation:tipIn .18s ease}
  @keyframes tipIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}
}
.tipintro{display:block;margin:0 auto var(--space-2)}
.tipintro svg{display:block;width:100%;max-width:280px;margin:0 auto}
.tipsteps{margin:0 0 var(--space-3);padding-left:20px;display:flex;flex-direction:column;gap:6px;font-size:14px}
/* база .ti-* = ГОТОВИЙ план: reduced-motion / друк / зрив анімації → статична картинка, не порожнеча */
/* Заставка малює кімнату так само, як застосунок: графітовий контур (див. .rp-edge). Теракотою
   лишається лише стартова крапка — вона, як і в режимі креслення, «звідки ростуть стіни». */
.ti-trace{fill:none;stroke:var(--muted);stroke-width:2.5;stroke-linejoin:round;stroke-linecap:butt}
.ti-floor{fill:var(--accent-soft)}
.ti-start{fill:var(--accent-d)}
.ti-dim{font-family:var(--mono);font-size:11px;fill:var(--muted)}
.ti-door line{stroke:var(--muted);stroke-width:3}
.ti-door line:last-child{stroke-width:2}
.ti-door .ti-gap{stroke:var(--ti-gap,var(--surface));stroke-width:6}
.tipintro--empty{--ti-gap:var(--bg)}
/* статичний фолбек: без анімацій видно ЛИШЕ першу сцену (готовий план), а не 3 накладені */
.ti-scene ~ .ti-scene{opacity:0}
/* приховані стани живуть ЛИШЕ у keyframes; глобальний reduce-override (рядок ~35) робить
   негейтовану infinite-анімацію флікером — тому гейт no-preference обовʼязковий.
   Сцени: діти крутять свій 6с-цикл, слот-обгортка (18с) відкриває їх по черзі; фаза —
   негативним delay (--ti-slot з розмітки). delay ОКРЕМИМ лонгхендом ПІСЛЯ шорхенда. */
@media (prefers-reduced-motion: no-preference){
  .ti-scene{animation:ti-slot 18s linear infinite;animation-delay:var(--ti-slot,0s)}
  .ti-trace{stroke-dasharray:100;animation:ti-trace 6s linear infinite}
  .ti-dims{animation:ti-dims 6s linear infinite}
  .ti-door{animation:ti-door 6s linear infinite}
  .ti-floor{animation:ti-floor 6s linear infinite}
  @keyframes ti-trace{0%{stroke-dashoffset:101}35%,100%{stroke-dashoffset:0}}
  @keyframes ti-dims{0%,35%{opacity:0}50%,100%{opacity:1}}
  @keyframes ti-door{0%,50%{opacity:0}65%,100%{opacity:1}}
  @keyframes ti-floor{0%,65%{opacity:0}75%,100%{opacity:1}}
  /* видима 0–30%, фейд-аут до рівно 33.333% (діти ресетяться на межі 6с — 33.333% з 18с
     ледь РАНІШЕ межі, безпечний бік; НЕ округлювати до 33.34%), далі слот закритий */
  @keyframes ti-slot{0%,30%{opacity:1}33.333%,100%{opacity:0}}
}
.doorctl{align-items:center}
.cz--drag .rp-floor{cursor:grab}
.cz.dragging{cursor:grabbing}
/* Тінь — на ГРУПІ, не на заливці: смуга стіни живе поруч із нею, і тінь лише під підлогою
   лишала б сіру стіну висіти без тіні, тобто кімната роз'їжджалась би на два предмети. */
.cz.dragging{filter:drop-shadow(0 2px 6px rgba(0,0,0,.18))}
.cz.dragging .rp-edge{stroke-width:calc(var(--rp-wa,3) * 1.25)}
/* Помилку показують заливка й обвід. Смуга стіни лишається нейтральною свідомо: вона
   контекст, а не повідомлення (той самий довід, що записаний для .rp-wall вище). */
.cz--bad .rp-floor{fill:var(--danger-soft)}
.cz--bad .rp-edge{stroke:var(--danger)}
.cz-wall{stroke:var(--accent);stroke-width:4;vector-effect:non-scaling-stroke;stroke-linecap:round}
.cz-wall--bad{stroke:var(--danger)}
.cz-door{stroke:var(--ok);stroke-width:6;vector-effect:non-scaling-stroke;stroke-linecap:round}
/* активна група — жирніший контур; кандидат-двері на pick-up; хіт-лінії стін у режимі «додати двері» */
.cz--active .rp-edge{stroke-width:var(--rp-wa,3)}
/* Місток прорізу без обраного формату — заливкою підлоги, як сама кімната: інакше отвір між
   двома персиковими кімнатами лишався б дірою кольору полотна. Не ціль тапа — нею є шов. */
.cz-bfloor{fill:var(--accent-soft);stroke:none;pointer-events:none}
.cz-cand{fill:var(--ok);fill-opacity:.16;stroke:var(--ok);stroke-width:2;vector-effect:non-scaling-stroke}
/* Режим дверей на полотні — той самий знак, що в редакторі кімнати (див. .zed-plan вище).
   Хіт-лінія ПРОЗОРА: це ціль пальця, не графіка. Фарбувати її не можна — при масштабі
   полотна ~40 мм/px ці 26px накривають метр світу, план застеляють плити, а round-cap
   звисає за кінці стін і дає темні «подушки» в кутах. Видима підсвітка — окрема тонка
   напрямна, і горить ЛИШЕ та стіна, яку поверне nearestWall під пальцем. */
.cz-wallhit{stroke:transparent;stroke-width:26;vector-effect:non-scaling-stroke;stroke-linecap:round;cursor:pointer}
.cz-guide{stroke:var(--accent-d);stroke-width:3;stroke-linecap:butt;vector-effect:non-scaling-stroke;
  pointer-events:none;opacity:0;transition:opacity .1s ease}
.cz-guide.guide--hot{opacity:1}
.czwrap--pick{outline:2px dashed var(--accent);outline-offset:-2px}
.czwrap--pick .cz--drag{cursor:pointer}
/* — Межа плитки в прорізі (split-план) —
   Ціль тапу — весь квад прорізу; лінії показують, докуди дістає плитка кожної кімнати,
   а штрихована смуга між ними — вільне місце під поріг. При вузькому прорізі (< 8 px)
   seamGlyphs малює ОДНУ лінію по середині замість двох — див. коментар там. */
/* Сама заливка квада — це лише ~9px по вузькій осі (проріз 100 мм на типовому зумі),
   тобто вдвічі менше за палець. Розширюємо ціль прозорим non-scaling штрихом — той самий
   прийом, що й .cz-wallhit: 36 → по 18px у кожен бік, разом ~46px. */
.cz-seamhit{fill:transparent;stroke:transparent;stroke-width:36;vector-effect:non-scaling-stroke;
  stroke-linejoin:round;pointer-events:all;cursor:pointer}
@media (hover:hover){.cz-seamhit:hover{fill:var(--accent);fill-opacity:.14;stroke:var(--accent);stroke-opacity:.1}}

/* — PDF-імпорт — */
.impwarn{border-color:var(--warn);margin-bottom:var(--space-3)}
.impwarn .field{max-width:220px}
.imprender{padding:var(--space-2);margin-bottom:var(--space-3)}
.imprender img{display:block;width:100%;border-radius:var(--radius-s)}
.implist{display:flex;flex-direction:column;gap:var(--space-2)}
.improw{display:flex;align-items:center;gap:var(--space-3);padding:var(--space-2) var(--space-3);background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-s);cursor:pointer}
.improw .imp-mini{width:72px;flex:none;background:var(--surface-2);border-radius:var(--radius-s)}
.improw .imp-name{flex:1;min-width:0}
.improw .imp-area{font-family:var(--mono);font-size:13px;color:var(--muted);white-space:nowrap}
.improw .imp-sel{width:20px;height:20px;flex:none}

/* ═══ Екран «Розкладка» (#/layout) ═══ */
/* Каркас: план угорі, КОНТРОЛИ ВНИЗУ. З 2026-09-08 сцена бере всю висоту, яку лишає clamp
   (див. «ВИСОТА ЙДЕ ПЛАНУ» у layout.js): доти fitStageHeight зрізала її до потреби meet-фіту,
   і `margin-top:auto` відносив 173–324px порожнечі між план і контроли — «два кластери»
   читались як «не довантажилось» (критика 2026-09-08). Тепер поза сценою лишається хіба
   решта від стелі 66vh (~38px на 874), і саме її margin-top:auto кладе під сцену. */
.screen--layout{display:flex;flex-direction:column}
.screen--layout .lctl{margin-top:auto}
/* Шапка .lhead живе разом із .zhead у секції «Каркас» — рядок в один ряд тепер спільний
   для #/layout і #/zones (шукати «Шапка в ОДИН рядок»). */
/* touch-action:none ЛИШЕ тут: сцена — обмежений бокс, під нею завжди є за що потягнути сторінку */
/* Висота — від ЕКРАНА, не від ширини. Було min(52vh,68vw): на телефоні завжди вигравало 68vw,
   тобто план був заручником ширини й діставав 38% екрана.
   196px — і це число НЕ Є сумою видимих коробок. Спроба «уточнити» його підсумовуванням
   (шапка 44 + підвал 50 + панель 61 + відступ 8 = 163) провалилась 2026-09-07: поза сумою
   лишаються поле самого .screen і межі, разом ~26px, і екран пішов у скрол на 360×640,
   375×553 і 390×664. Міряти це можна ЛИШЕ як `docH − stageH − nudgeH` у стані, де clamp
   справді зв'язує (заміряно 189 на трьох розмірах при резерві 55). Коли «Зберегти» стала
   повними 44px, панель зросла 55→61 — і рівно на ці 6px мусив вирости резерв
   `.app.immersive .has-stickybar`, а за ним і це число: 190 → 196. Заміряно, що без цього
   360×640 і 375×553 йдуть у скрол на 4–5px.
   Картка зсуву входить окремо через --nudge-h (114 згорнута / 244 розгорнута), бо міняється
   на льоту; плюс --advice-h, яку ставить render() (банер оцінки буває не завжди).
   Сцена бере ЦЮ висоту цілком (inline-обрізки більше немає): масштаб плану обирає політика
   входу в layout.js (syncStage/kPolicy), а між рендерами масштаб сталий і міняється лише
   вікно — тож розгортання панелі не перемальовує план дрібнішим під пальцем.
   Було 365 із розгорнутою карткою зсуву 165: та константа трималась на контракті «сцена і
   зсув в одному фолді». Контракт свідомо скасовано — зсув тепер згорнутий за замовчуванням,
   бо на план дивляться значно частіше, ніж крутять зсув. Розгортання зсуву робить повний
   render(), і сцена стискається рівно на різницю. Додаючи будь-що над сценою — сюди ж. */
.lstage{position:relative;height:clamp(var(--stage-floor,200px),calc(100dvh - 196px - var(--nudge-h, 114px) - var(--advice-h, 50px)),66vh);
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius);
  overflow:hidden;touch-action:none;user-select:none;-webkit-user-select:none}
/* На телефоні сцена йде НА ВСЮ ШИРИНУ екрана. План тут зв'язаний шириною (див. STAGE_PAD у
   layout.js), тож 16px поля з кожного боку — це 9% креслення, віддані рамці. Радіус і бічні
   межі знімаємо РАЗОМ із полями: аркуш, що впритул торкається краю екрана, читається як
   обрізаний, а смуга — ні. Вище 768px екран уже не тісний, і сцена лишається карткою. */
@media(max-width:767.98px){
  .lstage{margin-inline:calc(-1 * var(--space-4));border-left:0;border-right:0;border-radius:0}
}
/* На НИЗЬКОМУ екрані (SE з панеллю Safari — 375×553) розгорнута панель зсуву не вміщається
   поруч зі сценою в принципі: 244px контролів + ~189px хрому лишають сцені 120px, а її
   підлога 200 — звідси скрол. На екрані з touch-action:none це не дрібниця: сторінку нічим
   потягнути, бо палець на сцені тягне сцену. Порушення не нове (заміряно +70px ще до
   full-bleed), але закривати його треба з боку КОНТРОЛІВ, а не сцени.
   Поки панель відкрита на такому екрані: банер мовчить (він тут і так лише діагноз, а рядок
   підбору стоїть у самій панелі), підвал сцени ховається — легенда це довідка, а зум
   лишається доступним пінчем, — і сцена дістає нижчу підлогу. */
/* Два рівні, бо дефіцит буває різної глибини. Порахувати «чи влізе» можна: хром ~190 +
   панель 244 + банер 27 + підлога сцени 200 = 661, тож обидва разом живуть лише на екранах
   від ~700px. Нижче — банер мовчить (він при відкритій панелі й так лише діагноз, а рядок
   підбору стоїть усередині самої панелі, тобто попередження нікуди не зникає, лише міняє
   голос). Заміряно 2026-09-07: без цього правила 360×640 давав +28px скролу, 390×664 +3. */
@media(max-height:700px){
  /* Заголовок картки зсуву (спільний шеврон) коштує 52px, і на короткому екрані з
     РОЗГОРНУТОЮ панеллю вони виводили сторінку в скрол (+46px на 360×640, заміряно
     2026-09-09). Платить підвал сцени: легенда — довідка, а зум лишається пінчем. Тут він
     ховається на рівень раніше, ніж було (нижче 620 він зникав і без цього). */
  body:has(.lnudge:not(.lnudge--closed)) .lsfoot,
  body:has(.lnudge:not(.lnudge--closed)) .ladvice,
  /* .lbanner тут ЗА ТИМ САМИМ правилом, і його відсутність коштувала 86px скролу при
     360×640 з розгорнутою панеллю в стані approx (заміряно 2026-09-09): банер технічний,
     він займає місце оцінки, тож і мовчати мусить разом із нею. */
  body:has(.lnudge:not(.lnudge--closed)) .lbanner{display:none}
  /* ДВА БАНЕРИ ОДИН НАД ОДНИМ — і так порушення «одного повідомлення за раз», а на низькому
     екрані ще й +16px скролу (360×640, панель ЗГОРНУТА, 8 900 плиток: оцінка 65 + технічний
     банер 88 = 199px над сценою, а її підлога вже 200 — віддавати нема чого; заміряно
     2026-09-09). Поступається ТЕХНІЧНИЙ: він каже «цілі залито суцільним, підрізи й тонкі
     точні» — це засторога про малювання й радше запевнення, тоді як оцінка називає проблему
     плану І несе дію. Вище 700px обидва лишаються. */
  .ladvice + .lbanner{display:none}
}
/* Другий рівень — справді низький екран (SE з панеллю Safari, 375×553). Тут не вміщається
   вже й підвал сцени: легенда це довідка, а зум лишається доступним пінчем. Плюс сцена
   дістає нижчу підлогу — 160px плану гірше за 200, але незрівнянно краще за скрол, якого на
   екрані з touch-action:none нічим потягнути. */
@media(max-height:620px){
  .lstage{--stage-floor:160px}
  /* Найглибший дефіцит (SE з панеллю Safari, 375×553): підвал сцени тут уже мовчить за
     правилом вище, тож поступається ряд пресетів — 69px разом із роздільником. Степери,
     числа й рядок підбору лишаються: саме по них сюди й заходять, а «Центрувати»/«Скинути»
     мають довший шлях-заміну (гізмо і ручний ввід). */
  body:has(.lnudge:not(.lnudge--closed)) .lnfoot{display:none}
}
.lscene{margin-bottom:var(--space-2)}
/* Підвал сцени: легенда + зум. Обидва були накладками ПОВЕРХ плану — на вузькій кімнаті
   вони закривали саме те, що оцінюють. 40px беруться в контролів, не в плану (див. 288). */
.lsfoot{display:flex;align-items:center;gap:var(--space-2);padding-top:6px;min-height:34px}
/* Тісніші проміжки, ніж у легенди деінде: поруч ряд зуму (186px), і при типових --space-3
   легенді бракувало 9px до одного рядка — вона переносилась і підвал ріс з 34 до 51px. */
.lsfoot .llegend{flex:1;min-width:0;gap:var(--space-2)}
.lsfoot .llegend span{gap:4px}
.lstage>svg{display:block;width:100%;height:100%}
/* Обвід КОЖНОЇ плитки — інакше при шві 2 мм на 600 мм сітка субпіксельна і підлога
   читається суцільною плямою. non-scaling-stroke тримає волосінь на будь-якому зумі. */
.lt{stroke-width:1;vector-effect:non-scaling-stroke;stroke-linejoin:round}
.lt--full{fill:var(--tile-full);stroke:var(--line-2)}
.lt--cut{fill:var(--tile-cut);stroke:var(--accent)}
.lt--sliver{fill:var(--tile-sliver);stroke:var(--tile-sliver-ink);stroke-width:1.5}
.lstage [data-hit]{cursor:grab}
/* Тап по банеру: тонкі смуги активної кімнати спалахують тричі — число дістає адресу. */
.lgrp--flash .lt--sliver{animation:ltFlash .6s ease-out 3}
@keyframes ltFlash{50%{fill:var(--warn-line);stroke-width:3}}
@media (prefers-reduced-motion:reduce){.lgrp--flash .lt--sliver{animation:none;stroke-width:3}}
/* Стіни й пороги — КАРКАС сцени (див. «КАРКАС СЦЕНИ» в screens/layout.js).
   Сцена показувала лише підлоги: два полігони з зазором, кожен обведений по всьому колу —
   разом три лінії поперек дверей і жодного знаку проходу, тож кімнати читались як не зʼєднані.
   Стіни тілом немає з 2026-09-11 (див. «ТІЛО КІМНАТИ»): її товщину показує зазор між обводами. */
/* Смуга під поріг — ШТРИХОВКА (pattern у самому SVG, див. hatchDefs): рівна заливка виходила
   того ж світло-сірого тону, що й .rp-wall поруч, і поріг читався як частина стіни. */
.rp-thr{fill:url(#rpThrHatch);stroke:none;pointer-events:none}
/* Стик двох сіток. Нейтральний, а не акцентний: акцент означає «підріз» — і на сцені, і на
   полотні спільного плану, відколи воно теж малює плитку, — а стик це фізичний факт, не
   проблема. Волосінь на будь-якому зумі, як і обвід плитки.
   Один клас на всі три поверхні: доти форма стику була написана двічі (`thresholdsSVG` на
   сцені, `seamGlyphs` на полотні) під різними іменами, а герой картки не мав її взагалі. */
.rp-seam{stroke:var(--ink);stroke-opacity:.55;stroke-width:var(--rp-seam,1.6);
  vector-effect:non-scaling-stroke;pointer-events:none}
/* Широкий проріз: стик з БІЛОЮ ОБЛЯМІВКОЮ (варіант B з аркуша, 2026-09-30; чому — коментар над
   `cased` у plan-draw.seamSVG). Облямівка відсуває краї плитки, що лежать рівно на стику, тож
   лінія лишається одна; 85 % графіту × 1,8 px — помітніше за обвід кімнати, бо це й є відповідь
   на «де тут поріг». Товщини сталі, а не за законом: облямівка з'являється лише на прорізі
   ширшому за 8 px, тож 6 px у нього влазять завжди. */
.rp-seam-case{stroke:var(--surface);stroke-width:6;vector-effect:non-scaling-stroke;stroke-linecap:butt;pointer-events:none}
.rp-seam-cased .rp-seam{stroke-opacity:.85;stroke-width:1.8;stroke-linecap:butt}
.rp-seams{pointer-events:none}
/* Щоки прорізу (plan-draw.jambsSVG): кольором і вагою ОБВОДУ — це продовження межі кімнати,
   що замикає торець стіни, а не окремий знак. `square`, а не `butt`: обвід у прорізі зрізаний
   butt-кінцем, і квадратний кінець щоки добирає рівно пів товщини — кут замикається без щербини.
   Не приглушується з неактивним шаром сцени: щока належить ПАРІ кімнат, як колись стіна. */
.rp-jamb{fill:none;stroke:var(--muted);stroke-width:var(--rp-w,1);vector-effect:non-scaling-stroke;
  stroke-linecap:square;pointer-events:none}
/* Сцена split-плану несе КІЛЬКА шарів — по кімнаті кожен, зі своєю плиткою і своїм зсувом.
   Неактивні приглушені, але НЕ сховані: саме заради них сюди й заходять — звести шви через
   проріз можна лише бачачи сусідню сітку. 0.42 — та межа, за якою сусідка ще читається як
   плитка (видно напрямок рядів), але вже не сперечається з активною за увагу.
   Активну кімнату позначає ПРОЗОРІСТЬ сусідок, а не колір обводу (2026-09-10): обвід графітовий
   у всіх, бо теракота на кресленні лишена обраній стіні — а теракотовий обвід активної ще й
   зливався з рамками підрізів, які лежать саме вздовж периметра. Не заливкою: вона сперечалася б
   із класами плитки (цілі/підрізи/тонкі), а вони тут — головне повідомлення. Не товщиною: товщий
   обвід ламав рівність контурів — активна кімната виглядала іншою фігурою, а не тією самою. */
.lgrp{cursor:pointer}
.lgrp:not(.lgrp--on){opacity:.42}
.lgrp--on{cursor:default}
/* Товщина — --rp-w (spec див. «ТІЛО КІМНАТИ»): екранні px, рахує спільний plan-draw.strokeLaw,
   подає сюди tuneStroke() у screens/layout.js. Коефіцієнт 0.75 сидить уже в самому законі, тож
   calc() тут більше не потрібен. Число й колір ОДНІ на всі кімнати сцени: активну відрізняє
   прозорість сусідок. */
.lgrp-out{stroke:var(--muted);stroke-width:var(--rp-w, 1);vector-effect:non-scaling-stroke}
/* Лічильник кімнат у шапці: без нього зміна h1 після тапу читається як перехід на інший екран */
.lhead-i{flex:none;font-family:var(--mono);font-size:12.5px;color:var(--muted);
  font-variant-numeric:tabular-nums;padding:0 2px}
.lbadge{position:absolute;top:8px;left:50%;transform:translateX(-50%);z-index:2;
  display:flex;gap:10px;align-items:baseline;padding:6px 12px;border-radius:999px;
  background:rgba(27,30,35,.86);color:#fff;font-size:13px;white-space:nowrap;pointer-events:none;
  box-shadow:var(--shadow-md)}
.lbadge .mono{font-family:var(--mono);font-variant-numeric:tabular-nums}
.lbadge-s{color:var(--on-ink-warn);font-weight:600}
/* Зум ПОВЕРХ сцени, у нижньому правому куті. Раніше він стояв під сценою — «плаваючі кнопки
   затулять пів-плану» було правдою при висоті 52vh; тепер сцена вдвічі вища, а власний рядок
   коштував 60px висоти, яких на телефоні саме й бракує. */
.lzoom{display:flex;gap:6px;align-items:center}
/* Вимкнена «Вмістити» = «ми вже вміщені». Без цього правила кнопка була disabled лише для
   вказівника, а на вигляд лишалась активною — тобто мовчки не реагувала на тап. */
.zbtn:disabled{opacity:.45;cursor:default}
.zbtn{width:var(--tap);height:var(--tap);border:1px solid var(--line-2);border-radius:var(--radius-s);
  background:rgba(255,255,255,.92);color:var(--ink);font-size:20px;line-height:1;cursor:pointer;
  display:flex;align-items:center;justify-content:center;box-shadow:var(--shadow-sm);flex:none}
.zbtn--wide{width:auto;padding:0 12px;font-size:13px;font-weight:600}
.zbtn:active{background:var(--accent-soft)}

/* Легенда — довідка, не контрол. Свотч КРУГЛИЙ саме тому: квадрат 14px із рамкою поруч із
   кнопками читався як чекбокс, і в нього тапали, чекаючи фільтра. */
.llegend{display:flex;gap:var(--space-3);font-size:11.5px;color:var(--muted);flex-wrap:wrap}
.llegend span{display:inline-flex;align-items:center;gap:5px}
.llegend i{width:10px;height:10px;border-radius:999px;border:1px solid var(--line-2);display:inline-block}

/* Блок контролів під сценою: картка «Зсув» і більше нічого. Шухляди «Ще» немає (дії зсуву
   стоять у самій панелі, «Схеми» — у шторці плитки), сутність «Переходи» видалено 2026-08-03.
   :has нижче лишається: згорнута картка тримає рядкову розкладку, розгорнута — колонкову.
   Розгорнута — сітка степерів займає всю ширину (на 360px кнопка збоку з'їдала 70px і «+½»
   ховалось під нею), тож підвал іде ПІД сіткою окремим рядком .lnfoot — але ВСЕРЕДИНІ картки. */
.lctl{display:flex;flex-direction:column;align-items:stretch;gap:var(--space-2)}
/* Підвал зсуву — у картці, за волосяною лінією. Був .lctl-foot ПІД карткою, на сірому тлі:
   там він читався як контроли плану (рядок зуму над карткою має той самий словник — білі
   пігулки на сірому), хоч усі його кнопки пишуть tox/toy. Межа картки = межа сутності. */
.lnfoot{display:flex;align-items:center;gap:var(--space-2);
  margin-top:var(--space-3);padding-top:var(--space-3);border-top:1px solid var(--line)}
/* 44px: три кнопки підвалу коштували 34. Ширина стала вільнішою, відколи шеврон згортання
   переїхав у заголовок картки: у ряду лишились три ПІДПИСАНІ кнопки замість чотирьох. */
.lnfoot .btn{flex:none;gap:4px;min-height:var(--tap)}
/* 360px: 44+57+103+80+3×8 = 308 при 302 доступних — ряд переповнював картку на 6px
   (заміряно 2026-09-08). Тісніші проміжки й поля, а не менший кегль. */
@media(max-width:360px){
  .lnfoot{gap:6px}
  .lnfoot .btn--sm{padding:0 9px}
  .lnval-u{display:none}   /* «301 мм» у 44px не влазить; одиницю несе aria-label і шторка «Міліметри» */
}
.lnfoot .btn svg{color:var(--muted)}
/* .lnclose видалено 2026-09-09: згортання переїхало в заголовок картки, спільний для обох
   станів (див. headRow у nudgeHTML) — шеврон більше не стрибає з кута в кут. */
/* Підбір — окремим рядком на всю ширину: «Оптимізувати» це 115px, які в рядок із пресетами
   не влазять ніяк. Фон surface-2, бо кнопка тепер стоїть НА БІЛІЙ картці: біла пігулка на
   білому трималась би на самій рамці. Акцентна заливка ЛИШЕ у стані з відомим виграшом
   (.lopt--go): акцент тут означає «це точно допоможе», а не «тут кнопка» — інакше вона б
   сперечалась із «Зберегти». */
.lopt{width:100%;gap:6px;margin-top:var(--space-2);background:var(--surface-2)}
.lopt svg{color:var(--muted)}
/* Наведення обидва стани описують САМІ: `.btn:hover` (0,2,0) сильніший за клас модифікатора
   (0,1,0), тож без цих двох правил акцентна кнопка на hover ставала сірою — акцент зникав
   саме тоді, коли на неї ціляться. Той самий прийом, що й у `.btn--primary:hover`. */
@media (hover:hover){.lopt:hover{background:var(--line);border-color:var(--faint)}}
.lopt--go{background:var(--accent);border-color:var(--accent);color:#fff}
@media (hover:hover){.lopt--go:hover{background:var(--accent-d);border-color:var(--accent-d)}}
.lopt--go svg{color:#fff}
/* Білий, а не #f6e3da: тінт на --accent давав 3.77:1 при 11.5px. Підпорядкованість несуть
   вага (500 проти 600) і кегль, а не приглушений колір, якого однаково не видно. */
.lopt--go small{font-weight:500;font-size:11.5px;color:#fff;white-space:nowrap}
.lopt--go:active{background:var(--accent-d);border-color:var(--accent-d)}
/* «Кращої розкладки немає» — статус, не контроль: без заливки й рамки, той самий бокс 44px, щоб
   --nudge-h (244) не смикалась, коли стан міняється під пальцем. Галочка тоном ok — це
   «готово» за реєстром; текст лишається muted, бо виправляти тут нічого. */
.lopt--done{display:flex;align-items:center;justify-content:center;gap:6px;min-height:var(--tap);
  border:1px solid transparent;background:transparent;color:var(--muted);font-size:14px;font-weight:500;cursor:default}
.lopt--done svg{color:var(--ok)}
.lopt--done small{font-weight:400;font-size:12.5px}
.lctl:has(.lnudge--closed){flex-direction:row;align-items:stretch}
.lctl:has(.lnudge--closed) .lnudge{flex:1;min-width:0}

/* Смуга зсуву — первинний контрол: на телефоні кнопки точніші за палець */
.lnudge{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  /* Поле картки оголошене ОДИН раз на обидва стани: заголовок мусить стояти на тій самій
     висоті, а рядок підбору — на тій самій відстані від нижнього краю. Доти верх був
     вирівняний, а низ ні (8 проти 12), і кнопка «Оптимізувати» на кожен тап по шеврону
     міняла відступ 9↔13px — заміряно 2026-09-09. */
  padding:var(--space-2) var(--space-3)}
/* Без нижнього поля: .lctl — останній елемент потоку на екрані (далі лише fixed-панель),
   тож поле під ним було б чистим скролом. :last-child тут не спрацює — .stickybar теж дитина main. */
.lnrow{display:flex;align-items:center;gap:6px;margin-bottom:var(--space-2)}
.lnrow:last-child{margin-bottom:0}   /* між сіткою і підвалом відступ дає сам .lnfoot */
.lnlab{flex:none;width:64px;font-size:11px;font-weight:600;text-transform:uppercase;
  letter-spacing:.06em;color:var(--muted)}
/* Стрілка осі (↔ ↕) замість X/Y. У дрібному підписі гліф шрифту ледь видно (↕ 6.7px завширшки
   при 11px), тож збільшуємо саму стрілку; line-height:0 — щоб рядок не виріс. */
/* Моноширинний стек — не для вигляду: у Space Grotesk немає гліфа ↕, і на iOS Safari добирає його з
   Apple Color Emoji (синій квадрат у «Сторона ↕» шторки плитки, симулятор 2026-09-28). У стеку --mono
   гліф є. `U+FE0E` після стрілки пробували — вебшрифт не знає селектора, і Safari брав стрілку з
   третього шрифту, тонку й дрібну, навіть там, де доти було гаразд. */
.ax{font-family:var(--mono);font-size:1.45em;line-height:0;font-weight:500;letter-spacing:0;vertical-align:-.05em}
.lnval{flex:1;min-width:var(--tap);min-height:var(--tap);border:1px solid var(--line-2);border-radius:var(--radius-s);
  background:var(--surface-2);color:var(--ink);font-family:var(--mono);font-size:14px;padding:0 2px;
  font-variant-numeric:tabular-nums;cursor:pointer;white-space:nowrap}   /* 360px: «301 мм» ішло у два рядки */
.lnval:active{background:var(--accent-soft)}
/* Легенда з підвалу картки переїхала під план (.lsfoot) — вона описує план, а не зсув.
   Сам .lnfoot лишився і живе вище, поруч із .lctl. */
/* Згорнутий зсув — один рядок замість сітки степерів: 165px → 48px, і різниця йде плану.
   Показує ОБИДВА значення, бо це головне, що зі зсуву треба знати не крутячи його. */
/* Згорнута панель — КОЛОНКА: рядок «Зсув X / Y» і під ним рядок підбору. Був рядок, бо в
   згорнутому стані картка несла лише зведення; відколи дія живе тут в обох станах (див.
   nudgeHTML), другий рядок потрібен завжди. */
.lnudge--closed{display:flex;flex-direction:column;align-items:stretch;gap:0}
.lnsum{width:100%;flex:1;min-width:0;display:flex;align-items:center;gap:var(--space-2);min-height:var(--tap);
  border:0;background:transparent;color:var(--ink);cursor:pointer;text-align:left}
.lnsum .lnlab{width:auto}
.lnsum-v{flex:1;min-width:0;font-family:var(--mono);font-size:14px;font-variant-numeric:tabular-nums}
.lnsum svg{flex:none;color:var(--muted);transform:rotate(180deg)}   /* ▾ — розкрити */
/* Розгорнута: той самий вузол на тому самому місці, шеврон повертається на ▴ — згорнути. */
.lnudge:not(.lnudge--closed) .lnsum{margin-bottom:var(--space-2)}
.lnudge:not(.lnudge--closed) .lnsum svg{transform:none}
/* Візерунок = сітка 2×2 карток «назва + цифри». Замінила чипи + окрему шторку «Порівняти
   схеми»: вибір і підстава для вибору тепер в одному контролі. Дві колонки, бо «зміщення ½»
   (103px) із рядком цифр у чотири колонки не влазить, а 167px вистачає обом.
   Активна — рамка й підложка акцентом, а НЕ суцільна заливка (як у чипа): всередині картки
   лежить дрібний текст, який на акцентному тлі перестав би читатись.
   .morelist/.morerow (шухляда «Ще») і .ltable (шторка порівняння) звідси прибрано — обидва
   контейнери зникли разом зі своїми екранами. */
.patgrid{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-2);margin-top:6px}
.patcard{display:flex;flex-direction:column;align-items:flex-start;gap:2px;
  min-height:var(--tap);padding:8px 10px;border:1px solid var(--line);
  border-radius:var(--radius-s);background:var(--surface);cursor:pointer;text-align:left}
.patcard b{font-size:13.5px;font-weight:600}
/* Цифри — довідка, тож muted; «тонкі» виділяємо тоном warn, бо це єдине, що тут може бути
   проблемою (те саме правило, що в банері оцінки на екрані). */
/* min-height = два рядки: «25 шт · 9 підрізів · 1 тонка» (28 знаків) у 136px картки на 360px
   не влазить у рядок ніяк, тож місце під перенос резервуємо ЗАВЖДИ — інакше картки зі
   смугами вищі за сусідні й сітка виглядає рваною. */
.patcard small{color:var(--muted);font-size:11.5px;line-height:1.3;min-height:30px;
  font-variant-numeric:tabular-nums}
.patcard small i{font-style:normal;color:var(--warn)}
/* Обрана картка — та, яку читають найдовше, і саме вона провалювала контраст: --accent на
   --accent-soft дає 3.77:1, а підпис --muted 3.89 при потрібних 4.5 (заміряно детектором у
   живій сторінці 2026-09-07). Тобто рівно на обраному варіанті цифри читались найгірше.
   Заголовок іде в --accent-d (4.72), а числа — в --ink (13.46): на ОБРАНІЙ схемі вони й є
   відповіддю, тож повна легкість читання тут не надмірність. «Тонкі» лишаються --warn —
   після затемнення це 5.02 на цьому ж тлі. */
.patcard.active{border-color:var(--accent);background:var(--accent-soft)}
.patcard.active b{color:var(--accent-d)}
.patcard.active small{color:var(--ink)}

/* Стоїть НАД сценою, тож кожен зайвий піксель тут — піксель, віднятий у плану:
   один рядок, стислі відступи. Висота (42+8=50) закладена в calc() для .lstage — банер тепер
   несе кнопку (34px), тож він вищий за старий текстовий на 9px.
   Дію банер НЕ несе: вона живе в рядку підбору панелі зсуву, видимому в обох її станах.
   Тут — лише діагноз, і тап по ньому спалахує ті самі смуги на плані. */
.ladvice{display:flex;align-items:center;gap:var(--space-2);
  margin:0 0 var(--space-2);padding:4px 4px 4px var(--space-3);border-radius:var(--radius-s);font-size:13px}
/* Текст банера — КНОПКА: тап спалахує тонкі смуги на плані (flashSlivers) і веде до найвужчої.
   Дотична підкреслена лише адреса («найвужча 190 мм (Коридор)») — це те, що можна знайти. */
/* Ціль дотику 44px — відʼємними полями, а не min-height: банер лишається тим самим рядком
   (27px), інакше кожен діагноз коштував би плану 25px. */
.ladvice-txt{flex:1;min-width:0;margin:-9px 0;padding:9px 0;border:0;background:none;color:inherit;font:inherit;
  text-align:left;cursor:pointer}
/* Сегменти підрядка пігулки: ховає fitPill з хвоста, коли не влазять (hidden → display:none) */
.tilepill-sub .tps[hidden],.tilepill-sub .tps-dot[hidden]{display:none}
.ladvice-where{text-decoration:underline dotted;text-underline-offset:3px;text-decoration-thickness:1px}
/* .ladvice--ok видалено 2026-09-08: тон не емітувався ніде («мовчання = все гаразд»). */
.ladvice--warn{background:var(--warn-soft);color:var(--warn)}
/* Підказка про гізмо стоїть ПЛАВАЮЧИМ ЧИПОМ усередині сцени (`.lstage` уже position:relative),
   а не слотом над нею: у слоті вона гейтилась банером і не показалась жодного разу. Внизу, а не
   вгорі — угорі сидить транзитний `.lbadge`, і два плаваючі елементи не сміють ділити один кут. */
.lstage .tipchip{top:auto;bottom:8px}
/* Живий регіон для скрінрідера (зміна активної кімнати перебудовує h1, а перебудову не оголошують) */
/* top:0 обовʼязково: без нього 1px-бокс став у кінці body й давав scrollHeight = innerHeight + 1 (заміряно на 4 розмірах) */
.sr-live{position:absolute;top:0;left:0;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
/* Липка панель приймає фокус після закриття шухляди з-під пальця (без обводу: це не ціль) */
.stickybar:focus{outline:none}
/* Кнопки в банері більше немає — дія живе в рядку підбору всередині панелі зсуву, у ОБОХ її
   станах (див. adviceHTML). Разом із нею знято `.ladvice--info`: гілка «Зсув можна покращити»
   існувала лише заради тієї кнопки. */
/* ДЕФОЛТ — info (пояснення, як саме намальовано); --warn коли є що виправляти (розмір плитки). */
.lbanner{margin:0 0 var(--space-3);padding:10px var(--space-3);border-radius:var(--radius-s);
  background:var(--info-soft);color:var(--info);font-size:13px}
.lbanner--warn{background:var(--warn-soft);color:var(--warn)}

/* Живуть у шухляді «Розрахунок», а не на екрані: під скролом вони були невидимі саме тоді,
   коли користувач міняв формат плитки чи зсув — тобто коли ці числа й потрібні.
   Форма — РЯДКИ, а не сітка кахлів (рішення власника 2026-09-08, обидва варіанти зібрано на
   стенді й заміряно). Кахлі коштували 885px проти 809 і лишали до ~50px порожнечі всередині
   нижчої картки ряду: у групі з двох карток вирівнювати ряд більше нічим. Рядок ставить усі
   значення в ОДНУ праву колонку — «59,29» і «17,59» порівнюються поглядом згори вниз, а не
   зигзагом по сітці 2×3. */

/* Заголовок розділу: підпис і лінія до правого краю. Лінія, а не рамка — розділи мусять
   читатись як частини одного аркуша, а не як вкладені картки; рамка тут відтворила б рівно
   ті кахлі, від яких ми відмовились. */
.lsec{display:flex;align-items:center;gap:var(--space-2);
  font-size:11.5px;font-weight:600;color:var(--muted);
  text-transform:uppercase;letter-spacing:.05em;margin:var(--space-4) 0 var(--space-2)}
.lsec:first-child{margin-top:0}
.lsec::after{content:"";flex:1;height:1px;background:var(--line)}

/* Бічний відступ = поле картки + її рамка (13px). Список кімнат нижче має рівно таке саме
   внутрішнє поле (1px рамка + 12px padding), тож усі підписи шухляди стоять на одній лівій
   лінії, а всі значення — на одній правій. Рахуємо формулою, а не літералом: число походить
   від картки й мусить поїхати за нею. */
.lrow{display:flex;align-items:baseline;gap:var(--space-3);
  padding:5px calc(var(--space-3) + 1px);min-height:30px}
.lrow>span{flex:1;min-width:0;font-size:13.5px;color:var(--ink)}
.lrow>b{font-family:var(--mono);font-size:19px;font-weight:600;
  font-variant-numeric:tabular-nums;white-space:nowrap}
/* «купити» — єдиний лід шухляди: 22px, той самий крок, що й заголовок екрана. Друга одиниця
   (м²) свідомо тихіша: це та сама відповідь у мові магазину, а не окрема величина. */
.lrow--lead>b{font-size:22px;line-height:1.15}
.lrow--lead>b i{font-style:normal;font-size:15px;font-weight:500;color:var(--muted)}
.lsub{padding:0 calc(var(--space-3) + 1px) 4px;font-size:11px;color:var(--muted);line-height:1.35}
/* Кількість тонких лишається в тоні warn — це підмножина, яка попереджає. */
.lsub em{font-style:normal;font-weight:600;color:var(--warn)}

/* Пояснення прочерків. Стоїть над обома розділами — воно про них обидва. Не `.statusband`
   (той має 4px-смугу як підпис своєї сутності) і не `.tipbox` (та навчає, а тут повідомляють
   про стан даних): це носій тону, а не нова сутність. */
.lnote{margin:0 0 var(--space-3);padding:8px 10px;
  border-radius:var(--radius-s);font-size:12.5px;line-height:1.4}
.lnote--warn{background:var(--warn-soft);color:var(--warn)}

/* Список кімнат split-плану — у тій самій шухляді, що й картки метрик: порівнювати кімнати
   хочеться саме над числами. Тому він же й перемикач активної (тап = активувати й закрити);
   окремої смуги-перемикача над сценою немає свідомо. Підсумок — ЛИШЕ сумовні величини:
   «купити» тут немає, бо штуки різних форматів не додаються. */
.lrooms{display:flex;flex-direction:column;gap:1px;margin-bottom:var(--space-3);
  border:1px solid var(--line);border-radius:var(--radius-s);overflow:hidden;background:var(--line)}
.lroom{display:flex;align-items:center;gap:var(--space-3);width:100%;min-height:44px;
  padding:8px var(--space-3);background:var(--surface);border:0;text-align:left;cursor:pointer;font:inherit;color:inherit}
/* Hover ЛИШЕ для вказівних пристроїв. На iOS тапнутий елемент лишається в `:hover` до тапу
   деінде, а `.lroom:hover` (0,2,0) специфічніший за `.lroom--on` (0,1,0) — тож рядок, який
   користувач ЩОЙНО ОБРАВ, ставав сірим замість персикового, тобто вибір гасив власну ж
   позначку. Видно тільки на пристрої: у браузері вказівник ішов далі й hover спадав.
   Стало помітно після того, як вибір кімнати перестав закривати шухляду (2026-09-08) —
   доти підсвітку не встигали побачити. */
@media (hover:hover){.lroom:hover{background:var(--surface-2)}}
.lroom--on{background:var(--accent-soft);cursor:default}
.lroom--sum{cursor:default;background:var(--surface-2)}
.lroom-nm{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px;font-size:13.5px;font-weight:500}
.lroom-nm small{font-weight:400;font-size:11px;color:var(--muted);font-family:var(--mono)}
.lroom-v{flex:none;font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums;text-align:right}
/* На персиковій заливці --muted дає 4.19:1 (заміряно двічі, 2026-09-08). Той самий прийом,
   що в .patcard.active: формат — теракота глибока (4.72), числа — чорнило. */
.lroom--on .lroom-nm small{color:var(--accent-d)}
.lroom--on .lroom-v{color:var(--ink)}

.btn--busy{pointer-events:auto;opacity:.85}

/* Липка панель розкладки: формат плитки + «Купити» + «Зберегти» в один рядок.
   Формат — причина, число — наслідок: поруч видно, як зміна формату рухає кошторис. */
.stickybar--layout{gap:var(--space-2);padding-left:var(--space-3);padding-right:var(--space-3)}
/* Число — кнопка (вхід у розрахунок). Відʼємні поля дають повні 44px дотику, не роздуваючи
   саму панель: її висота закладена в calc() для .lstage. */
.stickybar--layout .lsum{display:flex;flex-direction:column;justify-content:center;line-height:1.1;
  min-width:var(--tap);flex:none;min-height:var(--tap);margin:-3px 0;padding:0 2px;
  border:0;background:transparent;color:inherit;text-align:left;cursor:pointer}
.stickybar--layout .lsum:active .sum{color:var(--accent-d)}
.stickybar--layout .lbl{color:var(--muted);font-size:11px;white-space:nowrap}
.stickybar--layout .lbl svg{display:inline-block;vertical-align:-1px;color:var(--faint)}
.stickybar--layout .sum{font-size:17px}
.stickybar--layout .btn{flex:none}
/* Пігулка-контур проти залитої «Зберегти»: сусідні кнопки не мають читатись як однакові дії */
.tilepill{flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:6px;min-height:var(--tap);
  padding:0 10px;border:1px solid var(--line-2);border-radius:999px;background:var(--surface);
  /* 44, а не 38: це один із трьох контролів липкої панелі, і всі три були під мінімумом дотику */
  color:var(--ink);text-align:left;cursor:pointer;transition:background .15s,border-color .15s}
@media (hover:hover){.tilepill:hover{background:var(--surface-2);border-color:var(--faint)}}
/* Формат не обрано — пігулка не сміє виглядати як рішення майстра. Тон warn за реєстром:
   є що виправляти. Заливка м'яка, бо це стан контролу, а не банер; рамка називає його. */
.tilepill--unset{background:var(--warn-soft);border-color:var(--warn-line)}
@media (hover:hover){.tilepill--unset:hover{background:var(--warn-soft);border-color:var(--warn)}}
.tilepill--unset .tilepill-txt small{color:var(--warn)}
.tilepill--unset svg{color:var(--warn)}
.tilepill svg{flex:none;color:var(--muted)}
.tilepill-txt{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.15}
.tilepill-txt b{font-size:14px;font-weight:600;white-space:nowrap}
.tilepill-txt small{color:var(--muted);font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media(max-width:400px){
  .stickybar--layout .btn{padding:0 10px;font-size:13px}
}

/* Липка панель кошториса: сума + «PDF / Друк».
   У базовій .stickybar сума була єдиним елементом, здатним стискатись (кнопки тримає власний
   nowrap-текст), тож на 360px увесь дефіцит ішов у неї: «32 812,78 грн» ламалось на три рядки
   в колонці 58px, панель роздувалась до 121px, і «PDF / Друк» усе одно вилазив за край.
   Лікуємо причину: сума flex:none і nowrap. Вторинна «Оновити кількості», якій тут доти
   ховали підпис, знята 2026-09-30 (кількості оновлюються на кожному вході на екран). */
.stickybar--est{gap:var(--space-2);padding-left:var(--space-3);padding-right:var(--space-3)}
.stickybar--est .estsum{flex:none;min-width:0;display:flex;flex-direction:column;
  justify-content:center;line-height:1.15}
.stickybar--est .lbl{font-size:11px;white-space:nowrap}
.stickybar--est .sum{font-size:17px;white-space:nowrap}
.stickybar--est .btn{flex:none}
.stickybar--est .btn--primary{padding:0 var(--space-4)}
/* 320px (SE 1-го покоління, спліт-екран). Сума flex:none і nowrap, тож на цій ширині дефіцит
   уперся б у «PDF / Друк» і знову виштовхнув його за край (−15px). Дотискаємо число й поля, а
   не підпис головної дії: «32 812,78 грн» мусить лишитись цілим — обрізана сума гірша за дрібну. */
@media(max-width:340px){
  .stickybar--est{gap:6px;padding-left:var(--space-2);padding-right:var(--space-2)}
  .stickybar--est .sum{font-size:15px}
  .stickybar--est .btn--primary{padding:0 10px;font-size:13px}
}

/* Landscape на телефоні: висота — дефіцитний ресурс. Тиснемо ШАПКУ, а не сцену:
   інакше заголовок + підзаголовок з'їдали 230px із 375 і плану лишалась смужка. */
@media(orientation:landscape) and (max-height:560px){
  .screen{padding-top:var(--space-2)}
  .backlink{min-height:32px}
  .screen-head{margin-bottom:var(--space-2)}
  .screen-head h1{font-size:17px}
  .screen-head .sub{display:inline;margin-left:var(--space-2);font-size:12px}
  .screen-head>div{display:flex;align-items:baseline;flex-wrap:wrap}
  .lstage{height:58vh;min-height:190px}
  .llegend{margin-bottom:var(--space-2)}
}

/* Стрічку зон (.lzones/.lzone) прибрано: перехід між кімнатами йде через список кімнат,
   куди й так веде «Зберегти» — це коротше й без діалогу «Зберегти розкладку?» на кожен чип. */


/* ══════════ Баг-репорт із пристрою (bug-report.js) ══════════
   Шторка тестувальника, а не продуктова поверхня: жодних власних токенів, усе з наявних
   класів (.chips/.field/.actions). Єдине, що тут своє, — блок контексту: він показує, ЩО
   піде у файл, тож людина не переказує словами те, що застосунок уже знає. */
.bugkinds{gap:var(--space-2)}
.bugdict{margin:-6px 0 var(--space-3)}
.bugctx{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--radius-s);
  padding:10px 12px;display:flex;flex-direction:column;gap:6px;font-size:12.5px}
.bugctx div{display:flex;gap:var(--space-3);align-items:baseline}
/* Підпис фіксованої ширини ставить усі значення в одну колонку — той самий прийом, що в
   рядках шухляди «Розрахунок»: зіставляти очима згори вниз, а не шукати зигзагом. */
.bugctx b{flex:none;width:86px;color:var(--muted);font-weight:600}
.bugctx span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bugctx .mono{font-family:var(--mono);font-size:12px}
.bugctx-warn{color:var(--warn);font-weight:600}
