/* ═══════════════════════════════════════════════════════════════════════
   Freshweb Booking — дизайн по ЧЕРТЕЖУ ceh/klienty/hos-majed/blueprint.md
   (образец: barberandco.us, снят 03.08.2026). Ни один цвет и шрифт не взят
   «из головы» — только из чертежа.

   Палитра и шрифты (наряд С6, чертёж v2 §2.6) ЦЕЛИКОМ переехали в
   theme.css — это ЕДИНСТВЕННОЕ место, где встречаются хекс-цвета; здесь,
   в style.css, их быть не должно (проверка: src/theme.test.ts, grep).
   Коротко: чёрный ↔ белый чередованием; золото — единственный акцент
   (≤10% площади: главная кнопка/эйбров/росчерк); янтарь — только иконки.
   Типографика: Oswald 500/600 CAPS, межстрочник 0.9 (аналог GT America
   Compressed) + Bitter (слаб-сериф) для текста и кнопок.
   Форма: пилюли radius 100px; карточки 8–16px; секции разделяет смена фона.
   Запреты чертежа: НЕТ градиентов в UI, НЕТ теней-карточек, НЕТ третьего
   цвета. Исключение (записано в чертеже): красная черта «сейчас» на
   таймлайнах — функциональный индикатор + зелёный/красный статусы форм.
   ═══════════════════════════════════════════════════════════════════════ */

@import url('theme.css');

* { margin: 0; padding: 0; box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  font-family: 'Bitter', Georgia, serif;      /* тело — слаб-сериф, как в чертеже */
  background: var(--sort);
  color: var(--hvid);
  line-height: 1.55;
  min-height: 100vh;
  font-size: 16px;
}

/* Заголовок-плакат: Oswald CAPS, межстрочник 0.9 — из чертежа */
h1, h2, h3, .display, .tid {
  font-family: 'Oswald', 'Arial Narrow', sans-serif;
  font-weight: 600;
  text-transform: uppercase;
  line-height: .9;
  letter-spacing: .5px;
}
h2.step-title { font-size: clamp(1.5rem, 4.5vw, 2rem); margin: 30px 0 12px; }

/* Эйбров чертежа: короткая золотая линия + капс */
.eyebrow {
  display: flex; align-items: center; gap: 10px;
  font: 600 .85rem 'Oswald', sans-serif; text-transform: uppercase;
  letter-spacing: 2px; color: inherit; margin-bottom: 10px;
}
.eyebrow::before { content: ''; width: 44px; height: 3px; background: var(--guld); }

.wrap { max-width: 640px; margin: 0 auto; padding: 0 16px 60px; }
.wrap-wide { max-width: 1184px; margin: 0 auto; padding: 0 20px 40px; }

header.top {
  padding: 18px 0 12px;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap;
}
.top .logo-img { height: 46px; width: auto; display: block; }
.top .sub { color: var(--daempet); font-size: .9rem; }

/* ── Кнопки-пилюли (radius 100px из чертежа) ────────────────────────────
   Главная: золотая заливка, ЧЁРНЫЙ текст. Вторичная: золотая ОБВОДКА.
   Третичная: серые (--pille-graa). Тёмного-на-тёмном нет.
   Кружок-стрелка — фирменный приём образца — снят вердиктом директора
   05.08 вечером (наряд Д4, п.5 «Никаких стрелок/эмодзи на кнопках — по
   всему продукту»): чертёж §14, чистая надпись важнее приёма образца. */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  cursor: pointer; text-decoration: none;
  font: 500 1.02rem 'Bitter', serif;
  padding: 14px 26px; border-radius: var(--pille);
  background: transparent; color: var(--hvid);
  border: 1.5px solid var(--guld);
  transition: background .15s ease, transform .08s ease;
  -webkit-tap-highlight-color: transparent;
}
.btn:hover { background: rgba(205,154,79,.12); }
.btn:active { transform: scale(.98); }
.btn:focus-visible { outline: 3px solid var(--rav); outline-offset: 3px; }
.btn-guld { background: var(--guld); border-color: var(--guld); color: var(--sort); font-weight: 600; }
.btn-guld:hover { background: var(--guld-hover); }
.btn-graa { background: var(--pille-graa); border-color: var(--pille-graa); color: var(--hvid); }
.btn[disabled] { opacity: .4; cursor: not-allowed; }
.btn-block { display: flex; width: 100%; }

/* ── Свои модалки взамен системных alert()/confirm() (наряд Д4) ─────────
   Системный confirm() браузер не даёт стилизовать — на любом телефоне он
   выглядит чужим на золото-чёрном продукте. Обёртка над нативным <dialog>
   (web/assets/modal.js): фокус-ловушку, Escape и затемнение фона браузер
   уже умеет сам — своей разметкой рисуем только карточку и кнопки. */
dialog.fw-modal {
  border: none; border-radius: var(--radius); padding: 22px;
  background: var(--mokka); color: var(--hvid);
  max-width: 360px; width: calc(100vw - 32px);
}
dialog.fw-modal::backdrop { background: rgba(0,0,0,.6); }
.fw-modal-text { font: 500 1.05rem 'Bitter', serif; line-height: 1.5;
  margin: 0 0 20px; white-space: pre-line; }
.fw-modal-actions { display: flex; gap: 10px; justify-content: flex-end; flex-wrap: wrap; }
/* Пульт причин (наряд П4, В9): в окне отмены не «да/нет», а четыре
   кнопки-цели — каждая сама себе ответ. Столбиком: датские подписи в ряд
   на 320 не живут, а тап-цель обязана остаться ≥44 px. */
.grund-pult { display: grid; gap: 8px; margin: 0 0 16px; }
.grund-pult .btn { width: 100%; min-height: 44px; }
/* Одна строка предупреждения у необратимого действия — единственное
   исключение из запрета абзацев (закон 0.2 чертежа). */
.fw-modal-note { margin: 0 0 16px; font-size: 1rem; color: var(--daempet); }

/* Замер (Н-3): белый по --roed даёт 4,04 : 1 — ниже канонных 4,5 у кнопки,
   которой удаляют и закрывают день. Чёрный по тому же красному даёт 5,20 и
   совпадает с языком продукта: заливка акцентом = тёмный текст (.btn-guld). */
.fw-modal-danger { background: var(--roed); border-color: var(--roed);
  color: var(--sort); font-weight: 600; }

/* ── Чипы: пилюли с золотой обводкой; активный — золотая заливка ──────── */
.chips { display: flex; gap: 8px; flex-wrap: wrap; margin: 14px 0; }
.chip {
  border: 1.5px solid var(--guld); background: transparent; color: var(--hvid);
  padding: 9px 18px; border-radius: var(--pille); cursor: pointer;
  font: 500 .95rem 'Bitter', serif;
}
.chip:hover { background: rgba(205,154,79,.12); }
.chip[aria-pressed="true"] { background: var(--guld); color: var(--sort); font-weight: 600; }
.chip:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }

/* ── Карточки услуг: флэт-панель, цена — Oswald ───────────────────────── */
.card {
  background: var(--mokka); border-radius: var(--radius);
  padding: 15px 18px; margin: 10px 0; cursor: pointer;
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  border: 1.5px solid transparent;
}
.card:hover { background: var(--mokka-2); }
.card[aria-pressed="true"] { border-color: var(--guld); }
.card .name { font-weight: 600; font-family: 'Bitter', serif; }
.card .meta { color: var(--daempet); font-size: .85rem; margin-top: 2px; }
.card .price {
  font-family: 'Oswald', sans-serif; font-weight: 600;
  font-size: 1.5rem; color: var(--hvid); white-space: nowrap;
}

/* ── Таблетки дат/времени: Oswald-цифры; активная — золотая ───────────── */
.pills { display: flex; gap: 8px; overflow-x: auto; padding: 6px 2px 10px; scrollbar-width: none; }
.pills::-webkit-scrollbar { display: none; }
.pill {
  min-width: 64px; padding: 10px 12px; border-radius: var(--radius); text-align: center;
  background: var(--mokka); color: var(--hvid); border: 1.5px solid rgba(255,255,255,.22);
  cursor: pointer; flex: 0 0 auto;
  font: 600 1.05rem 'Oswald', sans-serif; letter-spacing: .5px;
}
.pill small { display: block; color: var(--daempet); font: 500 .68rem 'Bitter', serif;
  text-transform: uppercase; letter-spacing: 1.2px; }
.pill:hover { border-color: var(--guld); }
.pill[aria-pressed="true"] { background: var(--guld); border-color: var(--guld); color: var(--sort); }
.pill[aria-pressed="true"] small { color: rgba(0,0,0,.6); }
.pill:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }
.pill[disabled] { opacity: .35; cursor: not-allowed; }

/* Слоты времени: ровная сетка равных ячеек (вердикт Алекса 16.08 с
   телефона: кнопки плясали по ширине текста — то один столбик, то два).
   Ширину задаёт сетка, не текст. */
.pills.tider {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
  gap: 8px;
  overflow-x: visible;
}
.pills.tider .pill { min-width: 0; width: 100%; }

/* ── Полка стрижек (наряд С4, чертёж §4): лента миниатюр внутри .pills ──
   Карточка — та же пилюля-логика (aria-pressed золотой), но с превью-фото. */
.frisure-pil {
  min-width: 84px; padding: 8px; border-radius: var(--radius); text-align: center;
  background: var(--mokka); color: var(--hvid); border: 1.5px solid rgba(255,255,255,.22);
  cursor: pointer; flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 6px;
}
.frisure-pil img { width: 64px; height: 64px; border-radius: 8px; object-fit: cover; display: block; }
.frisure-pil .frisure-ingen-ikon { width: 64px; height: 64px; border-radius: 8px;
  border: 1.5px dashed rgba(255,255,255,.3); display: flex; align-items: center; justify-content: center;
  font-size: 1.4rem; color: var(--daempet); }
.frisure-pil span { font: 600 .8rem 'Bitter', serif; max-width: 84px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.frisure-pil:hover { border-color: var(--guld); }
.frisure-pil[aria-pressed="true"] { background: var(--guld); border-color: var(--guld); color: var(--sort); }
.frisure-pil:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }
.lys .frisure-pil { background: var(--graa-bg); color: var(--sort); border-color: var(--graa-linje); }
.lys .frisure-pil[aria-pressed="true"] { background: var(--guld); border-color: var(--guld); }

/* ── Min hylde (klientens frisure-CRUD i «Mine tider») ─────────────────── */
.hylde-kort { display: flex; gap: 12px; align-items: center; padding: 10px 0;
  border-bottom: 1.5px solid var(--graa-linje); }
.hylde-kort:last-of-type { border-bottom: 0; }
.hylde-fotos { display: flex; gap: 4px; flex: 0 0 auto; }
.hylde-fotos img { width: 40px; height: 40px; border-radius: 6px; object-fit: cover; }
.hylde-info { flex: 1; min-width: 0; }
.hylde-info .name { font-weight: 600; }
.hylde-info .meta { color: var(--moerk-graa); font-size: .8rem; }
.hylde-tilfoej { margin-top: 14px; }
.hylde-tilfoej input[type="file"] { margin: 8px 0; font-size: .85rem; }

/* ── Календарь «Senere» (вердикт 05.08 п.7, общий узор — kalender.js) ── */
.kal { background: var(--mokka); border-radius: var(--radius); padding: 12px;
  margin: 4px 0 10px; max-width: 360px; }
.kal-hoved { display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 8px; }
.kal-titel { font: 600 1.05rem 'Oswald', sans-serif; letter-spacing: .06em;
  text-transform: capitalize; }
.kal-pil { width: 44px; height: 44px; border-radius: var(--radius);
  background: none; border: 1.5px solid rgba(255,255,255,.22);
  color: var(--hvid); font-size: 1.3rem; cursor: pointer; }
.kal-pil:hover { border-color: var(--guld); }
.kal-pil:disabled { opacity: .3; cursor: default; }
.kal-pil:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }
.kal-uge, .kal-net { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.kal-uge span { text-align: center; padding: 2px 0; color: var(--daempet);
  font: 500 .68rem 'Bitter', serif; text-transform: uppercase; letter-spacing: 1px; }
.kal-dag { aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
  border-radius: 10px; background: none; border: 1.5px solid transparent;
  color: var(--hvid); font: 600 1rem 'Oswald', sans-serif; cursor: pointer;
  min-height: 42px; }
.kal-dag:hover { border-color: var(--guld); }
.kal-dag[aria-pressed="true"] { background: var(--guld); color: var(--sort); }
.kal-dag:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }
span.kal-lukket { color: var(--daempet); opacity: .4; cursor: default; }
.kal-tom { min-height: 42px; }

/* ── Формы ────────────────────────────────────────────────────────────── */
label.field { display: block; margin: 14px 0 4px; color: var(--daempet); font-size: .9rem; }
/* type="url" был забыт в этом списке: два поля соцсетей в панели рисовались
   голыми системными полями — белая заливка на чёрной панели, высота 19 px
   при канонных 44 (замер 332×19). Кроме admin.html полей url в продукте нет,
   так что добавление типа не трогает другие страницы. */
input[type="text"], input[type="tel"], input[type="number"], input[type="date"],
input[type="time"], input[type="email"], input[type="password"], input[type="url"], select {
  width: 100%; padding: 13px 16px; border-radius: var(--radius);
  border: 1.5px solid rgba(255,255,255,.22); background: var(--mokka); color: var(--hvid);
  font: 500 1.02rem 'Bitter', serif;
}
input:focus-visible, select:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }

/* ── Итог брони: чертёжное чередование — БЕЛАЯ секция на чёрной странице ─ */
.summary {
  background: var(--hvid); color: var(--sort);
  border-radius: 16px 16px 0 0;
  padding: 18px 20px 6px; margin: 18px 0 0;
}
.summary dt { color: var(--daempet); font-size: .74rem; text-transform: uppercase;
  letter-spacing: 1.4px; margin-top: 12px; font-family: 'Oswald', sans-serif; font-weight: 500; }
.summary dd { font-size: 1.06rem; font-weight: 600; }
.summary dd.big {
  font-family: 'Oswald', sans-serif; font-weight: 600;
  font-size: 2.1rem; line-height: 1; color: var(--sort);
}
.confirm-block { background: var(--hvid); border-radius: 0 0 16px 16px; padding: 12px 16px 16px; }
.confirm-block .btn { background: var(--guld); border-color: var(--guld); color: var(--sort); font-weight: 600; }
.confirm-block .btn:hover { background: var(--guld-hover); }

/* ── РАЗРЕЗ ЗАНАВЕСА: ножницы режут ЧЁРНЫЙ ЭКРАН ────────────────────────
   Подход директора (04.08.2026, третья итерация — принят): лента просто
   едет вверх скроллом; после героя стоит ЧЁРНЫЙ ЗАНАВЕС из двух половин
   с диагональным стыком. Спектакль по времени: ножницы прорезают чёрное
   золотой линией → половины разъезжаются (верхняя вверх, нижняя вниз) →
   в щели всплывает белая зона с кнопками.
   Переменные (ставит JS):
   --klinge 0..1 — полёт ножниц по диагонали = прорисовка линии;
   --spalt  0..1 — раздвижение половин;
   --frem   0..1 — всплытие белого содержимого;
   --chik   0..14 — раскрытие лезвий (градусы), «чик-чик» по пути;
   --hcut   px   — высота линии реза от верха занавеса;
   --vinkel/--diag — угол и длина диагонали (зависят от ширины экрана).
   ДЕФОЛТЫ CSS = открытое состояние: без JS страница полностью рабочая.
   Диагональ: слева ниже на 48px, как след косого реза. ────────────────── */
.snit-wrap {
  position: relative;
  z-index: 3;
  /* Улетевшие за край ножницы растягивали страницу вбок — запираем */
  overflow: hidden; overflow: clip;
  --klinge: 1; --spalt: 1; --frem: 1; --chik: 0; --hcut: 300px;
}
/* Занавес: слой в первый экран поверх белой зоны; свой clip — уехавшие
   половины исчезают за его краями, кнопкам не мешает (pointer-events) */
.taeppe {
  position: absolute; left: 0; right: 0; top: 0; height: 100svh;
  z-index: 4; pointer-events: none;
  overflow: hidden; overflow: clip;
}
.taeppe-del { position: absolute; left: 0; right: 0; background: var(--sort); }
/* Верхняя половина: низ скошен по диагонали, уезжает ВВЕРХ */
.taeppe-del.top {
  top: 0; height: calc(var(--hcut) + 48px);
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 48px), 0 100%);
  transform: translateY(calc(-1 * var(--spalt) * (var(--hcut) + 68px)));
}
/* Нижняя половина: верх скошен, уезжает ВНИЗ */
.taeppe-del.bund {
  top: var(--hcut); height: calc(100svh - var(--hcut));
  clip-path: polygon(0 48px, 100% 0, 100% 100%, 0 100%);
  transform: translateY(calc(var(--spalt) * (100svh - var(--hcut))));
}
/* Золотые кромки разреза: линия рисуется за ножницами; при раздвижении
   верхняя уезжает с верхней половиной, нижняя — с нижней (две кромки
   разрезанной ткани). Div вместо SVG: dashoffset рисовал пунктир на ретине */
.snit-linje {
  position: absolute; left: 0;
  top: calc(var(--hcut) + 48px);
  width: var(--diag, 100%); height: 3px;
  z-index: 5; pointer-events: none;
  background: var(--guld);
  transform-origin: 0 50%;
  filter: drop-shadow(0 0 6px rgba(205,154,79,.55));
}
.snit-linje.guld-top {
  transform: translateY(calc(-1 * var(--spalt) * (var(--hcut) + 68px)))
             rotate(var(--vinkel, -7deg)) scaleX(var(--klinge));
}
.snit-linje.guld-bund {
  transform: translateY(calc(var(--spalt) * (100svh - var(--hcut))))
             rotate(var(--vinkel, -7deg)) scaleX(var(--klinge));
  opacity: min(1, calc(var(--spalt) * 8));  /* вторая кромка видна с раздвижением */
}
/* Ножницы-резчики: две копии маски лого (кольцо в центре холста = ось),
   нижняя отражена — смыкаются и раскрываются, «стригут» чёрное */
.snit-saks {
  position: absolute; z-index: 6; pointer-events: none;
  left: calc(var(--klinge) * 100%);
  top: calc(var(--hcut) + 48px - var(--klinge) * 48px);
  width: 130px; height: 130px; margin: -65px 0 0 -65px;
  transform: rotate(var(--vinkel, -7deg));
  opacity: var(--saks-syn, 0);
  transition: opacity .18s linear;
  filter: drop-shadow(0 2px 8px rgba(0,0,0,.65));
}
.snit-blad {
  position: absolute; inset: 0;
  -webkit-mask: url('/assets/logo-saks-fed.png') center / contain no-repeat;
          mask: url('/assets/logo-saks-fed.png') center / contain no-repeat;
  background: var(--stal-lys);        /* светлая сталь, как ножницы в его лого */
}
.snit-blad.a { transform: rotate(calc(var(--chik) * 1deg)); }
.snit-blad.b { transform: scaleY(-1) rotate(calc(var(--chik) * 1deg)); }
/* Десктоп: диагональ длинная — ножницы крупнее, иначе теряются */
@media (min-width: 900px) {
  .snit-saks { width: 180px; height: 180px; margin: -90px 0 0 -90px; }
}
/* Всплытие белого: содержимое поднимается и дорастает до места, пока
   половины разъезжаются. Под закрытым занавесом его не видно вовсе,
   так что туман на паузе (забракован директором) невозможен. */
.snit-wrap .lys > .wrap {
  transform: translateY(calc((1 - var(--frem)) * 26px))
             scale(calc(.982 + .018 * var(--frem)));
  opacity: var(--frem);
}
/* Белой зоне — минимум экран роста: иначе странице не хватало длины
   довезти запись до верха (glideTo стукался о дно на полном ходу),
   а на десктопе занавес обрезался над подвалом */
.snit-wrap .lys { padding-top: 40px; min-height: 100svh; }

/* ── Светлая секция (.lys): чередование чёрное↔белое из чертежа ───────── */
.lys { background: var(--hvid); color: var(--sort); }
.lys .card { background: var(--graa-bg); border-color: transparent; }
.lys .card:hover { background: var(--lys-hover); }
.lys .card[aria-pressed="true"] { border-color: var(--guld); }
.lys .card .price, .lys .card .name { color: var(--sort); }
.lys .chip { color: var(--sort); }
.lys .chip[aria-pressed="true"] { color: var(--sort); }
.lys .pill { background: var(--graa-bg); color: var(--sort); border-color: var(--graa-linje); }
.lys .pill small { color: var(--daempet-lys); }
.lys .pill[aria-pressed="true"] { background: var(--guld); border-color: var(--guld); }
.lys input, .lys select { background: var(--graa-bg); color: var(--sort); border-color: var(--graa-linje); }
.lys label.field { color: var(--moerk-graa); }
.lys .note { color: var(--moerk-graa); }
.lys .muted { color: var(--daempet-lys); }
.lys .btn { color: var(--sort); }
.lys .btn-guld { color: var(--sort); }
.lys .summary { border: 1.5px solid var(--graa-linje); border-bottom: 0; }
.lys .confirm-block { border: 1.5px solid var(--graa-linje); border-top: 0; }

/* ── Единый поток записи (наряд Д2, вердикт директора 05.08) ────────────
   Переключатель «1 person / Flere personer» встраивает группу в ту же
   белую ленту — чёрная отдельная страница /gruppe ушла. Внутри карточки
   человека два УРОВНЯ выбора должны читаться с одного взгляда: сегмент
   («кого стрижём») — контурная пилюля (.chip, уже есть), услуги — карточки
   (.card, уже есть); здесь только сама карточка-контейнер и подпись корзины. */
.modus-toggle { display: flex; gap: 8px; margin: 4px 0 20px; }
.modus-toggle .chip { flex: 1; text-align: center; }
.person-kort {
  background: var(--mokka); border-radius: var(--radius);
  padding: 16px; margin: 14px 0;
}
.lys .person-kort { background: var(--graa-bg); }
.person-kort h3 { font-size: 1.05rem; margin-bottom: 10px; }
.person-kort input.navn { width: 100%; margin-bottom: 12px; }
.person-kort .chips { margin: 8px 0 4px; }
.valgte-korv { color: var(--guld); font-size: .88rem; min-height: 1.3em; margin: 2px 0 4px; }

/* Обзор визита на шаге подтверждения (flere personer): каждая позиция —
   золотая точка-индикатор перед именем, текст наследует чёрный от .lys. */
.oversigt-person { margin: 12px 0; }
.oversigt-person .nm { font-family: 'Oswald', sans-serif; font-weight: 600; letter-spacing: .3px; }
.oversigt-person .nm::before { content: ''; display: inline-block; width: 5px; height: 5px; background: var(--guld); border-radius: 50%; margin-right: 8px; vertical-align: middle; }
/* Подпись рассадки под временем варианта — строчными, не капсом дат/времени */
.variant small { text-transform: none; letter-spacing: 0; }

/* ── Служебные ────────────────────────────────────────────────────────── */
.note { color: var(--daempet); font-size: .88rem; margin: 10px 0; }
.error { background: rgba(225,72,63,.1); border: 1.5px solid var(--roed); color: inherit;
  border-radius: var(--radius); padding: 12px 14px; margin: 12px 0; }
.ok-banner { background: rgba(79,157,105,.1); border: 1.5px solid var(--groen);
  border-radius: var(--radius); padding: 14px 16px; margin: 12px 0; }
/* Строка «запись закрыта» и строка акции — одно место страницы записи и
   один приём: рамка золотом, без заливки. Правило ОДНО на оба класса, чтобы
   баннер акции в панели (превью) и у клиента не могли выглядеть по-разному
   (наряд П5). Саму разметку .tilbud-banner строит /assets/tilbud.js. */
.paused-banner, .tilbud-banner { border: 1.5px solid var(--guld);
  border-radius: var(--radius); padding: 14px 16px; margin: 14px 0; font-weight: 600; }
/* Обе строки живут на БЕЛОЙ секции — там золото берёт свою тёмную ступень
   (theme.css, --guld-paa-hvid): замер рамки 2,52 → 3,43 : 1. */
.lys .paused-banner, .lys .tilbud-banner { border-color: var(--guld-paa-hvid); }

/* ── Пусто в дне (наряд Д3): было мелким .note, тонуло на экране —
   директор попросил КРУПНОЕ красное сообщение, не тихую сноску. ────────── */
.varsel-stor {
  font: 600 clamp(1rem, 4vw, 1.25rem) 'Oswald', sans-serif;
  text-transform: uppercase; letter-spacing: .3px; line-height: 1.35;
  text-align: center; color: var(--roed);
  background: rgba(225,72,63,.08); border: 1.5px solid var(--roed);
  border-radius: var(--radius); padding: 18px 16px; margin: 12px 0;
}

/* ── Мигание проблемного места при ошибке валидации (наряд Д3): скроллим
   к полю/ряду и обводим красным — сообщение сверху одно, но глаз ведём
   туда, где чинить, а не заставляем искать самому. ─────────────────────── */
@keyframes felt-blink {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  25%, 75% { box-shadow: 0 0 0 3px var(--roed); }
}
.felt-blink { border-radius: var(--radius); animation: felt-blink .5s ease-in-out 3; }
@media (prefers-reduced-motion: reduce) {
  .felt-blink { animation: none; box-shadow: 0 0 0 3px var(--roed); }
}

/* ── Konto (наряд С3, чертёж §3): kort til login/mine tider ────────────── */
.konto-kort { background: var(--graa-bg); border: 1.5px solid var(--graa-linje);
  border-radius: var(--radius); padding: 16px 18px; margin: 14px 0; }
.lys .konto-kort { background: var(--graa-bg); }
/* Вся строка — тап-цель: у <label> клик по тексту переключает галку, и
   именно строка обязана держать канонные 44 px. Сам системный чекбокс
   20×20 — это его размер, не размер цели. */
.checkbox-row { display: flex; align-items: center; gap: 10px; margin: 14px 0;
  min-height: 44px; cursor: pointer; }
.checkbox-row input[type="checkbox"] {
  width: 20px; height: 20px; flex-shrink: 0; margin-top: 1px; accent-color: var(--guld);
}
.checkbox-row input[type="checkbox"]:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }
/* Канон §2: текст ≥16 px ВСЕГДА. Было .92rem (14,7 px) — подпись согласия
   (наряд П4) обязана читаться, и то же чинится у соседей по классу. */
.checkbox-row span { font-size: 1rem; line-height: 1.5; color: var(--moerk-graa); }
.link-btn { background: none; border: 0; padding: 0; color: var(--guld); font-weight: 600;
  font: inherit; cursor: pointer; text-decoration: underline; }
.link-btn:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }
.social-stub { display: flex; gap: 8px; margin-top: 10px; }
.social-stub button {
  flex: 1; padding: 10px; border-radius: var(--radius); border: 1.5px solid var(--graa-linje);
  background: transparent; color: var(--moerk-graa); font: 500 .88rem 'Bitter', serif;
  cursor: not-allowed; opacity: .55;                    /* честно «скоро», не кликабельно */
}

.step-title { margin: 24px 0 8px; }
.muted { color: var(--daempet); }
.hidden { display: none !important; }

/* Визуально скрытый текст, но доступный читалкам и поисковикам */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); clip-path: inset(50%);
  white-space: nowrap; border-width: 0;
}

.sticky-cta { position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 40; }

footer.bund { color: var(--daempet); font-size: .8rem; text-align: center; padding: 30px 0 16px; }
/* Значки соцсетей (наряд Д4): янтарь — по чертежу цвет ТОЛЬКО для иконок.
   Facebook/Instagram — один и тот же класс, ссылки приходят из salon.* —
   свели в одно место вместо захардкоженной ссылки в разметке. */
.bund .social { display: inline-flex; gap: 14px; justify-content: center; margin: 2px 0 10px; }
.bund .social a { display: inline-flex; padding: 6px; color: var(--rav); border-radius: 50%; }
.bund .social a:hover { color: var(--guld); }
.bund .social a:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }

/* ═══ ГЕРОЙ ГЛАВНОЙ ═══════════════════════════════════════════════════
   Круг 4, вердикт директора: на экране только МАРКА КЛИЕНТА в масштабе
   героя и два действия. Заголовок-обещание, эйбров и подзаголовок сняты
   вместе с их правилами — не спрятаны, а удалены.
   Весь металл живёт в запечённых ассетах (буквы, знак, кнопка); в CSS нет
   ни градиента, ни стопки копий «под объём» — повторение хрома круга 1
   кодом приёмка считает браком.
   ══════════════════════════════════════════════════════════════════════ */
.hero {
  position: relative; min-height: 100svh; overflow: hidden;
  display: grid; place-items: center; text-align: center;
}
/* Полный кадр без зума. Кадрирование top:-50%/160% ставилось кругом 2
   против родной вывески «HOS MAJED» в сценах 0–5,3 с — но круг 3 играет
   только тёплый отрезок 7,6–13,6 с, вывески в петле больше нет, и зум
   1,91× лишь срезал потолок с лампами — ту самую «тёплую тьму» чертежа.
   Подпорка снята приёмкой круга 3 (Хольгер заметил, Андерсен подтвердил
   пробой в браузере). ВОССТАНОВЛЕНО 16.08 вечером: правку смыло откатом
   соседней сессии в общей рабочей копии (тот же класс, что урок
   git-reset). Если петля когда-нибудь вернёт холодный отрезок с
   вывеской — кадрирование возвращается вместе с ним. */
.hero-video {
  position: absolute; left: 0; width: 100%;
  top: 0; height: 100%;
  object-fit: cover;
}
/* Видео уводим в фактуру: затемнение + лёгкая расфокусировка.
   04.08.2026, директор: «слишком затуманено» — размытие 3→2, добавлен
   контраст, тень .66→.58. */
.hero-video { filter: blur(2px) saturate(.95) contrast(1.06);
  /* нырок в темноту на шве петли — класс ставит скрипт героя */
  transition: opacity .35s ease; }
.hero-video.v-styk { opacity: 0; }
.hero-skygge { position: absolute; inset: 0; background: rgba(0,0,0,.58); }
/* width:100% обязателен. Без него грид-элемент с place-items:center
   сжимается по содержимому, а если самый широкий ребёнок задан в vw, сумма
   «ребёнок + собственный паддинг» вылезает за экран — и браузер прижимает
   колонку к левому краю. Прибор ловил это как перекос +3,9 / +6 / +9 px
   на 390 / 600 / 900 (на 1280 работал max-width и перекоса не было).
   Отсюда правило: ширина ШИРОКИХ детей героя (заголовок, знак) считается
   от контейнера в %, не в vw — иначе она не знает про его паддинг. */
.hero-inner {
  position: relative; z-index: 2;
  width: 100%; max-width: 1184px;          /* контейнер чертежа */
  padding: 32px clamp(16px, 5vw, 64px);
}

/* ── МАРКА КЛИЕНТА В МАСШТАБЕ ГЕРОЯ ────────────────────────────────────
   Ширина блока = ширина слова MAJED. От неё в ДОЛЯХ считается всё
   остальное, поэтому пропорции логотипа одинаковы на телефоне и на
   десктопе — они сняты прибором с самой марки (assets/logo-hosmajed.png):

     кегль HOS / кегль MAJED          0,530  →  собрано 0,523
     ширина HOS / ширина MAJED        0,279  →  собрано 0,281
     межстрочный зазор / кегль MAJED  0,386  →  собрано 0,367

   ОДНО отношение марке намеренно НЕ следует — ширина знака (круг 5).
   В самой марке росчерк занимает 29,9 % ширины MAJED и работает
   подчёркиванием под словом; в героя, где марка ростом во весь экран, при
   этой доле он читается щепкой («сами ножницы маленькие, коравастые» —
   вердикт пальцем 17.08). Директор задал размер по глифам: знак заполняет
   три средние буквы, от левого края A до правого края E, а это 818 px из
   1599 = 51,2 % ширины MAJED. Правило журнала вкуса 16.08 (8): в героя
   марка идёт композицией под экран, а не копией пропорций логотипа. */
.maerke { width: min(100%, 820px); margin: 0 auto; }
.maerke-ord { width: 100%; height: auto; display: block; }

/* ── ЗНАК САЛОНА: запечённый рендер, вырезанный по силуэту ─────────────
   Объём НЕ имитируется стопкой плоских копий (правило приёмки 13.08):
   толщина, свет и металл сняты в рендере znak-etalon.png. Альфа снимается
   заливкой фона от края кадра, поэтому тело непрозрачно целиком и тень
   предмета не плывёт вместе с фоном (0,0 против 89 у круга 2).

   Отступ и ширина — доли ширины марки (проценты в margin считаются от
   ширины родителя, поэтому одно число держит пропорцию на всех экранах). */
.maerke-tegn {
  position: relative;
  /* 51,2 % — ширина трёх средних букв A→E, замер по глифам самой марки
     (818 px из 1599). Не «на глаз крупнее»: директор назвал границы, число
     снято прибором. Было 29,86 % (доля росчерка в марке) — рост в 1,71 раза. */
  width: 51.2%;
  /* 5,38 %, а не 2,93 % круга 4: отступ считается от НИЖНЕЙ КРОМКИ картинки
     букв, а у прежнего кандидата хвост J свисал под строку на 14 % кегля и
     сам съедал часть зазора. У нового кандидата свес 0,7 % (у марки 1,2 %),
     картинка кончается на базовой линии — и зазор до знака приходится
     задавать целиком. Число печатает instrument/sborka-logotipa.py. */
  margin: 5.38% auto 0;
  perspective: 900px;
  cursor: grab;
  touch-action: pan-y;      /* вертикальный скролл пальцем остаётся скроллом */
  user-select: none;        /* ведение пальцем не выделяет и не тащит картинку */
  -webkit-user-drag: none;
  -webkit-tap-highlight-color: transparent;
}
.maerke-tegn.holdes { cursor: grabbing; }
/* ЗОНА ЗАХВАТА, а не воздух: сам росчерк тонкий (на 390 его высота 18 px),
   а пальцу нужна цель от 44 px. Расширяем невидимым слоем поверх, а не
   паддингом: паддинг раздвинул бы поток и сбил марочный зазор под словом
   (на 390 он всего 10 px, паддинг съел бы его целиком). */
.maerke-tegn::before {
  content: ''; position: absolute; inset: -15px 0; z-index: 1;
}
.znak {
  width: 100%; height: auto; display: block;
  will-change: transform;
  filter: drop-shadow(0 10px 26px rgba(0,0,0,.55));  /* одна тень: предмет лежит на кадре */
}
/* ТОРЕЦ ПРЕДМЕТА — то, что видно, когда лицо повернулось к нам ребром.
   Ширина 1,6 % длины: у парикмахерских ножниц спинка 2–3 мм при длине около
   160 мм. Не «на глаз тонкая полоска», а размер настоящей вещи.
   Ассет — 3×243 px, выведен построчно из самого знака (rebro-znaka.py).
   Ширину по углу и видимость ведёт скрипт (см. risuj()); в покое торца в
   кадре нет вовсе — предмет стоит лицом. transform-origin по центру, чтобы
   полоска сжималась к оси вращения, а не уползала вбок. */
.znak-rebro {
  position: absolute; top: 0; bottom: 0; left: 0; right: 0;
  width: 1.6%; margin-inline: auto;
  background: url(/assets/rebro-majed.webp) center / 100% 100% no-repeat;
  transform: scaleX(0); transform-origin: 50% 50%;
  opacity: 0; pointer-events: none;
}

/* ── ДВА ДЕЙСТВИЯ ПРЕДМЕТАМИ ───────────────────────────────────────────
   Ряд кнопок ровно по ширине марки: размер берётся от логотипа, а не от
   длины надписи (наряд круга 4). Картинка кнопки НЕ растягивается —
   border-image режет её на три части и тянет только середину, концы
   держат свою форму. Круг 4-бис: заготовка сменена на ТЁМНУЮ сталь
   (kandidaty-knopka/temnye/gen-gpt-078003-2.png) — светлая латунь К1 не
   держала золотую надпись физически (1,88:1).
   Круг 5: заготовка сменена снова, на СВЕТЛУЮ тёплую сталь
   (kandidaty-knopka/stal/gen-gpt-962254-2.png) — вердикт пальцем 17.08:
   «полировка стали кнопок слишком тёмная, контрастит со сталью знака».
   Замер: яркость лица 142 против 92 у тёмной и 131 у знака — кнопка вошла
   в семью металла. Слайс 111 → 114, доля 0,5045 → 0,5182 (числа печатает
   instrument/podgotovka-knopki.py, они обязаны совпадать между собой).
   Круг 4-тер: слайс 93 → 111, доля 0,4227 → 0,5045, и это не подгонка
   вкуса. Круг 4-бис мерил слайс как «первый столбец полной высоты» и попал
   на 93 — но полная высота там набегала из-за тёмной нашлёпки в самом
   ассете, а настоящая полуось торца (место, где дуга переходит в прямую)
   равна 110,5 px из 220: предмет — стадион с почти полукруглыми концами
   (подгонка капсулы к контуру исходника, instrument/podgotovka-knopki.py,
   невязка медиана 0,72 px исходника). Из-за старого числа 17 px дуги
   лежали в растягиваемой середине и плющились вместе с ней.
   Слайс и доля обязаны совпадать: столько же занимает боковой бордюр от
   высоты кнопки, поэтому колпачок сохраняет свою форму на любой ширине.
   Надпись — настоящий текст: датский меняется, и читалка обязана его
   видеть, а впечатанный в картинку он был бы для неё немым. */
.hero-cta {
  display: flex; gap: 16px;
  width: min(100%, 820px); margin: 48px auto 0;
}
.knap-emne {
  --kh: clamp(56px, 5.4vw, 68px);
  --kolpak: calc(var(--kh) * .5182);   /* полуось колпачка = слайс 114 / высота 220 */
  flex: 1 1 0; position: relative;
  isolation: isolate;                  /* слои кнопки не выходят наружу */
  display: inline-flex; align-items: center; justify-content: center;
  /* Предмет живёт отдельным слоем (::before), а не бордюром самой ссылки.
     Причина механическая: слой-блик — абсолютный, его контейнер padding-box,
     и при бордюре он либо не накрывал колпачки, либо вылезал за padding-box
     на 26 px — робот вкуса честно ловил это как text-overflow (scrollWidth
     минус clientWidth). Теперь коробка ссылки = вся пилюля, оба слоя внутри,
     а место надписи держит паддинг, равный колпачку. */
  height: var(--kh); padding-inline: calc(var(--kolpak) + 8px);
  text-decoration: none; cursor: pointer;
  /* Кегль 24 px постоянный, не плавающий. Причина не вкусовая: фон надписи —
     живая фактура металла с разбросом яркости, и по WCAG 24 px это уже
     «крупный текст» (норма 3:1 вместо 4,5:1) — единственная планка, которую
     фотография стали держит честно. Замеры — в отчёте круга 4. */
  font: 600 1.5rem/1 'Oswald', sans-serif;
  letter-spacing: 1px;
  /* ГРАВЮРА РЕЛЬЕФОМ, а не цветом (круг 5).
     Вердикт пальцем 17.08: «текст закодирован, нет ощущения выгравированного
     золотом». Круги 4-бис/4-тер держали золото ЦВЕТОМ буквы — на тёмной
     стали это читалось, но лицо кнопки пришлось держать тёмным, и оно
     выпало из семьи металла. На светлой стали плоское золото физически
     не читается: --guld на лице яркостью 142 даёт 1,26:1.
     Поэтому золото переезжает из тела буквы в её кромку, а тело буквы
     становится тем, чем и должно быть у гравюры, — ТЕНЬЮ БОРОЗДКИ:

       тело     var(--gravyr)  — тёмное золото, не чёрное: тот же тон, что фаска
                                  заготовки, только глубоко в тени. 4,58:1 к лицу;
       снизу    --guld   — освещённая нижняя стенка выемки: свет в кадре
                           падает сверху, значит дно ловит его именно там.
                           Это и есть «выгравировано золотом»;
       сверху   чёрное   — верхняя стенка в собственной тени, отсюда
                           ощущение вдавленности, а не наклейки.

     Обе кромки ровно 1 px и без размытия: у резца край острый. Ни
     хромовых градиентов по телу буквы, ни стопки масок, ни бегущих бликов —
     объём здесь делает свет, а не количество слоёв. */
  color: var(--gravyr);
  text-shadow: 0 -1px 0 rgba(0, 0, 0, .55), 0 1px 0 var(--guld);
  -webkit-tap-highlight-color: transparent;
  transition: transform .15s ease;
}
/* САМ ПРЕДМЕТ. Бордюр держит только этот слой, поэтому «/ 1» здесь — не
   украшение: множитель от border-width против «auto». Круг 4 писал «auto»,
   и это была ошибка, которую поймал глаз на тёмной заготовке: auto = «взять
   натуральный размер слайса», то есть 93 CSS px на колпачок вместо
   положенных 28,7 — колпачок растягивался поперёк в 3,2 раза (замер на
   пробе: плато начиналось с 93 CSS px вместо 28). Оттуда же чёрный огрызок
   на кончике: тёмный носик ассета раздувался в отдельную палочку. */
.knap-emne::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  border: 0 solid transparent; border-inline-width: var(--kolpak);
  border-image: url(/assets/knopka-majed.webp) 0 114 fill / 1 / 0 stretch;
}
/* Один слой на два состояния: наведение добавляет блик, нажатие меняет его
   на тень — предмет утапливается, и свет с него уходит. Анимируется только
   opacity (норма канона).
   Вставка на 2–3 px: слой держится ВНУТРИ пилюли, иначе прямоугольник со
   скруглением вылезает за фаску ассета и по краю идёт светлая каёмка.
   Скругление ЭЛЛИПТИЧЕСКОЕ: горизонтальная полуось колпачка минус вставка,
   вертикальная — половина высоты. Проверено прибором: слой залит контрольным
   цветом, край сверен с силуэтом пилюли — вне силуэта 0 px, зазор 3 px. */
.knap-emne::after {
  content: ''; position: absolute; inset: 2px 3px;
  border-radius: calc(var(--kolpak) - 3px) / 50%;
  background: var(--blik, var(--hvid)); opacity: var(--blik-a, 0);
  transition: opacity .15s linear; pointer-events: none;
}
/* Блик наведения ТЁПЛЫЙ, а не белый. На тёмной стали круга 4-бис белый слой
   читался просто «светлее»; на светлой тёплой стали он сер и съедает тот
   самый тон, за который заготовку и взяли (сверка кадров пoкой/hover). */
.knap-emne:hover { --blik: var(--gravyr-blik); --blik-a: .10; }
.knap-emne:active { --blik: var(--sort); --blik-a: .16; transform: translateY(1px); }
.knap-emne:focus-visible { outline: 3px solid var(--rav); outline-offset: 4px; }

/* Телефон: две пилюли в ряд сжимаются до 167 px, и в них перестаёт
   помещаться крупная надпись (номер при кегле 24 px — 140 px плюс концы
   пилюли). Ставим друг под друга: каждая во всю ширину марки, надпись
   остаётся той же, а цель для пальца становится вдвое крупнее. */
@media (max-width: 639px) {
  .hero-cta { flex-direction: column; }
  /* В колонке flex-basis считается по ВЫСОТЕ: с flex:1 обе пилюли делили
     между собой высоту ряда и садились до 24 px. Высоту здесь задаёт --kh. */
  .knap-emne { flex: none; }
}

/* Стрелка «листай дальше».
   Гаснет, как только начался скролл (--hint ставит движок разреза). Раньше
   она этого не делала и белое полотно закапывало её на ходу — из шва торчал
   серый огрызок. Двигать её вверх нельзя: там кнопки. Гасим — она всё равно
   нужна только на первом кадре. */
.hero-scroll {
  position: absolute; bottom: 22px; left: 50%; transform: translateX(-50%);
  opacity: var(--hint, 1); transition: opacity .25s linear;
  z-index: 2; width: 26px; height: 42px; border: 2px solid rgba(255,255,255,.5);
  border-radius: 14px; display: grid; place-items: start center; padding-top: 7px;
  /* Явный цвет. Текста в ссылке нет, ни один пиксель им не красится — но без
     этой строки в вычисленных стилях страницы живёт синий цвет ссылки
     rgb(0,0,238), то есть третий цвет вне палитры чертежа (Н17 приёмки). */
  color: var(--hvid);
}
/* ЗОНА ЗАХВАТА, тот же приём, что у знака (.maerke-tegn::before): сам рисунок
   мышки 26×42, норма канона для цели пальца ≥44×44. Расширяем невидимым
   слоем, а не размером рамки: рамка — это и есть рисунок, растягивать её
   значит рисовать другую мышку. Паддинг тоже не годится — он сдвинул бы
   точку внутри рамки. Итог 50×62 при видимых 26×42. */
.hero-scroll::before {
  content: ''; position: absolute; inset: -10px -12px;
}
/* Подсказка скролла: ТРИ повтора, не бесконечность (Н16 приёмки; выжимка
   журнала §3 — ноль бесконечных автолупов на клиентских страницах).
   Почему повторы, а не снятие вовсе: точка приглашает пролистать, и это
   единственное, что её показывает, — но приглашение произносится один раз
   (5,4 с) и замолкает, дальше первый экран стоит неподвижно. */
.hero-scroll span { width: 3px; height: 8px; background: var(--guld); border-radius: 2px;
  animation: scroll-hint 1.8s ease-in-out 3; }
@keyframes scroll-hint { 50% { transform: translateY(12px); opacity: .3; } }

/* Уважаем системную настройку «уменьшить движение», но НЕ убиваем экран:
   видео остаётся (стоит на постере — тёплом кадре салона), знак не движется.
   Раньше здесь было display:none на видео — из-за этого при включённой
   настройке главная выглядела мёртвой. Исправлено 03.08.2026.
   16.08.2026 (Н14 приёмки): этот комментарий три круга ОБЕЩАЛ паузу, а код её
   не делал — у <video> стоял атрибут autoplay, и слушатель pause сам заводил
   видео обратно через 300 мс. Теперь пауза настоящая, механизм в index.html:
   атрибут autoplay снят, запуск ведёт скрипт и при reduce его не зовёт.
   Урок цеха: заявленное поведение проверяется пробой кода, не кадром —
   статичный снимок не отличит паузу от кадра играющего видео. */
@media (prefers-reduced-motion: reduce) {
  .hero-scroll span { animation: none; }
  /* Знак здесь НЕ фиксируется правилом transform:none. При «меньше
     движения» предмет по-прежнему поворачивается под пальцем — это ответ
     на действие человека, а не автодвижение; отнимать вещь у того, кто
     сам её взял, настройка не просит. Скрипт при reduce убирает ровно
     автоматическую часть: выбег по инерции после броска. */
}
/* Кнопку «Afspil video» при reduce показывает СКРИПТ тем же классом .vis,
   что и при заблокированном автозапуске: один механизм, одно место правки.
   Через CSS здесь нельзя — базовое правило .hero-play ниже по файлу и
   при равной силе перебило бы медиазапрос. */

/* Кнопка запуска видео — если браузер заблокировал автозапуск
   (iPhone в режиме энергосбережения, строгие настройки Safari) И при
   настройке «меньше движения», где она единственный способ посмотреть видео.
   Круг 3: переехала из-под кнопок в НИЖНИЙ ПРАВЫЙ УГОЛ. Причина замерена:
   стоя по центру на bottom:84px, она перекрывала кнопку телефона на 320 и
   1280 (пересечение прямоугольников, зазор −1 px при норме канона ≥8).
   Раньше это не было видно, потому что кнопка почти никогда не показывалась;
   с честным reduce она видна всегда. В углу зазоры: 12 px до подсказки
   скролла на 320, 47 px на 390, до кнопок — от 51 px. */
.hero-play {
  position: absolute; z-index: 3;
  right: clamp(16px, 5vw, 64px); bottom: 22px;
  display: none; align-items: center; gap: 10px;
  background: rgba(0,0,0,.55); color: var(--hvid); border: 1.5px solid var(--guld);
  border-radius: var(--pille); padding: 10px 18px; cursor: pointer;
  font: 500 .92rem 'Bitter', serif;
}
.hero-play.vis { display: inline-flex; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .btn { transition: none; }
  .btn:active { transform: none; }
}

/* ═══════════════════════════════════════════════════════════════════════
   ПАНЕЛЬ ВЛАДЕЛЬЦА — каркас четырёх вкладок (наряд П1, чертёж панели §1, §5, §7)

   Одна разметка навигации — два вида: на телефоне полоса внизу, на
   десктопе (≥1024) колонка слева. Так каждое действие телефона есть и на
   десктопе (паритет платформ, вердикт 23.08) — второй разметки нет и
   разъехаться нечему.

   Все правила зоны живут под `body.panel`: страница записи, пульт мастера,
   табло и киоск этих классов не видят, их вёрстка не тронута.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Оболочка панели: контент · навигация · резервный угол облачка ─────
   Наряд П6 требует НОЛЬ перекрытий интерактивных целей на всём пути
   прокрутки. Пока прокручивалось окно целиком, требование было
   невыполнимо в принципе: любой прибитый к экрану предмет (парящая
   кнопка агента, полоса навигации) пропускает контент под собой, и на
   каком-то шаге под ним оказывается чужая кнопка. Резерв отступов лечил
   только КОНЕЦ прокрутки — петли П1–П3 ловили это трижды.

   Поэтому прокрутка переехала внутрь колонки контента: оболочка ростом
   ровно в экран, навигация — её собственная строка, над ней .panel-krop
   со своей прокруткой. Контент не пересекает полосу НИКОГДА — это
   свойство раскладки. Так же устроено любое приложение с нижней панелью.

   П6-БИС. Полоса-шапка агента снята (решение Алекса: вход — одно живое
   облачко, без дублирующей строки). Где стоит облачко — решено по кадрам
   цены 26.08, ГИБРИД:

   · ТЕЛЕФОН (<1024): облачко — ПЯТАЯ ЯЧЕЙКА нижней полосы навигации.
     Колонка контента не платит ничего (--sky-rede = 0), потому что над
     контентом ничего не висит. Резерв в колонке стоил бы пятую часть
     ширины экрана: замер 390 → контент 294 против 374 px (−21 %), 320 →
     224 против 304 (−26 %), и страница на треть выше от переносов.
     Ячейка в полосе стоит ~2 % высоты — и ноль ширины.
   · ДЕСКТОП (≥1024): облачко ЛЕТАЕТ в правом нижнем углу колонки, под
     ним выгорожена зона --sky-rede. Там резерв БЕСПЛАТЕН: колонка
     центрована, и он съедает уже существующий воздух по бокам (замер
     1280: контент 624 px и с резервом, и без).
     Почему такой резерв держит, а прежний нижний — нет: полоса СПРАВА
     вертикальна, а вертикальная полоса инвариантна к вертикальной
     прокрутке. Нижний отступ гарантировал чистоту одного положения из
     сотен; правая полоса — всех сразу.
     Резерв стоит на .panel-krop, а не на .wrap: так он ложится ровно
     туда, где висит облачко, и на широком экране растворяется в воздухе
     центрованной колонки.

   Числа обеих геометрий живут ОДНИМ набором в zhivchik.css, рядом с
   размером самого облачка — иначе место и предмет разъедутся молча.

   `100dvh`, а не `100vh`: на iPhone панель браузера съедает нижние
   ~60 px, и полоса навигации ушла бы под неё (урок цеха о svh/dvh). */
/* Страница-приложение: прокрутки у документа нет вовсе. Без этой строки
   базовое `min-height: 100vh` тела оставляло бы окну лишнюю полоску высотой
   в свёрнутую панель браузера — и документ всё-таки ездил бы. */
body.panel { height: 100dvh; min-height: 0; overflow: hidden; }
/* ТЕЛЕФОН. Второй столбец сетки — ячейка облачка в нижней строке; вверху
   колонка контента идёт через оба столбца во всю ширину. Координаты есть
   у КАЖДОГО ребёнка: автоподстановка сетки, увидев занятую ячейку, завела
   бы лишний столбец и разрезала экран пополам (поймано первым же кадром).
   Полоса навигации тянется через оба столбца — её фон и верхняя линия
   красят весь низ, а пятая колонка внутри неё держит место облачку. Так
   ширину ячейки объявляет ОДНО число, а вид полосы живёт в одном месте. */
.panel-skal {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--sky-celle);
  grid-template-rows: minmax(0, 1fr) auto;
  height: 100dvh;
}
.panel-krop {
  grid-column: 1 / -1; grid-row: 1; min-height: 0;
  overflow-y: auto; overscroll-behavior-y: contain;
  padding-right: var(--sky-rede);
}
.panel-nav { grid-column: 1 / -1; grid-row: 2; }

/* Облачко — своя ячейка нижней строки, по центру её. Место ему даёт
   сетка: ни fixed, ни absolute, ни z-index (в разметке оно идёт
   последним — чтобы порядок Tab шёл за глазом). */
.sky-knap {
  grid-column: 2; grid-row: 2; justify-self: center; align-self: center;
  /* Полоса отбивает низ под домашнюю черту iPhone — облачко обязано
     отбить столько же, иначе оно сядет ниже четырёх вкладок. */
  margin-bottom: env(safe-area-inset-bottom, 0px);
}

/* ── Навигация: четыре вкладки ─────────────────────────────────────────
   Активная вкладка — ЗОЛОТОМ и точкой-индикатором. Вертикальные черты
   сбоку (side-tab) запрещены чертежом §7 — точка занимает 5 px и не
   спорит с золотой чертой эйброва.
   Прибивать полосу к низу экрана больше не нужно: она сама нижняя строка
   оболочки, и уехать ей некуда. */
.panel-nav {
  display: grid;
  /* Пятая колонка — место облачка (П6-бис, решение 26.08). Пустая: сам
     объект лежит в ячейке ОБОЛОЧКИ той же ширины, а не внутри <nav> —
     агент не пункт меню, и в разметке навигации ему делать нечего. */
  grid-template-columns: repeat(4, 1fr) var(--sky-celle);
  background: var(--sort); border-top: 1.5px solid var(--kant);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.fane-knap {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; min-height: 56px; padding: 8px 4px;      /* тап-цель ≥44 px с запасом */
  color: var(--daempet); text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.fane-navn {
  font: 500 .75rem 'Oswald', 'Arial Narrow', sans-serif;
  letter-spacing: 1.2px; text-transform: uppercase;
}
.fane-prik { width: 5px; height: 5px; border-radius: 50%; background: transparent; }
.fane-knap[aria-current="page"] { color: var(--guld); }
.fane-knap[aria-current="page"] .fane-navn { font-weight: 600; }
.fane-knap[aria-current="page"] .fane-prik { background: var(--guld); }
.fane-knap:hover { color: var(--hvid); }
.fane-knap:focus-visible { outline: 3px solid var(--rav); outline-offset: -3px; }

/* Резервы низа под полосу навигации и под парящую кнопку агента (76 →
   152 px) СНЯТЫ вместе с самой кнопкой: резервировать пустоту больше не
   от чего — ни один прибитый предмет над контентом не висит. Контенту
   остаётся его собственный нижний отступ из .wrap. */

/* Вкладка: показана ровно одна, остальные сняты со страницы целиком */
.fane[hidden] { display: none; }

/* Марка салона (Н-6): на телефоне имя стоит героем в шапке контента, на
   десктопе — сверху сайдбара, как в эталоне A-Desktop («HOS MAJED /
   Styrepanel»). Двух имён на одном экране не бывает: на десктопе шапка
   контента прячется — см. медиазапрос ниже. */
.panel-maerke { display: none; }

/* ── Mere: сворачиваемые секции (лечение «простыни», вердикт 22.08) ─────
   Родной <details>: клавиатура, читалки и состояние достаются даром,
   JS остаётся только запомнить открытые в localStorage. */
.mere-blok {
  background: var(--mokka); border: 1.5px solid var(--kant);
  border-radius: var(--radius); margin: 8px 0;       /* радиус 12 px из theme.css */
}
.mere-hoved {
  display: flex; align-items: center; gap: 12px;
  min-height: 56px; padding: 8px 16px; cursor: pointer;
  list-style: none;                                   /* свой шеврон вместо треугольника */
}
.mere-hoved::-webkit-details-marker { display: none; }
.mere-hoved:hover { color: var(--guld); }
.mere-hoved:focus-visible { outline: 3px solid var(--rav); outline-offset: -3px; }
/* 1.25rem — уже существующая ступень шкалы (как у h3 в отчётах): новой
   ступени между 16 и 20 px не заводим, иначе иерархия расплывается. */
.mere-titel { flex: 1; margin: 0; font-size: 1.25rem; }
.mere-pil { flex: none; color: var(--guld); transition: transform .18s ease; }
.mere-blok[open] > .mere-hoved .mere-pil { transform: rotate(90deg); }
/* Боковой отступ 12, а не 16: рамка секции и так съедает ширину у рядов
   услуг на 320–390 — лишние 8 px возвращаем содержимому. */
.mere-krop { padding: 12px 12px 16px; border-top: 1px solid var(--creme-25); }
/* 320 — самый узкий из канонных экранов, и там строке-ресурсу нужен каждый
   пиксель: два поля пальца по 44 съедают 88 из 261. Боковой отступ уходит
   на следующую ступень шкалы вниз (12 → 8) только на этой ширине. */
@media (max-width: 360px) { .mere-krop { padding: 12px 8px 16px; } }

/* ═══ СТРОКИ-РЕСУРСЫ: плотные списки настроек ════════════════════════════
   Наряд П9 по вердикту Алекса 26.08 («в топку, переделывать»).

   ЧТО ЛЕЧИМ. Список услуг стоял стопкой форм: у каждой услуги два вечно
   открытых поля по 44 px, часто в два яруса, и две кнопки-СЛОВА «Fra» и
   «Slet». Замер до правки (кадры `_shots/p9m-do-*`): на 320 в экран
   влезали ДВЕ услуги, на 390 — четыре. Владелец правит прайс пальцем на
   телефоне — а получал анкету.

   ПРИЁМ — три правила журнала вкуса 26.08:
   · строка-ресурс: имя и значения ТЕКСТОМ, поля появляются по тапу;
   · действия в строке — ИКОНКАМИ (галка · урна), не словами-кнопками;
   · плотность меряется строками на экран, а не «на глазок».

   ПОЧЕМУ ИМЯ И «279 kr · 25 min» СТОЯТ ДВУМЯ ЯРУСАМИ, А НЕ ОДНОЙ СТРОКОЙ.
   Одной строкой на 390 имени остаётся ~135 px, и «Herreklip & skæg inkl.
   voks af (øre/næse)» обрезается многоточием до «Herreklip & skæg …» —
   ровно до имени ДРУГОЙ услуги салона, которая стоит других денег. В
   списке настроек это потеря смысла, а не экономия места. Два яруса —
   тот же узор, что в списках настроек телефона: заголовок, подзаголовок,
   управление справа. Ярусы фиксированы (не «переносится, если не влезло»),
   чтобы цифры цен стояли по одной линии сверху вниз.

   ГЕОМЕТРИЯ ПАЛЬЦА (канон §2 в чтении журнала 26.08): 44 px — это ЗОНА
   тапа, а не размер видимой картинки. Иконка рисуется 22 px, зона вокруг
   неё — 44×44. Прежняя ошибка была обратной: под 44 гнали саму кнопку,
   и в строке вырастали лопаты со словами. ═════════════════════════════ */

/* Заголовок сегмента прайса (чертёж §5 «услуги по сегментам»): тихий
   разделитель, а не кнопка — сворачивать 16 услуг незачем, они и так
   умещаются в полтора экрана. */
.res-gruppe + .res-gruppe { margin-top: 16px; }
.res-gruppe-navn {
  margin: 0 0 4px; padding: 0 4px;
  font: 600 1rem 'Oswald', 'Arial Narrow', sans-serif;
  letter-spacing: .08em; text-transform: uppercase; color: var(--daempet);
}

/* Строка. Разделитель — волосок: единственное, что держит форму списка
   (своей заливки и своих полей у строки нет — отсюда и плотность), значит
   норма к нему ≥3 : 1 как к элементу интерфейса. Замер композитом на
   --mokka: --creme-25 даёт 2,01 (мало), --kant ровно 3,00 (сидит НА
   черте), --porc-45 даёт 4,52 — берём его, новый цвет заводить не
   пришлось, токен уже жил в theme.css. */
.res-raekke { display: flex; align-items: center; gap: 4px;
  border-bottom: 1px solid var(--porc-45); }
.res-liste > .res-gruppe > .res-raekke:last-child,
.res-liste > .res-raekke:last-child { border-bottom: 0; }

/* Плоскость строки — цель пальца, открывающая редактор. Именно <button>:
   клавиатура, читалка и роль достаются даром, изображать их не нужно. */
.res-flade {
  flex: 1; min-width: 0; display: flex; flex-direction: column;
  justify-content: center; gap: 2px;
  min-height: 44px; padding: 4px;
  background: none; border: 0; color: inherit; text-align: left;
  font: inherit; cursor: pointer; border-radius: 8px;
}
.res-flade:hover .res-navn { color: var(--guld); }
.res-flade:focus-visible { outline: 3px solid var(--rav); outline-offset: -3px; }
.res-navn { font: 600 1rem 'Bitter', Georgia, serif; line-height: 1.25;
  color: var(--hvid); overflow-wrap: anywhere; }
/* Строка с фото (мастера): аватар слева, два яруса текста справа.
   justify-content переопределяем явно: у колонки `center` центрует по
   вертикали, а у строки — по ГОРИЗОНТАЛИ, и аватар уезжал к середине. */
.res-flade-foto { flex-direction: row; align-items: center;
  justify-content: flex-start; gap: 10px; }
.res-tekst { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.res-avatar { width: 40px; height: 40px; }
/* Цифры — Oswald, как все числа панели. 1rem держит канон §2 «≥16 всегда»
   (у старого .row .meta было .8rem — долг прежних кругов, не наш). */
/* Ярус значений — флекс с переносом: на 320 приписка состояния не влезает
   в строку с ценой, и без этого она рвалась пополам («slået» / «fra»).
   Теперь переносится ЦЕЛИКОМ, а разделителем между цифрами и состоянием
   работает зазор, а не висящая на конце строки точка. */
.res-vaerdi { display: flex; flex-wrap: wrap; column-gap: 6px;
  font: 500 1rem 'Oswald', 'Arial Narrow', sans-serif;
  line-height: 1.25; letter-spacing: .04em; color: var(--daempet); }
.res-stand { white-space: nowrap; }

/* Кнопка-иконка: видимая картинка 22, зона пальца 44×44. */
.res-ikon {
  flex: none; width: 44px; min-height: 44px; align-self: stretch;
  display: flex; align-items: center; justify-content: center;
  padding: 0; background: none; border: 0; border-radius: 10px;
  color: var(--daempet); cursor: pointer;
}
.res-ikon:focus-visible { outline: 3px solid var(--rav); outline-offset: -3px; }
.res-slet:hover { color: var(--roed-lys); }      /* 5,90 : 1 на --mokka */
.res-gendan:hover { color: var(--guld); }

/* Галка-активность. Включено = ЗАЛИВКА золотом (7,87 : 1), выключено =
   ПУСТОЙ контур. Носитель состояния — форма (полно/пусто), цвет только
   помогает: дальтонику и на чёрно-белом кадре разница видна та же. */
.res-flag-ramme {
  width: 24px; height: 24px; border-radius: 8px;
  border: 2px solid var(--daempet);
  display: flex; align-items: center; justify-content: center;
}
.res-flag[aria-pressed="true"] .res-flag-ramme {
  background: var(--guld); border-color: var(--guld); color: var(--sort);
}
.res-flag:hover .res-flag-ramme { border-color: var(--guld); }

/* ВЫКЛЮЧЕННАЯ СТРОКА — приём «выключенного» из П3: ноль прозрачности.
   Три носителя сразу, ни один из них не opacity:
   1) галка пустая (форма), 2) текст уходит на --daempet — 8,40 : 1, то
   есть ЧИТАЕТСЯ ПОЛНОСТЬЮ, 3) в ярусе значений стоит слово состояния
   «slået fra». Слово тут законно: журнал 26.08 запретил кнопки-слова в
   строке, а не подпись состояния (прецедент П5). */
.res-raekke.slukket .res-navn { color: var(--daempet); }

/* «+ Tilføj» — такая же строка списка, а не кнопка-плита во всю ширину. */
.res-tilfoej {
  display: flex; align-items: center; gap: 8px;
  width: 100%; min-height: 44px; padding: 8px 4px;
  background: none; border: 0; border-radius: 8px;
  color: var(--guld); font: 600 1rem 'Bitter', Georgia, serif;
  text-align: left; cursor: pointer;
}
.res-tilfoej:hover { color: var(--guld-hover); }
.res-tilfoej:focus-visible { outline: 3px solid var(--rav); outline-offset: -3px; }
.res-tilfoej svg { flex: none; }

/* ── Редактор одной строки: раскрывается ПОД ней, список остаётся на
   месте. Открыт всегда максимум один (JS закрывает прежний). Модалку не
   берём: она закрыла бы собой соседние цены, а владелец правит прайс,
   глядя на соседние цены. ─────────────────────────────────────────── */
.res-red {
  padding: 12px 4px 14px; border-bottom: 1px solid var(--porc-45);
  background: var(--mokka-2); border-radius: 10px; margin: 0 0 1px;
}
/* ОДНА СТРОКА РЕДАКТОРА (вердикт Алекса 26.08-2): поля значений и дискета
   стоят в линию, отдельного ряда кнопок нет.

   Куда делись подписи «Pris» и «Varighed». Ярус подписей над полями — это
   ровно та строка, которую велено не съедать; на 320 внутри редактора
   всего 253 px, и подпись+поле+единица втроём в линию не садятся. Работу
   подписи делает ЕДИНИЦА рядом с полем («kr», «min»), а читалке имя поля
   даёт aria-label — оно не зависит от того, влезла подпись или нет.

   Стрелки-крутилку у числового поля снимаем: она съедала ~20 px ширины
   ради жеста, которым на телефоне никто не пользуется. Ввод остаётся
   числовым (type=number + inputmode=numeric), проверка границ — на
   сервере, ничего не потеряно. */
.res-red-linje { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.res-red-bred { width: 100%; }
.res-red-felt-flex { flex: 1 1 96px; min-width: 0; }
.res-red-gem { display: flex; justify-content: flex-end; margin-top: 8px; }
.res-enhed { font: 500 1rem 'Oswald', 'Arial Narrow', sans-serif; color: var(--daempet); }
/* 1rem, а не .95rem общего .inline: канон §2 требует ≥16 px и В ПОЛЯХ
   форм тоже. Правим только СВОИ поля — общий .inline держит ещё Kalender,
   и его долг чинится не отсюда. */
/* ⚠ КАСКАД. Общий `input.inline` живёт в <style> самой admin.html, то есть
   ПОСЛЕ этого файла и с тем же весом — «.res-tal» ему проигрывал молча, и
   поля оставались 90 px вместо 60 (поймано замером ширин, не глазом).
   Поэтому все правила полей редактора идут от `.res-red` — вес выше, и
   спор с каскадом решён один раз для всех, а не заплатой на каждое поле.

   ── ПОЛЕ СИДИТ ПО СОДЕРЖИМОМУ (вердикт Алекса 26.08-3) ────────────────
   «Почему окно-поле для цифр почти наполовину пустое? Цифра жмётся в
   верхний левый угол… Либо размер поля подгоняй к цифре, либо цифру
   подгоняй к полю».

   Что показал прибор (чтением ПИКСЕЛЕЙ кадра, не арифметикой CSS):
   · по ВЕРТИКАЛИ содержимое стояло по центру и до правки — 11/13 px,
     разница 2 px это несимметричные ascender/descender у Bitter. Не
     чиню то, чего нет: вертикаль подтверждена замером, а не обещанием;
   · по ГОРИЗОНТАЛИ был перекос влево у всех полей: цена 5/18, минуты
     5/28, время 7/36, имя 13/61. Пустой правый угол — та самая недоделка.

   Лечение: ширина числового поля считается от ЧИСЛА ЗНАКОВ (1ch =
   ширина «0» текущего шрифта), содержимое центруется. Цена — 4 знака
   (максимум прайса 5000), минуты — 3 (максимум 240). Тап-цель держит
   min-height 44, а не раздувание рамки.

   1rem, а не .95rem у .inline: канон §2 требует ≥16 px и В ПОЛЯХ форм.
   Общий .inline не трогаю — на нём висит ещё Kalender. */
.res-red input, .res-red select { font-size: 1rem; min-height: 44px; padding: 8px 10px; }
/* Отдельной строкой — ровно чтобы перебить `input.inline` из admin.html:
   он идёт позже и весит столько же, сколько `.res-red input`, поэтому
   общее правило выше ему проигрывало и кегль полей падал до 15,2 px
   (поймано прибором кеглей после правки, не глазом — канон §2 требует
   ≥16 и в полях форм). Здесь вес (0,2,1) против (0,1,1) у .inline. */
.res-red input.inline { font-size: 1rem; padding: 8px 10px; }
/* ── ЦИФРА ГЛАВНАЯ НА СТРОКЕ, РАМКА СИДИТ ПО НЕЙ (вердикт 26.08-3, второй
   заход: «цифра намного меньше своей ячейки»). Правило журнала «тап-цель
   ≥44 — ЗОНОЙ вокруг, не раздуванием рамки» применяется здесь буквально:
   видимая рамка 34 px по цифре, а 44 держит прозрачная обёртка-label
   (.res-tal-boks) — тап по ней фокусирует поле нативно, без JS.

   Замер эталона (поле времени, принято Алексом) дал неожиданное: по
   ВЕРТИКАЛИ пропорция у времени ровно такая же, 0,273 — цифра 12 px в
   рамке 44 у всех трёх полей. Разница, которую видно глазом, была
   ГОРИЗОНТАЛЬНОЙ: «09:00» занимает 44 px из 70 (63 %), а «400» — 30 из
   67 (45 %). Поэтому вертикаль чиню по СМЫСЛУ вердикта (цифре тесно —
   значит рамку ужать и кегль поднять), а не по букве «привести к
   эталону»: приводить к пропорции, которая сама и есть жалоба, нельзя.
   Горизонталь привожу к эталонному воздуху. Числа — в отчёте.

   Кегль 1.25rem — существующая ступень шкалы (как у .mere-titel), новой
   ступени между 16 и 20 не завожу. */
.res-tal-boks {
  display: inline-flex; align-items: center; justify-content: center;
  flex: none; min-height: 44px; cursor: text;
}
.res-red input.res-tal {
  flex: none; text-align: center;
  /* Высота 32, а не 34: критерий вердикта «воздух по оси ≤ половины
     высоты цифры» проверяется числом, и при 34 выходило 8 против 7,5 —
     мимо. При 32 воздух 7 при половине 7,5. Ширина: запас 12 px даёт
     горизонтальный воздух 12 — ровно как у принятого поля времени. */
  font-size: 1.25rem; height: 32px; min-height: 0; padding: 0 6px;
  /* Ширина = место под N цифр + ЕГО ЖЕ padding и рамка. Первый заход
     сюда padding с рамкой не заложил, и максимум прайса «5000» не влезал:
     место под текст 45,1 px при тексте 49,1 (замер чтением пикселей).
     Поймалось только проверкой КРАЙНИХ значений — на «400» всё выглядело
     хорошо. 15 = padding 12 + рамка 3. Табличные цифры тут не помогли:
     Bitter их не даёт, и 1ch остаётся шириной «0» — зато «0» у него шире
     реальной цифры, так что 4ch с запасом покрывают и «5000», и «888». */
  width: calc(var(--tegn) * 1ch + 15px);
  -moz-appearance: textfield; appearance: textfield;
}
.res-tal-4 { --tegn: 4; }                      /* цена: до «5000» */
.res-tal-3 { --tegn: 3; }                      /* минуты: до «240» */

/* ИМЯ УСЛУГИ — то же поле, только растяжимое (долг приёмки П9).
   Язык полей редактора один: высота 32, кегль 1.25rem, содержимое по
   центру ВЕРТИКАЛИ, зона пальца 44 обёрткой-label. По горизонтали имя
   стоит слева — оно рамку заполняет само, и центрировать его значило бы
   двигать начало строки при каждой букве. Правило 26.08-3 держится
   смыслом: пустого угла в поле нет.
   ── ПОЧЕМУ БАЗА 180, А НЕ «СКОЛЬКО ВЛЕЗЕТ» (замер, не глазомер) ───────
   Остальная часть строки занимает 229 px и не сжимается: цена 66 + «kr» 13
   + минуты 53 + «min» 23 + дискета 44 + пять зазоров по 6.
   Первый заход дал базу 128 — и строка ЛОМАЛАСЬ УРОДЛИВО: на 390 имя,
   цена и минуты оставались наверху, а дискета уезжала одна на вторую
   строку (кадр p7b-390-red-navn первого прогона). Ровно та лишняя строка,
   против которой вердикт 26.08-2 и был.
   База 180 = минимум, на котором имя ещё читается (≈12 знаков кеглем 20).
   Ниже 409 px ширины строки флекс переносит имя целиком на свою строку, и
   раскладка становится той же, что у НОВОЙ услуги, — уже принятой. Итог по
   замеру: 320/360/390 — два ряда, 94 px; 430 и шире — один ряд, 44 px. */
.res-navn-boks { flex: 1 1 180px; min-width: 0; }
/* Группа «цена · kr · минуты · min · дискета»: переносится ЦЕЛИКОМ.
   `flex: 1 1 auto` — чтобы дискета своим margin-left:auto уходила к
   правому краю и в один ряд, и на своей строке. */
.res-tal-gruppe { display: flex; align-items: center; gap: 6px; flex: 1 1 auto; }
.res-red input.res-navn {
  flex: 1 1 auto; width: 100%; min-width: 0; text-align: left;
  font-size: 1.25rem; height: 32px; min-height: 0; padding: 0 6px;
}
.res-red input.res-tal::-webkit-outer-spin-button,
.res-red input.res-tal::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
/* ВРЕМЯ. Поле резало цифры: `input.inline` давало 90 px, а собственная
   ширина поля (цифры + иконка-индикатор) — 94–97 px, и последняя цифра
   уезжала под иконку («09:0(» на кадре p9m3-do-390-zoom-timer.png).
   Прибор `scrollWidth > clientWidth` тут СЛЕП: у type=time содержимое
   живёт в закрытом shadow-DOM и наружу размер не отдаёт — обрезка ловится
   сравнением заданной ширины с естественной (width:auto). Лечится не
   подгонкой числа, а тем, что ширину назначает содержимое. */
/* Пропорция поля времени подтянута к цене (решение по возражению
   строителя, 26.08-3). Замер вскрыл, что «время пропорционально» было
   сравнением со СТАРОЙ ценой: у обоих полей цифра занимала 0,273 высоты
   рамки. После того как цена села по цифре, время осталось бы
   единственным рыхлым полем панели — язык полей обязан быть один.
   Те же три числа, что у цены: кегль 20, рамка 32, зона 44 обёрткой. */
.res-red input.res-tid {
  width: auto; flex: none; text-align: center;
  font-size: 1.25rem; height: 32px; min-height: 0; padding: 0 6px;
}
/* Иконка-пикер Chrome внутри поля времени СНЯТА. Замер: с ней естественная
   ширина поля 94 px, без неё 64 — то есть ровно она занимала правые 30 px
   и делала поле «наполовину пустым» на вид (прибор по пикселям её не
   ловит: UA рисует её полупрозрачной, и по яркости она сливается с
   заливкой — правый угол читался как пустой и глазом, и прибором).
   Со снятой иконкой ширину назначает содержимое, цифры встают по центру,
   а строка дня на 320 перестаёт переноситься — 60 px экономии на двух
   полях. Ввод не потерян: на телефоне тап по полю открывает нативный
   выбор времени, с клавиатуры поле правится посегментно и стрелками.
   Размен назван в отчёте: мышью на десктопе пикер больше не вызвать. */
.res-red input.res-tid::-webkit-calendar-picker-indicator { display: none; }
.res-red input.res-red-felt-flex, .res-red select.res-red-felt-flex { width: auto; }
/* Дискета — сохранить. Золото: это единственное действие редактора, и
   оно обязано читаться акцентом, а не сливаться с урной соседней строки. */
.res-gem { color: var(--guld); margin-left: auto; }
.res-gem:hover { color: var(--guld-hover); }

.res-timer { margin-top: 12px; }
.res-timer > .res-enhed { display: block; margin: 0 0 4px; }

/* Часы мастера внутри редактора: семь строк дня, каждая — цель пальца.
   Оба поля времени лежат в одной группе .res-dag-tider — на узком экране
   переносится ГРУППА, и «09:00 – 17:30» не разрывается пополам. */
.res-dag { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  min-height: 44px; }
.res-dag-navn { width: 38px; flex: none;
  font: 500 1rem 'Oswald', 'Arial Narrow', sans-serif; color: var(--daempet); }
/* 320: подросший кегль времени (16 → 20) забрал ту ширину, которую вернуло
   снятие иконки-пикера, и строка дня опять поехала на две линии — редактор
   мастера вырастал с 523 до 865 px. Возвращаем её в одну линию, забирая по
   мелочи там, где это ничего не стоит: имя дня по факту текста («man» в
   Oswald 16 px = 28), зазоры на ступень вниз по шкале. Замер по месту. */
@media (max-width: 360px) {
  .res-dag { gap: 6px; }
  .res-dag-navn { width: 30px; }
  .res-dag-tider { gap: 4px; }
}
/* Прямой потомок: иначе это правило ловило бы и обёртки-зоны полей
   времени внутри .res-dag-tider и красило их шрифтом подписи «fri». */
.res-dag > label { display: flex; align-items: center; gap: 6px; min-height: 44px;
  font: 500 1rem 'Bitter', Georgia, serif; color: var(--daempet); }
/* Системная галка красится браузером в свой синий — мимо палитры чертежа.
   Тот же приём, что у .checkbox-row: accent-color на золото. */
.res-dag input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--guld); }
.res-dag input[type="checkbox"]:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }
.res-dag-tider { display: flex; align-items: center; gap: 6px; flex: 0 1 auto;
  color: var(--daempet); }
/* ⚔ Мёртвое `.res-tid { width: 96px }` убрано: его перебивало
   `.res-red input.res-tid { width: auto }`, и оно только вводило в
   заблуждение при чтении файла. */

/* ── Десктоп ≥1024: та же навигация колонкой слева ──────────────────── */
@media (min-width: 1024px) {
  /* Сайдбар слева во всю высоту, справа — колонка контента с летающим
     облачком в своём нижнем углу. Строки те же, что на телефоне, просто
     повёрнуты: разметка одна, и разъехаться платформам нечему. */
  .panel-skal {
    grid-template-columns: 232px minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
  }
  /* Н-11: в разметке навигация идёт ПОСЛЕ содержимого — иначе Tab начинал
     обход с подвала. Место на десктопе держат координаты сетки, а не
     порядок узлов. */
  .panel-nav { grid-column: 1; grid-row: 1; }
  .panel-krop { grid-column: 2; grid-row: 1; min-width: 0; }
  /* Здесь облачко ЛЕТАЕТ: лежит в одной ячейке с колонкой контента,
     прижатое к её правому нижнему углу, над прокруткой. Пятой ячейки
     навигации на десктопе нет — сайдбар вертикальный, и место в углу
     стоит ноль (см. разбор цены в шапке зоны). */
  .sky-knap {
    grid-column: 2; grid-row: 1; justify-self: end; align-self: end;
    margin: var(--sky-luft); z-index: 2;
  }
  /* Правый край контента отбит резервом — своей правой стенки .wrap здесь
     не держит, иначе воздух справа стал бы вдвое шире левого. */
  body.panel .panel-krop > .wrap {
    --wrap-max: 640px;              /* по умолчанию; вкладки его переопределяют */
    max-width: var(--wrap-max);
    padding-right: 0;

    /* ЦЕНТРОВКА В ПОЛНОЙ ШИРИНЕ КОЛОНКИ, А НЕ В УРЕЗАННОЙ РЕЗЕРВОМ.
       Резерв под облачком отнимает 104 px справа, и `margin: 0 auto`
       центровал рамку внутри ОСТАТКА — то есть сдвигал её влево на
       половину резерва. На 1920 это читалось прямо: слева 200, справа
       304, и Marketing жался к сайдбару при пустой четверти справа.

       Считаем так: --luft это воздух, который и так есть по бокам рамки
       (ноль, если рамка упёрлась в края). Рамку сдвигаем вправо на
       половину резерва — но не больше, чем этого воздуха есть:

         сдвиг = min(резерв / 2, воздух)

       Что получается: пока места в обрез (1280, 1440 — рамка упирается),
       сдвиг ноль и всё как было; появился воздух — рамка встаёт по центру
       ПОЛНОЙ колонки, а облачко остаётся висеть в наружном воздухе.
       Резерв при этом НЕ снят: `padding-right` колонки на месте, и
       сдвинуться в зону рамка не может — воздух справа от неё всегда
       остаётся не меньше резерва. Числа замерены на 1280/1440/1600/1920. */
    --luft: max(0px, calc((100% - var(--wrap-max)) / 2));
    margin-left: calc(var(--luft) + min(var(--sky-rede) / 2, var(--luft)));
    margin-right: auto;
  }
  .panel-nav {
    grid-template-columns: 1fr; align-content: start; gap: 6px;
    background: var(--mokka); border-top: 0; border-right: 1.5px solid var(--kant);
    padding: 22px 16px;
  }
  .fane-knap {
    flex-direction: row; justify-content: flex-start; gap: 12px;
    min-height: 48px; padding: 10px 14px; border-radius: var(--radius);
  }
  .fane-navn { font: 500 .95rem 'Bitter', Georgia, serif; letter-spacing: .3px; text-transform: none; }
  .fane-knap[aria-current="page"] { background: var(--mokka-2); }
  .fane-knap[aria-current="page"] .fane-navn { font-weight: 600; }
  .fane-prik { margin-left: auto; }
  .panel-maerke { display: block; padding: 0 14px 20px; }
  .maerke-navn {
    display: block; font: 600 1.4rem 'Oswald', 'Arial Narrow', sans-serif;
    text-transform: uppercase; letter-spacing: .06em; line-height: 1; color: var(--hvid);
  }
  .maerke-sub { display: block; margin-top: 6px;
    font: 400 .85rem 'Bitter', Georgia, serif; color: var(--daempet); }
  /* Имя салона уже стоит в сайдбаре — в шапке контента оно было бы вторым
     на одном экране (Н-6: родовое «KONTROLPANEL» с экрана уходит совсем).
     Прячем ГЛАЗУ, но не читалке: display:none снёс бы единственный H1
     страницы из дерева доступности, а марка сайдбара — не заголовок. */
  body.panel .panel-krop > .wrap > .top {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
  }
  /* Со смертью полосы-шапки (П6-бис) верх колонки остался без воздуха: имя
     салона на десктопе спрятано, и первым видимым шёл заголовок дня —
     впритык к краю экрана, будто обрезанный. Отступ ставим только здесь:
     на телефоне воздух даёт своим полем сам заголовок «HOS MAJED». */
  body.panel .panel-krop > .wrap { padding-top: 24px; }
  /* Н-9 (перекрытие карточки денег парящей кнопкой) закрыт конструкцией:
     кнопки нет, над контентом ничего не висит, резерв не нужен. */
}

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

/* ═══════════════════════════════════════════════════════════════════════
   KALENDER — «что происходит сейчас» (наряд П2, чертёж панели §2)

   Порядок сверху вниз — из чертежа §2: шапка → строка-исключение → сетка
   дня → быстрые действия → деньги дня. Скелет сетки и карточки денег —
   утверждённый мокап A (maket-dashboard/A-Telefon, A-Desktop).

   ⚔ Почему сетка дня — HTML, а не SVG (чертёж §7 просит голый SVG для
   ГРАФИКОВ, и почасовые столбцы денег ниже действительно SVG). Сетка дня —
   не график, а раскладка: каждый её кусок это ЦЕЛЬ ПАЛЬЦА (бронь, окно,
   пересечение), а значит нужны ≥44 px, видимый фокус, перенос строк и
   родная клавиатура. В SVG всё это пришлось бы изображать вручную. Форма
   при этом мокапная: колонки по мастерам, часовые линии, красная черта
   «сейчас», пунктирные окна, красная капсула пересечения.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Шапка дня: дата + статус слева, «Spørg» справа ────────────────────── */
.dag-top {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; padding: 4px 0 12px;
}
.dag-dato { display: flex; flex-direction: column; gap: 6px; }
.dag-dato .sub { color: var(--daempet); font-size: .9rem; }
.dag-titel {
  font: 600 clamp(1.5rem, 1.1rem + 2vw, 2rem) 'Oswald', 'Arial Narrow', sans-serif;
  text-transform: uppercase; line-height: .9; letter-spacing: .5px; margin: 0;
}
/* Статус — подпись, не кнопка: пилюль-обманок на экране быть не должно. */
.dag-status {
  display: inline-flex; align-items: center; gap: 8px;
  font: 500 .9rem 'Bitter', Georgia, serif; color: var(--daempet);
}
.dag-status::before {
  content: ''; width: 8px; height: 8px; border-radius: 50%;
  background: var(--daempet); flex: none;
}
.dag-status[data-status="aaben"] { color: var(--hvid); }
.dag-status[data-status="aaben"]::before { background: var(--groen); }

/* ── Строка-исключение: одна карточка «требует действия» (§2 п.2) ───────
   Нет исключений — нет и строки: пустых рамок с «всё хорошо» не рисуем. */
.undtagelse {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; width: 100%;
  min-height: 56px; margin: 0 0 12px; padding: 12px 14px;
  background: var(--mokka); border: 1.5px solid var(--roed);
  border-radius: var(--radius); color: var(--hvid);
  font: 400 1rem 'Bitter', Georgia, serif;
}
.undtagelse-ikon { flex: none; color: var(--roed-lys); }
/* Текст занимает строку целиком, кнопки уходят ниже — на 320 иначе от
   имени клиента остаются две буквы (тот же замер, что в форме П1). */
.undtagelse-tekst { flex: 1 1 60%; min-width: 0; }
.undtagelse-hoved { font-weight: 600; }
.undtagelse-detalje { color: var(--daempet); font-size: .85rem; }
/* Действие своего типа — прямо в строке (§2 п.2: «тап — сразу действие»),
   а не за модалкой-переспросом. */
.undtagelse-knapper { display: flex; gap: 8px; flex: none; margin-left: auto; }
/* Общий .btn.mini даёт 33 px высоты — для строки, по которой тычут пальцем
   в спешке, это ниже канона (≥44). Поднимаем ТОЛЬКО здесь и в шапке дня:
   переделывать .mini во всей панели — работа другого наряда. */
.undtagelse .btn, .dag-top .btn { min-height: 44px; }

/* ── Сетка дня ─────────────────────────────────────────────────────────
   --pxmin: сколько пикселей стоит минута. 3 — не «на глазок»: канон требует
   тап-цель ≥44 px, самая короткая продаваемая услуга салона 15 минут,
   44 ÷ 15 = 2,93 → 3. При этом час = 180 px, а рабочий день целиком не
   влезает в экран — поэтому у рамки свой скролл (см. .net-ramme), а не
   бесконечная лента страницы. */
/* ГЕОМЕТРИЯ ДНЯ ЖИВЁТ В МИНУТАХ. У каждого куска дня свои `--m` (минут от
   начала дня) и `--d` (длительность) — их ставит JS, а в пиксели и в ОСЬ
   переводит CSS: на телефоне минуты идут в `top/height`, на ленте десктопа
   в `left/width`. Поэтому раскладку дня целиком меняет медиа-запрос, и
   второй реализации дня в продукте нет (наряд П2-бис п.2).
   `calc(var(--m) * var(--pxmin) * 1px)` повторяется в каждом правиле
   намеренно: подстановка custom property считается на том элементе, где
   она ОБЪЯВЛЕНА, — вынести общий множитель в переменную нельзя, у неё
   `--m` был бы всегда нулевой. */
.dag-net {
  --pxmin: 3; --akse: 44px; --kolbredde: calc(100% / 3);
  --dagmin: 0;        /* длина рабочего дня в минутах — ставит JS */
  --navn: 152px;      /* колонка имён мастеров в ленте десктопа */
  /* Высоту строки ленты задаёт самая высокая карточка — капсула
     пересечения. Считалась она по ПЯТИ строкам (→ 120), а строк с тех пор
     стало шесть: словарь Н-5 добавил «2 uafsluttede», и цена вылезала из
     строки — замер приёмки: «1.426 kr» видна на 51 %.
     Пересчёт по живому стенду, шесть строк: 17 + 25,6 + 15,8 + 17 + 16 +
     19 = 110,4; пять зазоров по 2 = 10; padding 5 + 5 = 10 → 130,4;
     плюс зазоры строки 3 + 3 → 136,4. Округлено вверх до 140.
     Резать состав капсулы вместо этого нельзя: каждая её строка — ответ на
     отдельный вопрос владельца (когда, сколько записей, сколько из них
     ещё горит, сколько денег), и убирать любую значит прятать причину, по
     которой капсула вообще красная. Высота строки — цена честного состава.
     Не опускать ниже расчёта: флекс-колонка давит лишнее МОЛЧА (при 108
     строка «aftaler i én stol» сжималась с 16 px до 3, а scrollHeight не
     рос — прибор переполнения такого не видит). */
  --raekke: 140px;    /* высота строки мастера в ленте десктопа */
  margin: 0 0 16px;
}

/* Чипы-фильтр мастеров: показываются только когда работающих больше трёх
   (чертёж §2 п.3). Выбор — локальная настройка устройства. */
.net-chips { display: flex; gap: 8px; overflow-x: auto; padding: 2px 2px 10px; scrollbar-width: none; }
.net-chips::-webkit-scrollbar { display: none; }

/* ОТВОДЫ робота вкуса (URL-скан, 390×844) — по чек-листу канона §5:
   1) [cramped-padding] «.net-ramme: children flush against border» — у
      сетки-календаря так и должно быть: колонки идут от края до края рамки,
      внутренний отступ сдвинул бы часовую шкалу относительно колонок и
      сломал бы единственное, ради чего сетка нужна, — совпадение времени по
      горизонтали. Отступы живут ВНУТРИ ячеек (.blok, .kol-hoved — 5–8 px).
   2) [text-occlusion] «09:00 / Mikkel закрыты элементом .undtagelse» —
      ложная тревога: рамка прокручена к «сейчас», и эти блоки ОБРЕЗАНЫ
      overflow'ом, а не закрыты карточкой. Замер (390×844): рамка top=303,
      блок Mikkel bottom=238 — он выше видимой области рамки на 65 px,
      робот же сравнивает голые getBoundingClientRect.
   Скан файла (npm run vkus admin.html) — 0 находок.
   3) ОТВОД kontrol.js на десктопе (наряд П2-бис): на 1280 и 1440 робот
      кричит «ВЫЛЕЗАЕТ» на .net-gitter, .dag-kol, .kol-krop, .hul и часовые
      линии. Это лента шириной 1682 px внутри ЭТОЙ рамки с overflow:auto —
      робот сравнивает голый getBoundingClientRect с шириной экрана и
      прокрутку внутри элемента за прокрутку не считает. Проверено иначе:
      documentElement.scrollWidth === clientWidth на 1024/1280/1440, и
      список элементов, вылезающих за экран и НЕ лежащих внутри #net-ramme,
      пуст. Страница вбок не едет. */
.net-ramme {
  position: relative; overflow: auto; overscroll-behavior: contain;
  max-height: min(62vh, 720px);
  background: var(--mokka); border: 1.5px solid var(--creme-25);
  border-radius: var(--radius);
}
/* Н4: fade-подсказка прокрутки (левый и правый края) */
.net-ramme::before,
.net-ramme::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 24px;
  pointer-events: none; opacity: 0; transition: opacity 0.2s ease;
  z-index: 4;
}
.net-ramme::before {
  left: 0; background: linear-gradient(90deg, rgba(31,31,31,0.4) 0%, transparent 100%);
}
.net-ramme::after {
  right: 0; background: linear-gradient(270deg, rgba(31,31,31,0.4) 0%, transparent 100%);
}
.net-ramme.kan-venstre::before,
.net-ramme.kan-hoejre::after {
  opacity: 1;
}
.net-gitter { display: flex; align-items: stretch; min-width: 100%; }

/* Ось времени липнет к левому краю рамки — при свайпе колонок часы
   остаются на месте (иначе владелец возит день вслепую). */
.net-akse {
  position: sticky; left: 0; z-index: 3; flex: none; width: var(--akse);
  background: var(--mokka); border-right: 1px solid var(--creme-25);
}
.akse-hoved { height: 44px; border-bottom: 1px solid var(--creme-25);
  position: sticky; top: 0; background: var(--mokka); z-index: 2; }
.akse-krop { position: relative; height: calc(var(--dagmin) * var(--pxmin) * 1px); }
.akse-time {
  position: absolute; right: 6px; top: calc(var(--m) * var(--pxmin) * 1px);
  transform: translateY(-50%);
  font: 500 .75rem 'Oswald', 'Arial Narrow', sans-serif; color: var(--daempet);
}
/* Часы «сейчас» — тем же красным, что и черта: одно событие, один цвет.
   Текстовый красный берётся светлым токеном (Н-2): --roed на этом фоне
   даёт 4,56, светлый — 6,59; норма канона для текста 4,5. */
.akse-nu {
  position: absolute; right: 4px; top: calc(var(--m) * var(--pxmin) * 1px);
  transform: translateY(-50%);
  font: 600 .75rem 'Oswald', 'Arial Narrow', sans-serif; color: var(--roed-lys);
  background: var(--mokka); padding: 2px 2px 2px 4px; z-index: 2;
}
/* Маркер начала черты (Н-8, скелет A-Desktop): точка живёт на оси времени,
   а ось лежит выше колонок — значит «сейчас» читается и там, где сама черта
   ушла под карточку брони. Одна точка вместо линии поперёк текста. */
.akse-nu::after {
  content: ''; position: absolute; right: -3.5px; top: 50%;
  width: 7px; height: 7px; margin-top: -3.5px; border-radius: 50%;
  background: var(--roed);
}

.net-spor { position: relative; display: flex; flex: 1; min-width: 0; }
.dag-kol { position: relative; z-index: 2;
  flex: 0 0 var(--kolbredde); min-width: 0; border-right: 1px solid var(--creme-25); }
.dag-kol:last-child { border-right: 0; }
.kol-hoved {
  position: sticky; top: 0; z-index: 2; height: 44px; padding: 5px 8px;
  background: var(--mokka); border-bottom: 1px solid var(--creme-25);
  overflow: hidden;
}
.kol-navn {
  font: 600 .78rem 'Oswald', 'Arial Narrow', sans-serif; letter-spacing: .08em;
  text-transform: uppercase; color: var(--hvid);
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* «barber · 10 aftaler» (Н-7): роль превращает «1 aftale» из тревоги в
   норму. Узкой колонке телефона строку обрезаем многоточием, а не переносим:
   у шапки колонки высота фиксирована (44 px), второй строке места нет. */
.kol-antal { display: block; font: 400 .72rem 'Bitter', Georgia, serif; color: var(--daempet);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kol-krop { position: relative; height: calc(var(--dagmin) * var(--pxmin) * 1px); }

/* Часовые линии — фон колонки, не элементы: рисуем повтором градиента?
   Нет: чертёж запрещает градиенты в UI. Линия — отдельный див в оси и
   тонкая рамка сверху у каждого часа внутри колонки. */
.kol-time { position: absolute; left: 0; right: 0;
  top: calc(var(--m) * var(--pxmin) * 1px); border-top: 1px solid var(--creme-25); }

/* Кусок дня вне часов ЭТОГО мастера (пришёл позже / ушёл раньше салона) */
.kol-udenfor { position: absolute; left: 0; right: 0;
  top: calc(var(--m) * var(--pxmin) * 1px);
  height: calc(var(--d) * var(--pxmin) * 1px);
  background: var(--sort); opacity: .55; }

/* Бронь: время · имя · цена. Кнопка — тап открывает карточку брони.
   ⚔ `body.panel` у .blok, .hul и .blokeret обязателен: имена оказались
   заняты. `.blok` живёт в пульте master2.html, `.blokeret` — на табло
   tv.html; общий style.css грузят все страницы, и без этой приставки
   панель молча переверстала бы чужие экраны (свойства, которых у них нет:
   display:flex, padding, overflow). Проверено: у tv/master/kiosk/index
   голый <body>, класс panel есть только у admin.html. */
body.panel .blok {
  position: absolute; left: 3px; right: 3px; overflow: hidden;
  top: calc(var(--m) * var(--pxmin) * 1px);
  height: calc(var(--d) * var(--pxmin) * 1px);
  display: flex; flex-direction: column; gap: 2px; justify-content: flex-start;
  padding: 5px 7px; text-align: left; cursor: pointer;
  background: var(--mokka-2); border: 1px solid var(--creme-25);
  border-radius: 8px; color: var(--hvid); font-family: 'Bitter', Georgia, serif;
}
body.panel .blok:hover { border-color: var(--guld); }
body.panel .blok:focus-visible { outline: 3px solid var(--rav); outline-offset: -1px; }
.blok-tid { font: 500 .72rem 'Oswald', 'Arial Narrow', sans-serif;
  letter-spacing: .04em; color: var(--porc-70); }
.blok-navn { font: 600 .82rem 'Bitter', Georgia, serif; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.blok-pris { font: 500 .78rem 'Oswald', 'Arial Narrow', sans-serif; color: var(--porc-70); }
/* Короткая бронь (меньше ~22 минут) не вмещает три строки — цена уходит
   первой: имя и время нужнее. Замер: три строки просят 66 px, 20-минутный
   блок даёт 60 (обрезался хвост имени, кадр p2-desktop круга 1). */
body.panel .blok.lav .blok-pris { display: none; }
.blok-maerke { font: 600 .72rem 'Oswald', 'Arial Narrow', sans-serif;
  letter-spacing: .1em; color: var(--guld); }
.blok-flueben { position: absolute; top: 6px; right: 6px; color: var(--guld); }

/* Пересечение: «N aftaler i én stol». Красная капсула — единственное место
   экрана, где красный несёт смысл «разберись сейчас». */
/* Рамка остаётся на --roed: как элемент интерфейса она держит норму ≥3
   (замер 4,08 на фоне --mokka-2). Красный ТЕКСТ внутри карточки — только
   --roed-lys (Н-2: было 4,08, стало 5,90 при норме 4,5). */
body.panel .blok.overlap { border: 1.5px solid var(--roed); }
body.panel .blok.overlap .blok-tid { color: var(--roed-lys); }
/* «aftaler i én stol» в узкой колонке (три на экран телефона) обрезалось в
   «aftaler i én …» — этой подписи разрешено переноситься: место есть,
   капсула пересечения всегда высокая. */
body.panel .blok.overlap .blok-navn { white-space: normal; }
.blok-antal { font: 600 1.6rem 'Oswald', 'Arial Narrow', sans-serif; line-height: 1;
  color: var(--hvid); }
.blok-overlap-ord { font: 600 .72rem 'Oswald', 'Arial Narrow', sans-serif;
  letter-spacing: .1em; color: var(--roed-lys); }

/* Свободное окно: пунктир. Золотой — впереди (можно продать), серый —
   позади (уже не вернуть). Слова из мокапа A: LEDIG / TOMT. */
/* Подпись прижата к верху окна, а не по центру: окно бывает в полдня
   высотой, и центр у него — за краем экрана. */
body.panel .hul {
  position: absolute; left: 4px; right: 4px; cursor: pointer;
  top: calc(var(--m) * var(--pxmin) * 1px);
  height: calc(var(--d) * var(--pxmin) * 1px);
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  gap: 2px; padding: 6px 4px; background: none; border: 1.5px dashed var(--guld);
  border-radius: 8px; color: var(--guld); font-family: 'Oswald', 'Arial Narrow', sans-serif;
}
body.panel .hul:hover { background: var(--mokka-2); }
body.panel .hul:focus-visible { outline: 3px solid var(--rav); outline-offset: -1px; }
/* Подпись окна липнет к верху рамки: пустой хвост дня бывает в 6 часов
   высотой, и подпись по центру такого окна уезжает за экран (кадр
   p2-desktop круга 1 — окно Praktikant без единого слова). */
.hul-lab { position: sticky; top: 52px; display: flex; flex-direction: column;
  align-items: center; gap: 2px; }
.hul-ord { font-weight: 600; font-size: .72rem; letter-spacing: .14em; }
.hul-min { font-size: .72rem; opacity: .85; }
/* Прошлое окно (Н-5): один словарь пустого времени — «Ledig» только у
   будущего, у прошлого слова нет вовсе, остаются приглушённые минуты.
   ⚠ Приглушение держат ЦВЕТ (--daempet) и серый пунктир, а не opacity:
   пробная opacity .72 поверх собственных .85 подписи дала 3,88 : 1 при
   норме 4,5 (замер), то есть лечила бы шум ценой читаемости. Без неё —
   6,38 : 1. */
body.panel .hul.fortid { border-color: var(--daempet); color: var(--daempet); cursor: default; }
body.panel .hul.smal .hul-min { display: none; }              /* короткому окну хватит слова */
body.panel .hul.fortid.smal .hul-min { display: block; }      /* …а у прошлого минуты — всё, что есть */

/* Блокировка мастера (обед, личное) — штриховки нет, есть честная заливка */
/* Подпись по центру, а не в углу: блокировка часто начинается там, где
   кончается бронь, и верхний угол уходит под блок брони — слово «Blokeret»
   пропадало совсем (кадр p2-blokeret круга 1, блок 13:00–14:00 под Mads). */
body.panel .blokeret {
  position: absolute; left: 3px; right: 3px; padding: 4px 6px;
  top: calc(var(--m) * var(--pxmin) * 1px);
  height: calc(var(--d) * var(--pxmin) * 1px);
  display: flex; align-items: center; justify-content: center; text-align: center;
  background: var(--sort); border: 1px solid var(--kant); border-radius: 8px;
  color: var(--daempet); font: 500 .72rem 'Oswald', 'Arial Narrow', sans-serif;
  letter-spacing: .08em; text-transform: uppercase; overflow: hidden;
}

/* Черта «сейчас»: через все колонки. Ни анимации, ни пульсации — наряд П2
   п.8 и выжимка журнала §3 (движения мало, автолупов ноль).
   ⚔ Н-8: черта идёт ПОД карточками, а не поверх. Поверх она ложилась ровно
   на строку «aftaler i én stol» (замер приёмки: черта 467,7 px, строка
   460,25–476 px) и читалась как зачёркивание — устойчивый знак «отменено».
   Слои: колонки z-index 2 (карточки непрозрачны — черта под ними не видна),
   черта z-index 1 (видна в пустом времени, там она и нужна), ось времени
   z-index 3 — красные часы «10:30» на ней остаются маркером края. */
.net-nu { position: absolute; left: 0; right: 0; height: 0;
  top: calc(var(--akse) + var(--m) * var(--pxmin) * 1px);
  border-top: 1.5px solid var(--roed); z-index: 1; pointer-events: none; }

/* Вопрос-подпись под сеткой (закон 0.3: карточка = вопрос агенту) */
.net-sporg, .penge-sporg {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 44px; margin-top: 8px; padding: 8px 2px; cursor: pointer;
  background: none; border: 0; border-top: 1px solid var(--creme-25);
  color: var(--guld); font: italic 400 .95rem 'Bitter', Georgia, serif; text-align: left;
}
.net-sporg span, .penge-sporg span { flex: 1; }
.net-sporg:hover, .penge-sporg:hover { color: var(--guld-hover); }
.net-sporg:focus-visible, .penge-sporg:focus-visible {
  outline: 3px solid var(--rav); outline-offset: 2px; }

/* Пусто: день без работающих мастеров */
.net-tom { padding: 24px 16px; color: var(--daempet); text-align: center; }

/* Отсутствующие сегодня (Н-16): колонки в сетке нет — правило §2 п.3
   в силе, — но факт дня владелец видеть обязан. Одна строка, без карточки
   и без абзаца: точка + имя + причина. */
.dag-fravaer { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 10px; }
.dag-fravaer:empty { display: none; }
.fravaer-linje {
  display: inline-flex; align-items: center; gap: 8px;
  font: 400 .85rem 'Bitter', Georgia, serif; color: var(--daempet);
}
.fravaer-linje::before {
  content: ''; width: 8px; height: 8px; border-radius: 50%;
  background: var(--daempet); flex: none;
}

/* ── Быстрые действия: три пилюли (мокап A-mobile, паритет платформ) ────
   П6-БИС: жёсткие `repeat(3, 1fr)` сломались, когда колонка отдала 80 px
   резервному углу облачка: три подписи с `nowrap` перестали помещаться на
   390 и ряд ВЫЛЕЗ вправо, в выгороженную зону (поймано скан-прогоном, а
   не глазом — 20 перекрытий на Kalender/390).
   Лечим не порогом ширины экрана (он врал бы при любой смене резерва), а
   переносом по месту: сколько пилюль влезло — столько и стоит в ряду,
   остальные уходят на следующую строку и растягиваются. Правило само
   отрабатывает и 320, и 390, и десктоп. */
.dag-handlinger { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 12px; }
.pille-knap {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  flex: 1 1 auto;                 /* делят строку поровну, ужимаясь до слова */
  min-height: 48px; padding: 6px 8px; cursor: pointer;
  background: none; border: 1.5px solid var(--kant); border-radius: var(--pille);
  color: var(--hvid); font: 500 .8rem 'Bitter', Georgia, serif;
}
/* Подпись пилюли — одной строкой: «Blokér / tid» в два этажа делало ряд
   разноэтажным (кадр p2-lukket-dag круга 1). Замер на 390: ряд просит
   107 px на пилюлю, есть 117. */
.pille-knap span { white-space: nowrap; }
.pille-knap:hover { border-color: var(--guld); color: var(--guld); }
.pille-knap:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }
.pille-knap[aria-expanded="true"] { border-color: var(--guld); color: var(--guld); }
.pille-knap svg { flex: none; }
/* На 320 три подписи в ряд не живут. Прятать слова и оставлять три голых
   значка — ребус (кадр p2-smal круга 1): вместо этого раскладываем пилюли
   в столбик, каждая со своим словом. Столбик теперь получается сам
   переносом; правило оставляет за собой только вид одиночной пилюли —
   растянутая на всю ширину, она читается лучше со значком слева. */
@media (max-width: 359px) {
  .pille-knap { justify-content: flex-start; padding-inline: 18px; }
}

/* Форма быстрого действия раскрывается НА МЕСТЕ, а не модалкой: обе формы
   (Sygemelding, Blokér tid) — те же поля наряда П1, им нужны select, дата и
   время; в fw-modal живёт один текст, ради двух форм её механику не гнём. */
.hurtig-form { margin: 0 0 12px; padding: 12px; background: var(--mokka);
  border: 1.5px solid var(--kant); border-radius: var(--radius); }
.hurtig-form[hidden] { display: none; }

/* ── Денежная строка дня: две подписанные цифры + почасовые столбцы ───── */
/* Рамка карточки живёт на ОБЁРТКЕ (добивка П6, находка К1): внутри неё
   две разные цели — сама карточка ведёт в Indsigt (чертёж §2 п.5), а
   подпись-вопрос под ней открывает агента (§3, «кнопка агента»). Кнопку
   в кнопку не вкладывают: разметка невалидна, вложенная цель недостижима
   с клавиатуры и не имеет своего состояния фокуса. Геометрия карточки не
   изменилась ни на пиксель — отступ 14 px просто переехал на обёртку. */
.dag-penge-boks {
  padding: 14px; background: var(--mokka); border: 1.5px solid var(--creme-25);
  border-radius: var(--radius);
}
/* Рамка отзывается на наведение именно карточки-ссылки: подпись-вопрос
   ведёт в другое место и говорит об этом своим золотом, а не рамкой. */
.dag-penge-boks:has(> .dag-penge:hover) { border-color: var(--guld); }
.dag-penge {
  display: block; width: 100%; text-align: left; cursor: pointer;
  padding: 0; background: none; border: 0;
  color: var(--hvid); font-family: 'Bitter', Georgia, serif;
}
.dag-penge:focus-visible { outline: 3px solid var(--rav); outline-offset: 2px; }
.penge-tal { display: flex; gap: 24px; flex-wrap: wrap; align-items: flex-end; }
.penge-et { display: flex; flex-direction: column; gap: 2px; }
.penge-mrk { font: 500 .78rem 'Bitter', Georgia, serif; color: var(--daempet); }
.penge-stor { font: 600 clamp(2rem, 1.2rem + 3.5vw, 2.9rem) 'Oswald', 'Arial Narrow', sans-serif;
  line-height: .9; letter-spacing: -.01em; }
.penge-lille { font: 600 1.4rem 'Oswald', 'Arial Narrow', sans-serif; line-height: .9;
  color: var(--porc-70); }
.penge-under { display: block; margin-top: 8px; font-size: .8rem; color: var(--daempet); }
.penge-graf { width: 100%; height: auto; margin-top: 10px; display: block; }
.penge-tegn { display: flex; gap: 14px; flex-wrap: wrap; margin-top: 6px;
  font-size: .75rem; color: var(--daempet); }
.penge-tegn i { display: inline-flex; align-items: center; gap: 6px; font-style: normal; }
.tegn-fyldt { width: 12px; height: 12px; background: var(--guld); flex: none; }
.tegn-tom { width: 12px; height: 12px; border: 1.5px dashed var(--guld); flex: none; }
.tegn-nu { width: 12px; height: 2px; background: var(--roed); flex: none; }

/* Почасовые столбцы — единственный настоящий ГРАФИК этого экрана, и он,
   как велит чертёж §7, голый SVG. Цвета — классами, не атрибутами fill:
   палитра обязана оставаться в токенах. */
.penge-graf .stav-fyldt { fill: var(--guld); }
.penge-graf .stav-tom { fill: none; stroke: var(--guld); stroke-width: 1.5; stroke-dasharray: 4 3; }
.penge-graf .stav-nul { fill: var(--creme-25); }
.penge-graf .graf-linje { stroke: var(--creme-25); }
.penge-graf .graf-nu { stroke: var(--roed); stroke-width: 1.2; stroke-dasharray: 3 3; }
/* оси и деления данных в графиках от 11px — канон §2, исключение узаконено Алексом 25.08 (decisions) */
.penge-graf .graf-tal { fill: var(--daempet); font: 500 11px 'Oswald', 'Arial Narrow', sans-serif; }
.penge-graf .graf-top { fill: var(--hvid); font: 600 11px 'Oswald', 'Arial Narrow', sans-serif; }

/* ── Десктоп ≥1024: сетка крупно слева, карточки правой колонкой ────────
   Не растянутый телефон (наряд П2 п.7). `.wrap` шире у ТРЁХ вкладок с
   картинками — Kalender (сетка дня), Indsigt (карточки графиков, наряд П3)
   и Marketing (наряд П5: живое превью страницы записи, полоса согласий,
   список спящих — те же .rap-kort, что у Indsigt). Mere остаётся формой,
   ей 640 px в самый раз.
   ⚠ До П5 здесь стояло «Marketing и Mere — формы»: тогда вкладка и была
   двумя формами. Она перестала ею быть вместе с чертежом §4, и ширина
   поехала за содержимым, а не наоборот.
   :has() поддерживают все живые браузеры; там, где нет, вкладка просто
   останется узкой — вёрстка не ломается. */
@media (min-width: 1024px) {
  /* Ленте дня ширина — рабочий материал, а не украшение: каждый лишний
     пиксель это ещё минуты дня, попавшие в кадр без прокрутки. Поэтому у
     Kalender рамка шире, чем у Indsigt: там карточки графиков, и 1184
     им ровно впору (П3 принят в этой ширине — не трогаем).
     1720 — не круглое число: рабочий день салона 09:00–17:30 это 510 мин,
     при полу 3 px/мин лента просит 1530 px, плюс колонка имён 152 и
     отступы 36 → 1718. То есть на достаточно большом мониторе день
     помещается ЦЕЛИКОМ, а не «сколько влезло». */
  /* Ширина рамки каждой вкладки живёт ОДНИМ числом — в --wrap-max: её
     читает и `max-width`, и формула центровки ниже. Две копии одного
     числа разъехались бы на первой же правке. */
  body.panel .wrap:has(#fane-kalender:not([hidden])) { --wrap-max: 1720px; }
  body.panel .wrap:has(#fane-indsigt:not([hidden])) { --wrap-max: 1184px; }
  /* Marketing — тот же словарь карточек, что Indsigt, значит та же рамка. */
  body.panel .wrap:has(#fane-marketing:not([hidden])) { --wrap-max: 1184px; }
  /* Порядок в разметке — телефонный (чертёж §2: исключение → сетка →
     действия → деньги). Десктоп не переставляет узлы, он раскладывает их
     по областям. Одна разметка на две платформы — паритет держится сам.
     Раскладка сменилась вместе с лентой: раньше сетка занимала левую
     колонку, а карточки шли правой (это годилось вертикальной сетке —
     ей нужна высота). Ленте нужна ШИРИНА: каждый отнятый у неё пиксель —
     это минуты дня, выпавшие из кадра (замер: при колонке 340 px лента на
     1280 показывала 2 ч 48 мин из 8 ч 30 — меньше, чем эталон-скелет).
     Поэтому лента идёт во всю ширину, а карточки — строками над ней.
     Строка-исключение остаётся во всю ширину сверху: это единственное на
     экране, что кричит «разберись сейчас», и делить его пополам нельзя.
     Раскладка — ОДНА КОЛОНКА и порядок сверху вниз: исключение → действия
     → деньги → лента. Две колонки («деньги слева, пилюли справа») сняты
     приёмкой добивок: денежная карточка тянулась на всю ширину ряда
     (`grid-column: 1 / -1` из Н7) и ложилась ПОВЕРХ ряда пилюль — замер
     1280: обе на y=150, `elementFromPoint` в центре «Blokér tid» отдавал
     `span.eyebrow` карточки денег, то есть все три быстрых действия были
     некликабельны (нарушение п.4 наряда П2-бис). Пилюлям своя строка над
     деньгами; ширину карточка денег при этом не теряет, пустота справа не
     возвращается. */
  #fane-kalender .dag-krop {
    display: grid; grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "und" "hand" "form" "penge" "net";
    gap: 12px; align-items: start;
  }
  #fane-kalender .dag-undtagelse-boks { grid-area: und; }
  #fane-kalender .dag-net { grid-area: net; margin-bottom: 0; }
  /* Пилюли рядом, но с потолком: на широкой ленте три кнопки, растянутые
     на 460 px каждая, читаются как баннеры, а не как действия.
     П6-бис: ряд переехал с сетки на перенос по месту, и потолок надо было
     переставить с колонок на сами пилюли — иначе `flex: 1 1 auto` тихо
     съел решение приёмки (замер поймал 282/305/325 px вместо 260). */
  #fane-kalender .dag-handlinger { grid-area: hand; margin: 0; }
  #fane-kalender .pille-knap { max-width: 260px; }
  #fane-kalender .hurtig-former { grid-area: form; }
  /* Н7: денежная карточка во всю ширину. Ширину ей теперь даёт сама
     колонка раскладки, а не растяжка `grid-column: 1 / -1` — та накрывала
     соседнюю область с пилюлями (см. разбор у .dag-krop выше). */
  #fane-kalender .dag-penge-boks { grid-area: penge; }
  #fane-kalender .net-ramme { max-height: calc(100vh - 230px); }
  /* Н2. На ленте у рамки нет вертикальной прокрутки — вертикальное колесо
     над ней JS переводит в движение дня вбок. Пока дню есть куда ехать,
     колесо забирает себе он; когда лента упёрлась в край, страница обязана
     поехать дальше, иначе рамка становится ямой: колесо уже не двигает
     день и ещё не двигает страницу. `contain` из базового правила остаётся
     телефону — там день едет ВНИЗ внутри рамки, и цепляться за страницу
     ему нельзя. */
  #fane-kalender .net-ramme { overscroll-behavior-y: auto; }
  /* Здесь стояла обрезка строки-вопроса на 76 px — плата за парящую кнопку
     в правом нижнем углу (находка Н-9): строка кончалась до кнопки, чтобы
     палец не целился в шеврон и не попадал в кнопку. Кнопки больше нет,
     полоса возвращена строке целиком. */
  #fane-kalender .pille-knap { justify-content: flex-start; padding-inline: 18px; }
  #fane-kalender .pille-knap span { display: inline; }
  #fane-kalender .undtagelse, #fane-kalender .hurtig-form { margin: 0; }
  .dag-titel { font-size: 2rem; }

  /* ── ЛЕНТА ДНЯ (наряд П2-бис п.1, скелет A-Desktop) ─────────────────
     Тот же день, повёрнутый на 90°: время течёт слева направо по верху,
     мастера — горизонтальными строками, черта «сейчас» режет ленту
     насквозь. Ни одного нового узла разметки — минуты (`--m`, `--d`)
     просто ложатся в другую ось. Всё, что решила приёмка про словарь
     пустого времени, роль под именем и слои черты, переезжает вместе с
     ними: правила те же, повёрнута только ось.
     Почему лента, а не широкие колонки: чертёж §2, последняя строка —
     «десктоп не растянутый телефон»; находка приёмки Н-14. */

  #fane-kalender .net-gitter { flex-direction: column; width: max-content; }

  /* Линейка времени переезжает наверх и липнет к верхнему краю рамки */
  #fane-kalender .net-akse {
    position: sticky; top: 0; left: auto; z-index: 4;
    display: flex; width: auto;
    border-right: 0; border-bottom: 1px solid var(--creme-25);
  }
  /* Угол над колонкой имён: липнет и вверх (внутри линейки), и влево —
     иначе часы уезжают под имена мастеров при прокрутке ленты. */
  #fane-kalender .akse-hoved {
    position: sticky; left: 0; z-index: 2; flex: none;
    width: var(--navn); height: 26px;
    border-bottom: 0; border-right: 1px solid var(--creme-25);
  }
  #fane-kalender .akse-krop {
    flex: none; height: 26px;
    width: calc(var(--dagmin) * var(--pxmin) * 1px);
  }
  /* Часы стоят У СВОЕЙ засечки, а не по её центру: центрированная первая
     метка наполовину уезжала бы за левый край ленты. */
  #fane-kalender .akse-time {
    top: 50%; right: auto; padding-left: 5px;
    left: calc(var(--m) * var(--pxmin) * 1px);
  }
  #fane-kalender .akse-nu {
    top: 50%; right: auto; padding: 2px 5px 2px 9px;
    left: calc(var(--m) * var(--pxmin) * 1px);
  }
  /* Точка-маркер начала черты переезжает на её левый край (Н-8) */
  #fane-kalender .akse-nu::after { right: auto; left: -3.5px; }

  /* Мастера — строки: имя слева липнет, день едет вбок */
  #fane-kalender .net-spor { flex-direction: column; }
  #fane-kalender .dag-kol {
    display: flex; flex: none; width: 100%;
    border-right: 0; border-bottom: 1px solid var(--creme-25);
  }
  #fane-kalender .dag-kol:last-child { border-bottom: 0; }
  #fane-kalender .kol-hoved {
    position: sticky; top: auto; left: 0; z-index: 3; flex: none;
    display: flex; flex-direction: column; justify-content: center;
    width: var(--navn); height: var(--raekke); padding: 6px 12px;
    border-bottom: 0; border-right: 1px solid var(--creme-25);
  }
  /* У строки высота есть — «barber · 10 aftaler» (Н-7) разрешено занять
     вторую строчку вместо многоточия; у шапки колонки телефона места на
     это не было, поэтому там правило другое. */
  #fane-kalender .kol-antal { white-space: normal; }
  #fane-kalender .kol-krop {
    flex: none; height: var(--raekke);
    width: calc(var(--dagmin) * var(--pxmin) * 1px);
  }
  #fane-kalender .kol-time {
    top: 0; bottom: 0; right: auto; border-top: 0;
    left: calc(var(--m) * var(--pxmin) * 1px);
    border-left: 1px solid var(--creme-25);
  }
  #fane-kalender .kol-udenfor {
    top: 0; bottom: 0; height: auto; right: auto;
    left: calc(var(--m) * var(--pxmin) * 1px);
    width: calc(var(--d) * var(--pxmin) * 1px);
  }
  /* Кусок дня: те же минуты, теперь это left/width. Зазор в 3 px был
     между колонками — теперь он между строками. */
  #fane-kalender .blok,
  #fane-kalender .hul,
  #fane-kalender .blokeret {
    top: 3px; bottom: 3px; height: auto; right: auto;
    left: calc(var(--m) * var(--pxmin) * 1px);
    width: calc(var(--d) * var(--pxmin) * 1px);
  }
  /* Строки карточки не сжимаются: флекс-колонка давит лишнее МОЛЧА —
     `.blok-navn` терял 13 px из 16 и превращался в полоску, а
     scrollHeight при этом не рос, то есть прибор переполнения такого
     не видит. Пусть лучше высота строки будет честно рассчитана. */
  #fane-kalender .blok > * { flex: none; }

  /* Подпись свободного окна липнет к ЛЕВОМУ краю: хвост дня бывает в шесть
     часов шириной, и подпись по центру такого окна уезжает за экран. Тот же
     приём, что на телефоне (там она липла к верху), только ось другая.
     Прилипает не к нулю, а к КРАЮ КОЛОНКИ ИМЁН: имена мастеров сами липкие
     и непрозрачные, и подпись, приклеенная к нулю, честно пряталась под
     ними (замер: подпись «90 min» на x=300 при колонке имён 249–401). */
  #fane-kalender .hul { align-items: flex-start; justify-content: center; padding: 6px 8px; }
  #fane-kalender .hul-lab { top: auto; left: var(--navn); align-items: flex-start; }
  /* Черта «сейчас» режет ВСЮ ленту сверху донизу; слева от неё — колонка
     имён, поэтому отступ считается от неё. Слои не меняются (Н-8): черта
     под карточками броней, ось времени над всем. */
  #fane-kalender .net-nu {
    top: 0; bottom: 0; height: auto; right: auto; width: 0; border-top: 0;
    left: calc(var(--navn) + var(--m) * var(--pxmin) * 1px);
    border-left: 1.5px solid var(--roed);
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   INDSIGT — отчёты картинками (наряд П3, чертёж панели §3)

   Правило формы: одна карточка = один вопрос владельца = одна картинка.
   Текста на карточке ровно три строки: заголовок, главная цифра с подписью
   и вопрос агенту курсивом. Всё длинное (формула метрики, чего цифра НЕ
   учитывает) живёт в окне по значку ⓘ — закон 0.2 чертежа.

   Цвет: золото — единственный акцент; доли различаются лестницей ЯРКОСТИ
   того же золота и нейтралов, третьего цвета нет (чертёж §7). Цвет здесь
   ВТОРОЙ ключ: у каждой доли рядом стоит имя и цифра в легенде, поэтому
   различить их можно и не различая оттенков.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Шапка вкладки: период + даты периода ─────────────────────────────── */
.rap-top { padding: 4px 0 2px; }
.rap-datoer { margin: 0 0 12px; font-size: .85rem; color: var(--daempet); }

/* ── Сетка карточек ──────────────────────────────────────────────────── */
.rap-gitter { display: grid; grid-template-columns: 1fr; gap: 12px; align-items: start; }
/* Элемент сетки по умолчанию не уже своего min-content — один длинный
   токен внутри (ссылка в тексте SMS) раздувает всю колонку и выносит
   карточку за экран. min-width:0 возвращает колонке право быть узкой. */
.rap-gitter > * { min-width: 0; }

.rap-kort {
  background: var(--mokka); border: 1.5px solid var(--creme-25);
  border-radius: var(--radius);                    /* 12 px — из чертёжных 8–16 */
  padding: 12px 14px 8px;
}
.rap-hoved { display: flex; align-items: center; gap: 8px; }
.rap-titel {
  flex: 1; margin: 0;
  font: 600 1rem 'Oswald', 'Arial Narrow', sans-serif;
  letter-spacing: .06em; text-transform: uppercase;
}
/* Значок методики — цель пальца 44 px канона §2, а не 22-пиксельная иконка */
.rap-info {
  flex: none; width: 44px; height: 44px; margin-right: -10px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; padding: 0; color: var(--daempet); cursor: pointer;
}
.rap-info:hover { color: var(--guld); }
.rap-info:focus-visible { outline: 3px solid var(--rav); outline-offset: -3px; border-radius: 50%; }

/* Главная цифра карточки: тот же приём, что у денег дня на Kalender */
.rap-stor {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 10px;
  margin: 2px 0 0;
  font: 600 clamp(1.6rem, 1.1rem + 2.4vw, 2.2rem) 'Oswald', 'Arial Narrow', sans-serif;
  line-height: 1; letter-spacing: -.01em;
}
.rap-enhed { font: 500 1rem 'Bitter', Georgia, serif; color: var(--daempet); letter-spacing: 0; }
.rap-under { margin: 8px 0 0; font-size: 1rem; color: var(--daempet); }
.rap-advarsel { color: var(--roed-lys); }
.rap-tom { margin: 10px 0 6px; font-size: 1rem; color: var(--daempet); }

/* Чип дельты к прошлому периоду (правило 3 отчёта-референса) */
.rap-delta {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--pille);
  background: var(--mokka-2); border: 1px solid var(--kant);
  font: 500 .8rem 'Bitter', Georgia, serif; letter-spacing: 0; color: var(--hvid);
}
.rap-delta svg { fill: var(--guld); }

/* Вопрос агенту = кнопка (закон 0.3). Ряд во всю ширину карточки, 44 px. */
.rap-sporg {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  width: 100%; min-height: 44px; margin-top: 6px; padding: 8px 0 4px;
  background: none; border: 0; border-top: 1px solid var(--creme-25);
  color: var(--guld); font-family: 'Bitter', Georgia, serif; font-size: .9rem;
  text-align: left; cursor: pointer;
}
.rap-sporg i { font-style: italic; }
.rap-sporg:hover { color: var(--guld-hover); }
.rap-sporg:focus-visible { outline: 3px solid var(--rav); outline-offset: -3px; }

/* ── Графики: голый SVG, ширина по месту (см. комментарий в admin.html) ── */
.rap-graf { margin-top: 12px; }
.rap-svg { display: block; max-width: 100%; }

/* Столбцы и линии — общий словарь форм со сводкой денег дня на Kalender:
   заливка = факт, пунктир = будущее, тонкая линия = прошлое. */
.rap-svg .stav { fill: var(--guld); }
.rap-svg .stav-plan { fill: var(--daempet); }
.rap-svg .stav-tom { fill: none; stroke: var(--guld); stroke-width: 1.5; stroke-dasharray: 4 3; }
.rap-svg .stav-nul { fill: var(--creme-25); }
.rap-svg .graf-linje { stroke: var(--creme-25); }
.rap-svg .graf-foer { fill: none; stroke: var(--daempet); stroke-width: 1.5; stroke-dasharray: 5 4; }
/* оси и деления данных в графиках от 11px — канон §2, исключение узаконено Алексом 25.08 (decisions) */
.rap-svg .graf-tal { fill: var(--daempet); font: 500 11px 'Oswald', 'Arial Narrow', sans-serif; }
.rap-svg .graf-top { fill: var(--hvid); font: 600 12px 'Oswald', 'Arial Narrow', sans-serif; }
.rap-svg .graf-navn { fill: var(--hvid); font: 400 13px 'Bitter', Georgia, serif; }
.rap-svg .graf-vaerdi { fill: var(--hvid); font: 600 13px 'Oswald', 'Arial Narrow', sans-serif; }
.rap-svg .graf-under { fill: var(--daempet); font: 400 11px 'Bitter', Georgia, serif; }
.rap-svg .graf-tom { fill: var(--daempet); font: italic 400 12px 'Bitter', Georgia, serif; }

/* Кольцо долей: сегменты — дуги одной окружности */
.rap-svg .ring-bund { fill: none; stroke: var(--mokka-2); }
.rap-svg .ring-del { fill: none; stroke: var(--dele); }
.rap-svg .polosa-del { fill: var(--dele); }

/* Шкала загрузки: за отметкой 100 % — перегруз, и он обязан быть виден (В2) */
.rap-svg .skala-bund { fill: var(--mokka-2); stroke: var(--varme-kant); stroke-width: 1.5; }
.rap-svg .skala-over { fill: var(--roed); }
.rap-svg .skala-maerke { stroke: var(--daempet); stroke-width: 1; stroke-dasharray: 2 2; }

/* Тепловая карта: одна краска, густота = число броней */
.rap-svg .varme { fill: var(--guld); }
.rap-svg .varme-nul { fill: var(--mokka-2); stroke: var(--varme-kant); stroke-width: 1.5; }

/* Лестница долей. Одно золото + нейтрали: «третьего цвета нет» (чертёж §7).
   Пятая ступень — предел: больше пяти долей на одной картинке не читает
   никто, и легенда всё равно несёт имя и цифру. */
/* Четвёртая и пятая ступени были РАЗБАВЛЕННЫМИ (золото с белым и серый с
   белым) и садились вплотную к своим же родителям: 1,46 и 1,09 — глазом
   один цвет (находка приёмки П4). Разводим их вниз по яркости: тёмное
   золото и тёмный серый. Тогда пары одной крови стоят 1,90 и 2,36, а
   соседние сегменты на картинке ещё и разделены зазором фона. */
.rap-d1 { --dele: var(--guld); }
.rap-d2 { --dele: var(--hvid); }
.rap-d3 { --dele: var(--daempet); }
.rap-d4 { --dele: color-mix(in srgb, var(--guld) 70%, var(--sort)); }
.rap-d5 { --dele: color-mix(in srgb, var(--daempet) 62%, var(--sort)); }

/* Ступени СЛОВАРЯ ПРИЧИН (наряд П4, В9). Отдельная лестница, а не rap-d*:
   у долей ступень зависит от порядка в данных, а причина обязана иметь
   ОДИН и тот же цвет во всех периодах — иначе «не пришёл» на прошлой
   неделе и в прошлом месяце окрашены по-разному, и глаз сравнивает не то.
   Цвета — токенами (theme.css), как велит наряд. */
.afb-kunde { --dele: var(--afbud-kunde); }
.afb-udebliv { --dele: var(--afbud-udeblevet); }
.afb-salon { --dele: var(--afbud-salon); }
.afb-flyt { --dele: var(--afbud-flyttet); }
.afb-ukendt { --dele: var(--afbud-ukendt); }
.rap-svg .aarsag-stav { fill: var(--dele); }

/* Список спящих клиентов: имя слева, «когда был» справа. Не таблица —
   две строки в ряду читаются на 320 без горизонтальной прокрутки. */
.sovende-liste { list-style: none; margin: 12px 0 0; padding: 0; }
.sovende-liste li {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 7px 0; border-top: 1px solid var(--creme-25);
}
.sovende-navn { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-size: 1rem; }
.sovende-hvornaar { color: var(--daempet); font: 500 .95rem 'Oswald', 'Arial Narrow', sans-serif;
  white-space: nowrap; }

/* Легенда: квадратик + имя + цифра */
.rap-tegn { list-style: none; margin: 10px 0 0; padding: 0; }
.rap-tegn li {
  display: flex; align-items: center; gap: 8px;
  padding: 3px 0; font-size: .85rem;
}
.rap-tegn-navn { flex: 1; min-width: 0; }
.rap-tegn-tal { color: var(--daempet); font-family: 'Oswald', 'Arial Narrow', sans-serif; }
.rap-prik { width: 12px; height: 12px; flex: none; background: var(--dele); }

/* ── Окно методики: длинное живёт здесь, а не на экране ───────────────── */
.metodik-ark { max-width: 460px; }
.metodik-titel {
  margin: 0 0 12px;
  font: 600 1.25rem 'Oswald', 'Arial Narrow', sans-serif;
  letter-spacing: .06em; text-transform: uppercase; color: var(--hvid);
}
.metodik-blok { margin-bottom: 16px; }
.metodik-mrk {
  margin: 0 0 4px; font: 500 .74rem 'Bitter', Georgia, serif;
  letter-spacing: .08em; text-transform: uppercase; color: var(--guld);
}
.metodik-tekst { margin: 0; font-size: .95rem; line-height: 1.5; color: var(--hvid); }
.metodik-fod {
  margin: 0 0 16px; font-size: .78rem; color: var(--daempet);
  font-family: 'Oswald', 'Arial Narrow', sans-serif; letter-spacing: .04em;
}

/* ═══ MARKETING (наряд П5, чертёж §4) ══════════════════════════════════
   Тот же словарь форм, что у Indsigt: карточка .rap-kort, ⓘ, подпись-вопрос.
   Своего языка у вкладки нет — иначе панель распадалась бы на три продукта.
   ══════════════════════════════════════════════════════════════════════ */

/* Экран клиента внутри панели. Белое поле на чёрной панели — то самое
   чередование чёрное↔белое из чертежа: владелец видит, что это ДРУГОЕ
   место, а не ещё одна карточка панели. Внутри работает .lys, поэтому
   баннер красится ровно теми же правилами, что на странице записи. */
.mk-skaerm { margin-top: 10px; }
.mk-skaerm-mrk {
  display: block; margin-bottom: 6px;
  font: 500 .74rem 'Bitter', Georgia, serif;
  letter-spacing: .08em; text-transform: uppercase; color: var(--guld);
}
.mk-lys { border-radius: var(--radius); padding: 4px 14px 14px; }
/* Баннер стоит первым и сам держит свой отступ сверху — в белом поле он
   первый элемент, и двойной воздух над ним читался бы как пустая полоса. */
.mk-lys .tilbud-banner { margin-top: 14px; }
.mk-lys .eyebrow { margin: 14px 0 0; }
.mk-tom-linje { margin: 14px 0 0; color: var(--daempet-lys); font-size: .95rem; }

/* Три контрола акции. Ряд с переносом: на 390 «услуга + % + дата + кнопка»
   в одну строку не живут, а тап-цель обязана остаться ≥44. */
.mk-tre { margin-top: 12px; }
.mk-tre select { flex: 1 1 100%; min-height: 44px; }
.mk-tre input { flex: 0 0 auto; min-height: 44px; }
.mk-tre .mk-felt { display: flex; align-items: center; gap: 6px; }
.mk-tre .mk-felt-mrk { color: var(--daempet); font-size: .85rem; white-space: nowrap; }
/* Специфичность не для красоты: глобальное `input[type=number]{width:100%}`
   (0,1,1) перебивает одиночный класс (0,1,0) — поле процентов растянулось бы
   во всю строку. Поэтому селектор из двух классов. */
.mk-tre .mk-pct { width: 84px; }
.mk-tre .mk-dato { width: auto; }

/* Список: имя и действие в первой строке, факты — во второй.
   Не таблица: три колонки на 320 схлопывают датское имя в две буквы. */
.mk-liste { list-style: none; margin: 12px 0 0; padding: 0; }
/* Маркер состояния — ТОЧКА перед именем (добивка приёмки П5, круг 2).
   До маркера три состояния различались в СВОДКЕ цветом, а в СТРОКАХ —
   только словом: сводка говорила «двое в паузе, двое без согласия», а
   список выглядел одинаково серым, и глаз не мог связать картинку со
   строками. Цвет берётся из той же лестницы .rap-d*, что красит полосу и
   легенду, — двух палитр для одного смысла не заводим.
   Цвет здесь ТРЕТИЙ канал, а не единственный: состояние уже названо словом
   в табличке и кнопкой (Send SMS ↔ Ring).

   ⚠ Первым заходом здесь стояла ПОЛОСКА 4 px слева — и это side-tab,
   выжженный штамп: Алекс уже снимал такую черту со сводки записи (коммит
   9899162, «точка-индикатор вместо черты»), и робот вкуса метит её
   [side-tab]. Форма взята у активной вкладки навигации (.fane-prik):
   круг того же приёма, только крупнее — 5 px рядом с 16-м именем не
   виден. Ступени и логика sovTrin не менялись, поменялась ФОРМА. */
.mk-liste { --prik: 8px; --prik-gab: 10px; }
.mk-liste li { padding: 10px 0 8px; border-top: 1px solid var(--creme-25); }
.mk-raekke::before {
  content: ''; flex: none;
  width: var(--prik); height: var(--prik); border-radius: 50%;
  background: var(--dele);
}
/* align-items:center сажает точку по центру строки ИМЕНИ (не всей
   двухстрочной записи) — она стоит перед именем и читается вместе с ним. */
.mk-raekke { display: flex; align-items: center; gap: var(--prik-gab); }
.mk-navn { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-size: 1rem; font-weight: 600; }
/* Вторая строка встаёт под именем, а не под точкой: отступ считается из
   тех же двух чисел, что задают саму точку, — разъехаться нечему. */
.mk-under { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin: 4px 0 0 calc(var(--prik) + var(--prik-gab)); }
.mk-hvornaar { color: var(--daempet); font: 500 .95rem 'Oswald', 'Arial Narrow', sans-serif; }
/* Слово состояния — тот же приём «выключенного», что у рядов и карточек:
   рамка плюс СЛОВО, ни грамма прозрачности (добивка приёмки круга 2). */
.mk-mrk {
  display: inline-block; padding: 2px 9px; border-radius: var(--pille);
  border: 1px dashed var(--daempet); color: var(--daempet);
  font: 500 .8rem 'Bitter', Georgia, serif;
}
/* Кнопка-ссылка «Ring» обязана выглядеть и попадаться пальцем как кнопка */
.mk-liste .btn { flex: none; }
a.btn.mini { display: inline-flex; align-items: center; text-decoration: none; }

/* Текст SMS — и в карточке напоминания, и в окне подтверждения отправки.
   Рамка отделяет ЧУЖОЙ текст (то, что прочитает клиент) от наших подписей.
   overflow-wrap: ссылка отмены — один непереносимый токен; без него он
   распирал колонку сетки (замер: карточка 389 px в окне 358 — grid-блоуаут,
   min-width:auto у элемента сетки). */
.sms-boks {
  margin: 0 0 16px; padding: 12px 14px;
  border: 1.5px solid var(--guld); border-radius: var(--radius);
  background: var(--mokka-2); color: var(--hvid);
  font: 400 .95rem/1.5 'Bitter', Georgia, serif; white-space: pre-line;
  overflow-wrap: anywhere;
}

/* Заглушка «Kommer» (чертёж §4): карточка есть, начинки нет — и это видно
   рамкой и словом, а не серым текстом. Обещаний и дат в ней нет. */
/* Рамка здесь НЕСЁТ состояние (вместе со словом), значит обязана быть
   видна: общая рамка карточки --creme-25 даёт 1,79 : 1 к чёрному фону, а
   приглушённый нейтраль — 8,4 : 1. Тот же цвет, что у выключенного ряда. */
.mk-kommer { border-style: dashed; border-color: var(--daempet); }

/* ── Десктоп ≥1024: карточки в ряд, а не растянутый телефон ───────────── */
@media (min-width: 1024px) {
  .rap-gitter { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
  /* Рамка будущего живёт в том же ритме колонок: во всю ширину десктопа
     семь столбцов расплывались бы в заливку, а сузить их — значит оставить
     полкарточки пустой. */
  #rap-frem { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
  /* Тепловая карта и план/факт просят ширины: 24 часа и длинные имена услуг
     в колонке 320 px нечитаемы. */
  .rap-kort.bred { grid-column: span 2; }
}
