/* ============================================================
   Кит как прислан — токены и компоненты, извлечённые из
   styleguide.html БЕЗ ИЗМЕНЕНИЙ.

   Отдельным файлом, чтобы направление 8 могло собираться из
   готовых классов кита (.card, .btn, .badge, .tbl, .side,
   .topbar, .desktop-frame), а не из моего пересказа этих
   классов. «Максимально из того, что прислано» — значит и
   компоненты его, а не только цвета.

   Здесь НЕТ слоя правки-контраста.css. Это сознательно: это
   версия «как есть», со всеми её числами, включая те девять
   пар, на которые ругается contrast-check.py из того же
   комплекта.
   ============================================================ */

/* ===== TOKENS ===== */
:root{
  color-scheme:light dark;
  --app-primary:#666cff;--app-primary-rgb:102,108,255;--app-primary-hover:#5c61e6;--app-primary-on:#fff;
  --app-secondary:#6d788d;--app-secondary-rgb:109,120,141;
  --app-success:#72e128;--app-success-rgb:114,225,40;
  --app-danger:#ff4d49;--app-danger-rgb:255,77,73;
  --app-warning:#fdb528;--app-warning-rgb:253,181,40;
  --app-info:#26c6f9;--app-info-rgb:38,198,249;
  --app-indigo:#666cff;--app-blue:#26c6f9;--app-cyan:#28c3d7;--app-teal:#20c997;--app-green:#72e128;
  --app-yellow:#ffd950;--app-orange:#fdb528;--app-red:#ff4d49;--app-pink:#e83e8c;--app-purple:#6f42c1;

  --app-font-sans:"Inter",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  --app-font-mono:"SFMono-Regular",Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
  --app-fw-regular:400;--app-fw-medium:500;--app-fw-semibold:600;--app-fw-bold:700;
  --app-fs-tiny:.75rem;--app-fs-sm:.8125rem;--app-fs-base:.9375rem;
  --app-fs-h6:.9375rem;--app-fs-h5:1.125rem;--app-fs-h4:1.473rem;--app-fs-h3:1.695rem;
  --app-fs-h2:2.252rem;--app-fs-h1:2.697rem;--app-fs-display:3.699rem;
  --app-lh-tight:1.1;--app-lh-body:1.375;--app-lh-head:1.56;--app-ls-wide:.4px;--app-ls-label:.2px;

  --app-space-1:.25rem;--app-space-2:.5rem;--app-space-3:.75rem;--app-space-4:1rem;
  --app-space-5:1.25rem;--app-space-6:1.5rem;--app-space-8:2rem;--app-space-10:2.5rem;--app-space-12:3rem;
  --app-card-padding:1.25rem;--app-grid-gutter:1.5rem;

  --app-radius-sm:.25rem;--app-radius:.375rem;--app-radius-lg:.5rem;
  --app-radius-xl:.625rem;--app-radius-2xl:1rem;--app-radius-pill:50rem;

  --app-border-width:1px;--app-focus-ring-width:.15rem;
  --app-dur-instant:100ms;--app-dur-fast:150ms;--app-dur-base:200ms;
  --app-dur-moderate:250ms;--app-dur-slow:300ms;--app-dur-slower:500ms;
  --app-ease-standard:cubic-bezier(.4,0,.2,1);--app-ease-out:cubic-bezier(0,0,.2,1);--app-ease-in-out:ease-in-out;
  --app-t-button:color var(--app-dur-fast) var(--app-ease-in-out),background-color var(--app-dur-fast) var(--app-ease-in-out),border-color var(--app-dur-fast) var(--app-ease-in-out),box-shadow var(--app-dur-fast) var(--app-ease-in-out);
  --app-t-input:border-color var(--app-dur-fast) var(--app-ease-in-out),box-shadow var(--app-dur-fast) var(--app-ease-in-out);
  --app-t-card:box-shadow var(--app-dur-slow) var(--app-ease-in-out),transform var(--app-dur-slow) var(--app-ease-in-out);
  --app-t-item:background-color var(--app-dur-base) var(--app-ease-in-out),color var(--app-dur-base) var(--app-ease-in-out);
  --app-sidebar-w:16.25rem;--app-navbar-h:4rem;--app-container-max:1392px;--app-navbar-blur:blur(7.5px);
}
:root,[data-theme=light]{
  --app-bg:#f7f7f9;--app-surface:#fff;--app-surface-alt:#f2f3f4;
  --app-text:#676a7b;--app-heading:#3b4055;--app-text-muted:#a8aab4;--app-text-faint:rgba(103,106,123,.5);
  --app-border:rgba(38,43,67,.12);--app-border-soft:rgba(38,43,67,.075);--app-divider:#e9e9ec;
  --app-gray-25:#fafafa;--app-gray-50:#f2f3f4;--app-gray-75:#eeeef0;--app-gray-100:#e9e9ec;
  --app-gray-200:#d4d5d9;--app-gray-300:#bdbfc6;--app-gray-400:#a8aab4;--app-gray-500:#9295a1;
  --app-gray-600:#7d808e;--app-gray-700:#676a7b;--app-gray-800:#515569;--app-gray-900:#3b4055;
  --app-primary-subtle:#e7e7ff;--app-primary-subtle-text:#292b66;--app-primary-subtle-border:#c3c6ff;
  --app-success-subtle:#e8fadd;--app-success-subtle-text:#2e5a10;--app-success-subtle-border:#c8f3ab;
  --app-danger-subtle:#ffe3e2;--app-danger-subtle-text:#661f1d;--app-danger-subtle-border:#ffbab8;
  --app-warning-subtle:#fff3dd;--app-warning-subtle-text:#654810;--app-warning-subtle-border:#fee2ab;
  --app-info-subtle:#dcf6fe;--app-info-subtle-text:#0f4f64;--app-info-subtle-border:#aae9fd;
  --app-secondary-subtle:#e8e9ed;--app-secondary-subtle-text:#2c3038;--app-secondary-subtle-border:#c6cad3;
  --app-menu-bg:#f7f7f9;--app-menu-color:#3b4055;--app-menu-hover-bg:rgba(38,43,67,.05);
  --app-navbar-bg:rgba(255,255,255,.85);--app-link:#666cff;--app-link-hover:#5c61e6;--app-code:#e83e8c;
  --app-shadow-xs:0 .125rem .375rem 0 rgba(38,43,67,.14);
  --app-shadow-sm:0 .125rem .625rem 0 rgba(38,43,67,.16);
  --app-shadow:0 .25rem .875rem 0 rgba(38,43,67,.16);
  --app-shadow-lg:0 .375rem 1.25rem 0 rgba(38,43,67,.18);
  --app-shadow-xl:0 .5rem 1.625rem 0 rgba(38,43,67,.18);
  --app-shadow-float:0 1px 16px 1px rgba(38,43,67,.09);
  --app-shadow-primary:0 2px 6px 0 rgba(var(--app-primary-rgb),.14);
}
[data-theme=dark]{
  --app-bg:#282a42;--app-surface:#30334e;--app-surface-alt:#3b3e58;
  --app-text:#b2b3ca;--app-heading:#d7d8ee;--app-text-muted:#7b7d95;--app-text-faint:rgba(178,179,202,.5);
  --app-border:rgba(234,234,255,.12);--app-border-soft:rgba(255,255,255,.09);--app-divider:#434660;
  --app-gray-25:#333851;--app-gray-50:#3b3e58;--app-gray-75:#3e415c;--app-gray-100:#434660;
  --app-gray-200:#555871;--app-gray-300:#696b84;--app-gray-400:#7b7d95;--app-gray-500:#8d8ea7;
  --app-gray-600:#9fa0b8;--app-gray-700:#b2b3ca;--app-gray-800:#c5c5dc;--app-gray-900:#d7d8ee;
  --app-primary-subtle:#393c6a;--app-primary-subtle-text:#a3a7ff;--app-primary-subtle-border:#5358c1;
  --app-success-subtle:#3b4f48;--app-success-subtle-text:#aaed7e;--app-success-subtle-border:#5ba435;
  --app-danger-subtle:#51374d;--app-danger-subtle-text:#ff9492;--app-danger-subtle-border:#b7444b;
  --app-warning-subtle:#514848;--app-warning-subtle-text:#fed37e;--app-warning-subtle-border:#b58835;
  --app-info-subtle:#2e4b69;--app-info-subtle-text:#7dddfb;--app-info-subtle-border:#2a93bd;
  --app-secondary-subtle:#3a3e58;--app-secondary-subtle-text:#a7aebb;--app-secondary-subtle-border:#586077;
  --app-menu-bg:#282a42;--app-menu-color:#d7d8ee;--app-menu-hover-bg:rgba(234,234,255,.06);
  --app-navbar-bg:rgba(48,51,78,.85);--app-link:#a3a7ff;--app-link-hover:#acb0ff;--app-code:#f18bba;
  --app-shadow-xs:0 .125rem .375rem 0 rgba(16,17,33,.2);
  --app-shadow-sm:0 .125rem .625rem 0 rgba(16,17,33,.24);
  --app-shadow:0 .25rem .875rem 0 rgba(16,17,33,.26);
  --app-shadow-lg:0 .375rem 1.25rem 0 rgba(16,17,33,.28);
  --app-shadow-xl:0 .5rem 1.625rem 0 rgba(16,17,33,.3);
  --app-shadow-float:0 1px 16px 1px rgba(255,255,255,.09);
  --app-shadow-primary:0 2px 6px 0 rgba(var(--app-primary-rgb),.3);
}

/* ===== KEYFRAMES ===== */
@keyframes app-dropdown-in{from{opacity:0;transform:translateY(-.5rem)}to{opacity:1;transform:none}}
@keyframes app-fade-in{from{opacity:0}to{opacity:1}}
@keyframes app-spin{to{transform:rotate(360deg)}}
@keyframes app-grow{0%{transform:scale(0);opacity:0}50%{opacity:1}100%{transform:none;opacity:0}}
@keyframes app-pulse-dot{0%,100%{box-shadow:0 0 0 0 rgba(var(--app-success-rgb),.55)}70%{box-shadow:0 0 0 .5rem rgba(var(--app-success-rgb),0)}}
@keyframes app-skeleton{100%{background-position:-200% 0}}
@keyframes app-stripes{0%{background-position-x:1rem}}
@keyframes app-rise-in{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}}

/* ===== BASE ===== */
*{box-sizing:border-box}
body{margin:0;background:var(--app-bg);color:var(--app-text);
  font-family:var(--app-font-sans);font-size:var(--app-fs-base);line-height:var(--app-lh-body);
  transition:background-color var(--app-dur-slow) var(--app-ease-in-out),color var(--app-dur-slow) var(--app-ease-in-out);
  -webkit-font-smoothing:antialiased}
h1,h2,h3,h4,h5,h6{color:var(--app-heading);font-weight:var(--app-fw-medium);margin:0 0 .5rem}
h1{font-size:var(--app-fs-h1);line-height:1.58}h2{font-size:var(--app-fs-h2);line-height:1.56}
h3{font-size:var(--app-fs-h3);line-height:1.55}h4{font-size:var(--app-fs-h4);line-height:1.61}
h5{font-size:var(--app-fs-h5);line-height:1.56}h6{font-size:var(--app-fs-h6);line-height:1.47}
p{margin:0 0 .75rem}
a{color:var(--app-link);text-decoration:none;transition:color var(--app-dur-fast) var(--app-ease-in-out)}
a:hover{color:var(--app-link-hover)}
code{font-family:var(--app-font-mono);font-size:.8125rem;color:var(--app-code);
  background:var(--app-gray-25);padding:.1rem .3rem;border-radius:var(--app-radius-sm)}
.muted{color:var(--app-text-muted)}
.small{font-size:var(--app-fs-sm)}
.caps{font-size:var(--app-fs-tiny);text-transform:uppercase;letter-spacing:var(--app-ls-wide);
  color:var(--app-text-muted);font-weight:var(--app-fw-medium)}

/* ===== LAYOUT ===== */
.wrap{display:flex;min-height:100vh}
.side{width:var(--app-sidebar-w);flex:0 0 var(--app-sidebar-w);background:var(--app-menu-bg);
  border-right:1px solid var(--app-border);padding:1.25rem .75rem;position:sticky;top:0;height:100vh;overflow-y:auto}
.brand{display:flex;align-items:center;gap:.625rem;padding:0 .5rem 1.25rem;color:var(--app-heading);
  font-size:1.125rem;font-weight:var(--app-fw-semibold)}
.brand .mark{width:32px;height:32px;border-radius:var(--app-radius-lg);flex:0 0 32px;
  background:linear-gradient(135deg,var(--app-primary),#8b90ff);box-shadow:var(--app-shadow-primary)}
.side .caps{padding:.75rem .5rem .25rem}
.nav a{display:block;padding:.4375rem .75rem;border-radius:var(--app-radius-lg);color:var(--app-menu-color);
  font-size:var(--app-fs-base);margin-bottom:.25rem;transition:var(--app-t-item)}
.nav a:hover{background:var(--app-menu-hover-bg);color:var(--app-heading)}
.nav a.active{background:var(--app-primary);color:#fff;box-shadow:var(--app-shadow-primary)}
.main{flex:1;min-width:0}
.topbar{position:sticky;top:0;z-index:20;height:var(--app-navbar-h);display:flex;align-items:center;
  justify-content:space-between;padding:0 1.5rem;background:var(--app-navbar-bg);
  backdrop-filter:var(--app-navbar-blur);-webkit-backdrop-filter:var(--app-navbar-blur);
  border-bottom:1px solid var(--app-border-soft);border-radius:0 0 var(--app-radius-xl) var(--app-radius-xl)}
.content{padding:1.5rem;max-width:var(--app-container-max)}
section{margin-bottom:3rem;scroll-margin-top:5rem}
.sec-head{margin-bottom:1.25rem;padding-bottom:.75rem;border-bottom:1px solid var(--app-border)}
.grid{display:grid;gap:var(--app-grid-gutter)}
.g2{grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.g3{grid-template-columns:repeat(auto-fit,minmax(220px,1fr))}
.g4{grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}
.row{display:flex;flex-wrap:wrap;gap:.75rem;align-items:center}

/* ===== CARD ===== */
.card{background:var(--app-surface);border-radius:var(--app-radius-xl);box-shadow:var(--app-shadow);
  padding:var(--app-card-padding);transition:var(--app-t-card);animation:app-rise-in .4s var(--app-ease-out) both}
.card.hoverable:hover{box-shadow:var(--app-shadow-lg);transform:translateY(-2px)}
.card-title{font-size:var(--app-fs-h5);color:var(--app-heading);font-weight:var(--app-fw-medium);margin-bottom:.25rem}

/* ===== BUTTONS ===== */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.375rem;
  font-family:inherit;font-size:var(--app-fs-base);font-weight:var(--app-fw-medium);
  letter-spacing:var(--app-ls-wide);text-transform:capitalize;line-height:1.375;
  padding:.5625rem 1.25rem;border-radius:var(--app-radius);border:1px solid transparent;
  cursor:pointer;transition:var(--app-t-button);position:relative;overflow:hidden;
  -webkit-user-select:none;user-select:none;background:transparent;color:var(--app-text)}
.btn:focus-visible{outline:none;box-shadow:0 0 0 var(--app-focus-ring-width) rgba(var(--app-primary-rgb),.35)}
.btn-sm{padding:.4375rem .96rem;font-size:var(--app-fs-sm);border-radius:var(--app-radius)}
.btn-lg{padding:.52rem 1.625rem;font-size:1.0625rem;border-radius:var(--app-radius-xl)}
.btn-primary{background:var(--app-primary);border-color:var(--app-primary);color:#fff;box-shadow:var(--app-shadow-primary)}
.btn-primary:hover{background:var(--app-primary-hover);border-color:var(--app-primary-hover);box-shadow:0 4px 10px 0 rgba(var(--app-primary-rgb),.28)}
.btn-success{background:var(--app-success);border-color:var(--app-success);color:#fff;box-shadow:0 2px 6px 0 rgba(var(--app-success-rgb),.2)}
.btn-danger{background:var(--app-danger);border-color:var(--app-danger);color:#fff;box-shadow:0 2px 6px 0 rgba(var(--app-danger-rgb),.2)}
.btn-outline{border-color:var(--app-primary);color:var(--app-primary)}
.btn-outline:hover{background:var(--app-primary);color:#fff}
.btn-tonal{background:var(--app-primary-subtle);color:var(--app-primary-subtle-text)}
.btn-tonal:hover{background:var(--app-primary);color:#fff}
.btn-ghost{color:var(--app-primary)}
.btn-ghost:hover{background:var(--app-primary-subtle)}
.btn-icon{padding:.5rem;width:38px;height:38px;border-radius:var(--app-radius-lg)}
.ripple{position:absolute;border-radius:50%;width:100px;height:100px;margin:-50px 0 0 -50px;
  pointer-events:none;transform:scale(0);opacity:.6;
  background:radial-gradient(rgba(255,255,255,.2) 0,rgba(255,255,255,.35) 40%,rgba(255,255,255,.5) 60%,rgba(255,255,255,0) 70%);
  animation:rip var(--app-dur-slower) var(--app-ease-out) forwards}
.btn-outline .ripple,.btn-ghost .ripple,.btn-tonal .ripple{
  background:radial-gradient(rgba(var(--app-primary-rgb),.2) 0,rgba(var(--app-primary-rgb),.35) 40%,rgba(var(--app-primary-rgb),.5) 60%,rgba(255,255,255,0) 70%)}
@keyframes rip{to{transform:scale(3.5);opacity:0}}

/* ===== BADGES ===== */
.badge{display:inline-flex;align-items:center;gap:.35rem;padding:.325rem .5rem;
  font-size:var(--app-fs-sm);font-weight:var(--app-fw-medium);border-radius:var(--app-radius);line-height:1.2}
.badge.pill{border-radius:var(--app-radius-pill);padding:.325rem .75rem}
.b-primary{background:var(--app-primary-subtle);color:var(--app-primary-subtle-text)}
.b-success{background:var(--app-success-subtle);color:var(--app-success-subtle-text)}
.b-danger{background:var(--app-danger-subtle);color:var(--app-danger-subtle-text)}
.b-warning{background:var(--app-warning-subtle);color:var(--app-warning-subtle-text)}
.b-info{background:var(--app-info-subtle);color:var(--app-info-subtle-text)}
.b-secondary{background:var(--app-secondary-subtle);color:var(--app-secondary-subtle-text)}
.b-solid-primary{background:var(--app-primary);color:#fff}
.dot{width:8px;height:8px;border-radius:50%;flex:0 0 8px}
.dot-live{background:var(--app-success);animation:app-pulse-dot 2s var(--app-ease-in-out) infinite}

/* ===== FORMS ===== */
.field{margin-bottom:1rem}
.label{display:block;font-size:var(--app-fs-base);font-weight:var(--app-fw-medium);
  color:var(--app-heading);margin-bottom:.5rem}
.input,.select{width:100%;height:48px;padding:.79rem .94rem;font-family:inherit;font-size:var(--app-fs-base);
  color:var(--app-heading);background:transparent;border:1px solid var(--app-gray-300);
  border-radius:var(--app-radius-lg);transition:var(--app-t-input);outline:none}
.input::placeholder{color:var(--app-text-muted)}
.input:focus,.select:focus{border-color:var(--app-primary);box-shadow:0 0 0 .15rem rgba(var(--app-primary-rgb),.18)}
.input.err{border-color:var(--app-danger)}
.input.err:focus{box-shadow:0 0 0 .15rem rgba(var(--app-danger-rgb),.18)}
.help{font-size:var(--app-fs-sm);color:var(--app-text-muted);margin-top:.375rem}
.help.err{color:var(--app-danger)}
.switch{position:relative;display:inline-block;width:42px;height:24px}
.switch input{opacity:0;width:0;height:0}
.slider{position:absolute;inset:0;background:var(--app-gray-300);border-radius:999px;cursor:pointer;
  transition:background-color var(--app-dur-base) var(--app-ease-in-out)}
.slider::before{content:"";position:absolute;width:18px;height:18px;left:3px;top:3px;background:#fff;
  border-radius:50%;box-shadow:var(--app-shadow-xs);transition:transform var(--app-dur-base) var(--app-ease-in-out)}
.switch input:checked+.slider{background:var(--app-primary)}
.switch input:checked+.slider::before{transform:translateX(18px)}

/* ===== TABLE ===== */
.tbl{width:100%;border-collapse:collapse}
.tbl th{padding:1rem 1.25rem;text-align:left;font-size:var(--app-fs-tiny);font-weight:var(--app-fw-regular);
  text-transform:uppercase;letter-spacing:var(--app-ls-label);color:var(--app-heading);
  border-bottom:1px solid var(--app-border)}
.tbl td{padding:.78rem 1.25rem;font-size:var(--app-fs-base);border-bottom:1px solid var(--app-border-soft)}
.tbl tbody tr{transition:background-color var(--app-dur-base) var(--app-ease-in-out)}
.tbl tbody tr:hover{background:var(--app-gray-25)}
.tbl tbody tr:last-child td{border-bottom:0}

/* ===== MISC ===== */
.swatch{border-radius:var(--app-radius-lg);overflow:hidden;box-shadow:var(--app-shadow-xs);background:var(--app-surface)}
.swatch .chip{height:72px}
.swatch .meta{padding:.625rem .75rem;font-size:var(--app-fs-sm)}
.swatch .meta b{display:block;color:var(--app-heading);font-weight:var(--app-fw-medium)}
.swatch .meta span{font-family:var(--app-font-mono);font-size:.75rem;color:var(--app-text-muted)}
.avatar{border-radius:50%;background:linear-gradient(135deg,var(--app-primary),#8b90ff);
  display:inline-flex;align-items:center;justify-content:center;color:#fff;font-weight:var(--app-fw-medium);
  position:relative;flex:0 0 auto}
.avatar .st{position:absolute;right:0;bottom:0;width:10px;height:10px;border-radius:50%;
  border:2px solid var(--app-surface)}
.stat-icon{width:40px;height:40px;border-radius:var(--app-radius-lg);display:inline-flex;
  align-items:center;justify-content:center;font-size:1.125rem}
.spinner{width:32px;height:32px;border:3px solid var(--app-primary-subtle);border-top-color:var(--app-primary);
  border-radius:50%;animation:app-spin .75s linear infinite}
.skeleton{height:14px;border-radius:var(--app-radius-sm);
  background:linear-gradient(90deg,var(--app-gray-100) 25%,var(--app-gray-75) 37%,var(--app-gray-100) 63%);
  background-size:200% 100%;animation:app-skeleton 1.4s linear infinite}
.progress{height:8px;background:var(--app-gray-100);border-radius:var(--app-radius-pill);overflow:hidden}
.progress i{display:block;height:100%;background:var(--app-primary);border-radius:inherit;
  transition:width var(--app-dur-base) var(--app-ease-in-out)}
.progress.striped i{background-image:linear-gradient(45deg,rgba(255,255,255,.18) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.18) 50%,rgba(255,255,255,.18) 75%,transparent 75%,transparent);
  background-size:1rem 1rem;animation:app-stripes 1s linear infinite}
.alert{padding:.875rem 1rem;border-radius:var(--app-radius-lg);font-size:var(--app-fs-base);
  border:1px solid transparent}
.a-primary{background:var(--app-primary-subtle);color:var(--app-primary-subtle-text);border-color:var(--app-primary-subtle-border)}
.a-success{background:var(--app-success-subtle);color:var(--app-success-subtle-text);border-color:var(--app-success-subtle-border)}
.a-danger{background:var(--app-danger-subtle);color:var(--app-danger-subtle-text);border-color:var(--app-danger-subtle-border)}
.a-warning{background:var(--app-warning-subtle);color:var(--app-warning-subtle-text);border-color:var(--app-warning-subtle-border)}
.shadow-demo{height:88px;background:var(--app-surface);border-radius:var(--app-radius-xl);
  display:flex;align-items:flex-end;justify-content:center;padding-bottom:.5rem;font-size:var(--app-fs-sm)}
.radius-demo{height:72px;background:var(--app-primary-subtle);display:flex;align-items:center;
  justify-content:center;color:var(--app-primary-subtle-text);font-size:var(--app-fs-sm);font-family:var(--app-font-mono)}
.space-bar{background:var(--app-primary);height:16px;border-radius:2px}
.motion-box{width:56px;height:56px;border-radius:var(--app-radius-lg);background:var(--app-primary);
  box-shadow:var(--app-shadow-primary)}
.demo-tile{background:var(--app-surface-alt);border:1px dashed var(--app-border);border-radius:var(--app-radius-lg);
  padding:1rem;text-align:center}
.id-field{font-family:var(--app-font-mono);font-size:var(--app-fs-h3);letter-spacing:3px;
  color:var(--app-heading);font-weight:var(--app-fw-medium)}
.desktop-frame{background:var(--app-surface);border:1px solid var(--app-border);border-radius:var(--app-radius-lg);
  overflow:hidden;box-shadow:var(--app-shadow-lg)}
.desktop-frame .tb{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;
  background:var(--app-surface-alt);border-bottom:1px solid var(--app-border);font-size:var(--app-fs-sm)}
.hero{border-radius:var(--app-radius-2xl);padding:3rem 2rem;text-align:center;color:#fff;
  background:linear-gradient(135deg,#666cff 0%,#8b90ff 55%,#a3a7ff 100%);box-shadow:var(--app-shadow-xl)}
@media(max-width:900px){.side{display:none}}

/* ============================================================
   Deskee — направление 9, слой правок поверх кита

   Направление 9 выбрано владельцем (ПЛАН-ЗАПУСКА.md, раздел 6.3).
   Сам кит подключается отдельно и дословно: кит-компоненты.css.
   Здесь — только то, что мы поверх него меняем.

   ЗАЧЕМ ОТДЕЛЬНЫМ ФАЙЛОМ. До этого правки жили ВНУТРИ страницы
   «Кит — направление 9 (вычищенный).html» — то есть в одном из двух
   набросков, которые лежат рядом ради сравнения «как прислан» и
   «вычищенный». Пара 8 против 9 обязана остаться нетронутой, а всё
   новое — приложение, сайт, кабинет — не может брать стили копированием
   из наброска: копии расходятся молча. Файл наброска не тронут, правки
   отсюда ему повторяют то же самое.

   ВСЕ ЧИСЛА НИЖЕ ИЗМЕРЕНЫ, а не взяты на глаз: contrast-check.py и
   аудит-кита.py из того же каталога.
   ============================================================ */

/* Единственная правка самого кита, и она не про вкус: text-transform:
   capitalize у кнопок. В английском приём нормальный, по-русски даёт
   «Оставить Заявку На Пилот». */
.btn { text-transform: none; }

/* ВТОРИЧНЫЙ ТЕКСТ. Светлая #a8aab4 — 2.31 на белом, 2.16 на фоне
   приложения; тёмная #7b7d95 — 3.05 на карточке. Минимум 4.5.
   Стало: 5.08 / 4.75 и 4.90 / 5.58. */
:root, [data-theme="light"] { --app-text-muted: #6b6e79; }
[data-theme="dark"]         { --app-text-muted: #a0a2ba; }

/* ССЫЛКИ. #666cff как текст — 4.07 на белом и 3.81 на фоне приложения,
   то есть ссылка читается хуже обычного текста. #5257e0: 5.53 и 5.17.
   Тот же цвет, что у сплошной кнопки, — одно значение вместо двух. */
:root, [data-theme="light"] { --app-link: #5257e0; --app-link-hover: #4348c4; }
/* И обязательно вернуть тёмной теме её собственную ссылку: :root
   матчится ВСЕГДА, и без этой строки в тёмной теме ссылки становятся
   тёмно-индиговыми на тёмном фоне — 1.98 вместо китовых 5.57.
   Правило, выведенное на этой ошибке: правишь токен темы — правь обе. */
[data-theme="dark"] { --app-link: #a3a7ff; --app-link-hover: #acb0ff; }

/* Белый текст на сплошном индиго — те же 4.07. */
.nav a.active, .b-solid-primary { background: #5257e0; }
.btn-outline:hover { background: #5257e0; }

/* Герой: белый на градиенте давал 2.79 в середине и 2.20 на светлом
   конце. Сдвигаем градиент в глубину — светлый конец теперь 5.53. */
.hero { background: linear-gradient(135deg, #4348c4 0%, #5257e0 100%); }

/* Аватары: белые инициалы на светлом конце давали 2.79. */
.avatar { background: linear-gradient(135deg, #4348c4, #5257e0); }

/* ГРАНИЦЫ ЭЛЕМЕНТОВ УПРАВЛЕНИЯ — не украшение: по границе человек
   понимает, где поле ввода. Было 1.84 в светлой и 2.36 в тёмной при
   пороге 3:1 (WCAG 1.4.11). Стало 3.23 и 3.05. Границы карточек и
   разделители таблиц НЕ трогаем — правило 3:1 к ним не относится, а
   поднять их значило бы убить мягкость, ради которой кит и выбран. */
:root, [data-theme="light"] { --app-gray-300: #8b8f9c; }
[data-theme="dark"]         { --app-gray-300: #7b7d95; }

/* Подсветка строки таблицы при наведении была 1.04 — то есть её нет. */
.tbl tbody tr:hover { background: var(--app-gray-50); }

/* ФОКУС С КЛАВИАТУРЫ. В ките он объявлен только у кнопки и поля ввода;
   у ссылок и пунктов меню нет вовсе, а у переключателя невозможен —
   сам флажок нулевого размера с opacity: 0, показывать нечего. */
a:focus-visible, .nav a:focus-visible {
  outline: 2px solid var(--app-primary); outline-offset: 2px;
  border-radius: var(--app-radius-sm);
}
.switch input:focus-visible + .slider {
  outline: 2px solid var(--app-primary); outline-offset: 2px;
}

/* Кит объявляет color-scheme: light dark и при этом сам переключает тему
   атрибутом. Из-за этого системные полосы прокрутки и выпадающие списки
   следуют настройке ОС, а не странице. Привязываем к теме. */
:root, [data-theme="light"] { color-scheme: light; }
[data-theme="dark"]         { color-scheme: dark; }

/* ============================================================
   ДОБАВЛЕНО ПОВЕРХ НАПРАВЛЕНИЯ 9 — сплошные кнопки

   В наброске 9 этого нет, и это не придирка: набросок — страница, на
   которой сплошных кнопок почти не встречается. В приложении они несут
   главные действия, и обе не проходят порог.

     белый на .btn-primary  #666cff — 4.07   (нужно 4.5)
     белый на .btn-danger   #ff4d49 — 3.28

   Красная — это «Прервать подключение», та самая, которую человек ищет
   в тревоге. Значения берём из правки-контраста.css, где они уже были
   выведены для направления 7: 5.53 и 5.67.

   Сам #666cff остаётся для заливок, графиков и теней: там контраст
   текста ни при чём.
   ============================================================ */
:root, [data-theme="light"] {
  --app-primary-solid: #5257e0;
  --app-danger-solid:  #c62622;
  --app-danger-text:   #a4142f;   /* 7.72 на белом, 6.38 на danger-subtle */
}
[data-theme="dark"] {
  /* На тёмном фоне кнопка СВЕТЛЕЕ фона, и затемнять её незачем. */
  --app-primary-solid: #666cff;
  --app-danger-solid:  #c62622;
  --app-danger-text:   #ff9492;
}
.btn-primary { background: var(--app-primary-solid); border-color: var(--app-primary-solid); }
.btn-primary:hover { background: #4348c4; border-color: #4348c4; }
[data-theme="dark"] .btn-primary:hover { background: var(--app-primary-hover); border-color: var(--app-primary-hover); }
.btn-danger  { background: var(--app-danger-solid);  border-color: var(--app-danger-solid); }
.btn-danger:hover { background: #a81f1c; border-color: #a81f1c; }

/* .btn-success и .btn-warning сплошными НЕ ПОЛЬЗУЕМСЯ вовсе: белый на
   китовом зелёном даёт 1.68, на жёлтом — 1.78. Это не чинится
   подкруткой оттенка, это другой цвет. Успех и предупреждение
   показываем мягкими бейджами (.b-success, .b-warning) — там текст
   тёмный и контраст в порядке. */

/* ============================================================
   ДОБАВЛЕНО ПОВЕРХ НАПРАВЛЕНИЯ 9 — надписи кнопок без заливки

   Найдено на макете приложения: .btn-ghost, .btn-outline и .btn-tonal
   красят надпись в --app-primary #666cff, и это ровно тот случай, что
   уже чинили у ссылок, — только там правился токен --app-link, а кнопки
   берут цвет отдельно и правку не увидели.

     #666cff на белом                     — 4.07   (нужно 4.5)
     #666cff на фоне приложения #f7f7f9   — 3.81
     #666cff на тёмной поверхности        — 3.02
     #666cff на тёмном фоне               — 3.44

   Ставим тот же цвет, что у ссылки: одно значение вместо двух.

     #5257e0 на белом 5.53, на фоне 5.17, на tonal-подложке 4.55
     #a3a7ff на тёмной поверхности 5.57, на тёмном фоне 6.35, tonal 4.70

   Заливку .btn-outline и его границу не трогаем: у границы порог 3:1,
   и 4.07 его проходит. */
.btn-ghost, .btn-outline, .btn-tonal { color: var(--app-link); }
.btn-tonal:hover, .btn-outline:hover { color: #fff; }
.btn-ghost:hover { color: var(--app-link-hover); }

/* ============================================================
   Шрифт приложения — отдельным файлом нарочно.

   Его подключает ТОЛЬКО посредник: файлы шрифтов лежат у него и
   отдаются по /font/<имя>. Агент ту же страницу отдаёт при прямом
   подключении, но шрифтов у него нет — и объявления, ссылающиеся в
   никуда, дали бы шесть напрасных запросов и шесть же ошибок в
   консоли. Проще не объявлять: кит откатится на Segoe UI, то есть на
   тот шрифт, которым Windows рисует всё остальное.
   ============================================================ */

@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/font/Inter-400-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/font/Inter-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap;
  src: url(/font/Inter-500-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap;
  src: url(/font/Inter-500-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap;
  src: url(/font/Inter-600-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap;
  src: url(/font/Inter-600-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}


/* ============================================================
   Deskee — слой приложения поверх кита

   Порядок подключения (собирается посредником в /style.css):
     1. кит-компоненты.css   — кит, дословно
     2. направление-9.css    — наш слой правок, общий с сайтом
     3. приложение.css       — этот файл: то, чего в ките нет

   Кит — про страницу. Здесь то, что бывает только в программе: верхняя
   полоса окна, строка машины, жалоба машины на саму себя. Ничего из
   этого в ките нет и быть не может.

   Правило по цветам: сюда не попадает ни одного значения цвета. Всё —
   через токены. Иначе следующая правка контраста опять пройдёт мимо
   половины интерфейса, как уже случилось с кнопками.
   ============================================================ */

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--app-bg);
  color: var(--app-text);
  font: var(--app-fs-base)/var(--app-lh-body) var(--app-font-sans);
  -webkit-font-smoothing: antialiased;
}

/* ---------- верхняя полоса ---------- */
.полоса {
  display: flex; align-items: center; gap: 16px;
  padding: 0 16px; height: var(--app-navbar-h);
  background: var(--app-surface);
  border-bottom: 1px solid var(--app-border);
  /* Полоса не уезжает при прокрутке списка: поле «подключиться к номеру»
     нужно ровно тогда, когда номер продиктовали, — то есть в любой момент. */
  position: sticky; top: 0; z-index: var(--app-z-navbar);
}
.марка { display: flex; align-items: center; gap: 10px;
         color: var(--app-heading); font-weight: var(--app-fw-medium); }
.марка .знак { width: 30px; height: 30px; flex: 0 0 30px;
               border-radius: var(--app-radius-lg);
               background: linear-gradient(135deg, #4348c4, #5257e0);
               color: #fff; display: grid; place-items: center;
               font-weight: var(--app-fw-semibold); }
.свой { display: flex; flex-direction: column; gap: 1px;
        padding-left: 16px; border-left: 1px solid var(--app-border); }
/* Свой display перебивает штатное действие атрибута hidden, и без этой
   строки подпись «этот компьютер» висит в браузере без числа под ней —
   то есть ровно то, чего hidden и должен был не допустить. */
.свой[hidden] { display: none; }
.свой .что { font-size: var(--app-fs-tiny); text-transform: uppercase;
             letter-spacing: var(--app-ls-wide); color: var(--app-text-muted); }
.цифры { font-family: var(--app-font-mono); letter-spacing: 1px;
         color: var(--app-heading); font-size: 1.0625rem; }
.тяга { margin-left: auto; }
/* Кто вошёл — слева от поля номера: это не действие, а состояние, и место
   ему рядом с тем, кого оно описывает. */
.вошёл { display: flex; align-items: center; gap: 8px; }
.кто-пара { display: flex; flex-direction: column; line-height: 1.2; }
.имя-вошедшего { color: var(--app-heading); font-weight: var(--app-fw-medium); }

/* Полоса «вход пропал» живёт в ленте, как и ожидание входа: обе — про
   состояние страницы, а не про машину в списке. */
#вход-пропал { margin-bottom: 14px; }
#вход-пропал[hidden] { display: none; }

/* Ожидание подтверждения. Полосой над списком, а не окном поверх: человек в
   это время смотрит в браузер и сверяет число, и модальное окно, которое надо
   закрывать, только мешало бы. */
.ждём-вход { display: flex; align-items: center; justify-content: space-between;
             gap: 16px; padding: 14px 16px; margin-bottom: 14px; }
.ждём-вход[hidden] { display: none; }
.сверка-строка { display: flex; align-items: center; gap: 10px; margin-top: 6px; }
.сверка { font-family: var(--app-font-mono); font-size: var(--app-fs-h4);
          letter-spacing: 4px; color: var(--app-heading); }

.строка-ввода { display: flex; gap: 8px; align-items: center; margin: 0; }
.строка-ввода .input { width: 11em; height: 38px;
                       font-family: var(--app-font-mono); letter-spacing: 1px; }

/* ---------- список ---------- */
.лента { padding: 18px 20px 32px; }
.шапка-списка { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.шапка-списка h2 { margin: 0; font-size: var(--app-fs-h5);
                   color: var(--app-heading); font-weight: var(--app-fw-medium); }
.машины { list-style: none; margin: 0; padding: 0; }

/* Строка машины. Плотная нарочно: машин у оператора десятки, и он ищет
   одну известную, а не разглядывает все. Плитки на том же экране
   помещают втрое меньше — сравнение лежит в дизайн/Приложение — макет.html. */
.машина {
  display: grid; align-items: center; gap: 4px 14px;
  grid-template-columns: 10px minmax(0, 1fr) auto auto auto;
  padding: 10px 12px; border-radius: var(--app-radius-lg);
  border-bottom: 1px solid var(--app-border-soft);
}
.машина:hover { background: var(--app-gray-25); }
.машина .имя { color: var(--app-heading); font-weight: var(--app-fw-medium);
               text-decoration: none; overflow: hidden;
               text-overflow: ellipsis; white-space: nowrap; }
.машина .имя:hover { color: var(--app-link); }
.машина .имя.как-номер { font-family: var(--app-font-mono);
                         font-weight: var(--app-fw-regular); letter-spacing: 1px; }
.машина .номер { font-family: var(--app-font-mono); font-size: var(--app-fs-sm);
                 color: var(--app-text-muted); letter-spacing: .5px; }
.машина .верс { font-size: var(--app-fs-sm); color: var(--app-text-muted); }
.машина .кнопки { display: flex; gap: 6px; align-items: center; justify-content: flex-end; }
.машина.офлайн .имя { color: var(--app-text-muted); font-weight: var(--app-fw-regular); }

/* Жалоба машины на саму себя — своя строка во всю ширину: длинный текст
   ошибки не должен ужимать имя и номер до нечитаемого. */
.машина .жалоба, .машина .замечание {
  grid-column: 2 / -1; font-size: var(--app-fs-sm);
}
.машина .жалоба { color: var(--app-danger-text); }
/* Работает, но хуже, чем могло бы: не тревога, а замечание. Мягче
   красного намеренно — иначе через неделю на красное перестанут смотреть.
   Токен парный: в светлой теме он тёмно-коричневый (7.89 на фоне
   приложения), в тёмной — песочный (9.89). Одно имя, обе темы. */
.машина .замечание { color: var(--app-warning-subtle-text); }
.точка { width: 8px; height: 8px; border-radius: 50%; background: var(--app-gray-300); }
.точка.жива { background: var(--app-success); }
/* Пульсация — только у машины, которую сейчас смотрят. Пульсирующий
   список целиком не сообщает ничего: мигает всё, значит не мигает ничто. */
.точка.смотрят { background: var(--app-primary);
                 animation: app-pulse-dot 2s var(--app-ease-in-out) infinite; }

.пусто { color: var(--app-text-muted); padding: 8px 12px; }

/* ---------- поле правки имени ---------- */
.правка { height: 34px; padding: 0 10px; width: 14em;
          font-family: inherit; font-size: var(--app-fs-base);
          color: var(--app-heading); background: var(--app-surface);
          border: 1px solid var(--app-gray-300); border-radius: var(--app-radius); }
.правка:focus { outline: none; border-color: var(--app-primary);
                box-shadow: var(--app-focus-ring); }

/* ---------- внутри нашего приложения ----------
   С версии 1.35.0 полосу рисует эта страница, и прятать её не надо.
   А до неё её рисовало само окно нативными элементами Windows — и там
   вторая такая же в странице означала бы два одинаковых поля подряд.

   Отсюда двойное условие. Признак `в-приложении` ставят ОБЕ версии,
   `своя-полоса` — только новая. Прячем ровно тем, кто рисует полосу сам.
   Одного признака на оба смысла хватило бы, чтобы новая страница оставила
   старый агент без полосы вовсе: ни своей, ни нативной, то есть без поля
   ввода и без номера. Машины в поле обновляются не в один день, и страница
   у них общая — она на сервере. */
.в-приложении:not(.своя-полоса) .полоса { display: none; }
.в-приложении:not(.своя-полоса) .лента { padding-top: 14px; }

@media (max-width: 720px) {
  .полоса { height: auto; padding: 10px 12px; flex-wrap: wrap; }
  .свой { padding-left: 0; border-left: 0; }
  .машина { grid-template-columns: 10px minmax(0, 1fr) auto; }
  .машина .верс { display: none; }
  .строка-ввода { width: 100%; }
  .строка-ввода .input { flex: 1; width: auto; }
}


/* ============================================================
   Экран сеанса — то, что видно, пока смотрят чужой компьютер.

   КОМНАТА ВСЕГДА ТЁМНАЯ, независимо от темы системы: страница ставит
   себе data-theme="dark" и не спрашивает никого. Причина не в моде —
   рама обязана уступить чужому экрану. Светлая полоса вокруг тёмного
   чужого окна спорит с ним за внимание и сбивает оценку цвета на той
   стороне, а разглядывают тут именно её.
   ============================================================ */

/* Полоса сеанса. Плотнее, чем в адресной книге: здесь она отнимает высоту
   у картинки, ради которой всё и открыто. */
#bar {
  padding: 7px 14px;
  background: var(--app-surface);
  border-bottom: 1px solid var(--app-border);
  font-size: var(--app-fs-sm);
  color: var(--app-text);
}
/* Ряды заданы разметкой, а не переносом: см. комментарий в index.html. */
#bar .ряд { display: flex; align-items: center; gap: 14px; min-height: 30px; }
#bar .ряд.низ { gap: 16px; margin-top: 2px; }
#назад { color: var(--app-link); text-decoration: none; white-space: nowrap; }
#назад:hover { color: var(--app-link-hover); text-decoration: underline; }

/* Кого смотрим. Имя берётся из адресной книги оператора, номер — из адреса
   страницы: человек, которому звонят с вопросом «а вы к кому подключены»,
   не должен искать это в другом окне. */
#кто { display: flex; align-items: center; gap: 8px; color: var(--app-heading);
       font-weight: var(--app-fw-medium); }
#кто .номер { font-family: var(--app-font-mono); font-weight: var(--app-fw-regular);
              color: var(--app-text-muted); letter-spacing: .5px; }
.точка { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px;
         background: var(--app-gray-300); }
.точка.жива { background: var(--app-success); }

#status { color: var(--app-text); }
.dim { color: var(--app-text-muted); }
/* Счётчики — диагностика, и живут во втором ряду вместе с подсказкой.
   Длинная строка («всего 12 запл + 3 из кеша + …») в общем ряду расталкивала
   кнопку файла вниз. Обрезаем по ширине окна, а не переносим: высота шапки
   отнимается у картинки. */
#stats { font-family: var(--app-font-mono); font-size: var(--app-fs-tiny);
         overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.тяга { margin-left: auto; }

/* Переключатели монитора и вида. Кнопки рисует скрипт, разметку менять
   нельзя — поэтому стили висят на том же, на чём и раньше: на потомках
   полок и на классе «вот-этот». */
#вид, #экраны { display: flex; align-items: center; gap: 6px; }
#вид button, #экраны button {
  font: inherit; cursor: pointer;
  padding: 4px 10px; border-radius: var(--app-radius);
  background: transparent; color: var(--app-text);
  border: 1px solid var(--app-gray-300);
}
#вид button:hover, #экраны button:hover { color: var(--app-heading); }
#вид button.вот-этот, #экраны button.вот-этот {
  background: var(--app-primary-solid); border-color: var(--app-primary-solid); color: #fff;
}

#file { display: none; }

/* Картинка чужого экрана. Ниже — геометрия, а не оформление: эти правила
   про то, где что лежит, и переписывать их под дизайн нечего. */

/* Обёртка обязана обнимать холст по фактическому размеру: слой курсора
   позиционируется по ней, и растянись она на всю ширину — курсор уехал бы от
   картинки при вписывании.
   БЛОЧНАЯ с width: fit-content, а НЕ inline-block. Проверено 18.08.2026:
   со строчным блоком под картинкой оставался зазор под нижние выносные
   элементы строки, и в режиме «вписать» вылезала полоса прокрутки на
   несколько точек — ровно та мелочь, ради устранения которой режим и нужен. */
#stack { position: relative; line-height: 0; display: block; width: fit-content; }
#screen, #pointer { display: block; }
#screen { cursor: crosshair; background: #000; }
/* Курсор живёт отдельным слоем поверх экрана. На основной холст его рисовать
   нельзя: кеш вырезает тайлы именно оттуда и запомнил бы их с курсором.
   Тянем его ровно по обёртке — она уже равна картинке. */
#pointer { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

/* ВПИСАТЬ: весь чужой экран целиком, с полями по краям, если пропорции
   разошлись. Ограничиваем и по ширине, и по высоте — иначе высокий экран
   вылезал бы вниз и его приходилось бы прокручивать, а смысл режима ровно в
   том, чтобы видеть всё сразу.
   Высоту шапки НЕ пишем числом: она переносится на две строки на узком окне
   и на появлении переключателя мониторов. Проверено 18.08.2026 — вместо
   ожидаемых 42 точек она оказалась 80, и полоса прокрутки осталась. Настоящую
   высоту измеряет скрипт и кладёт сюда. */
body.вписать #screen { max-width: 100vw; max-height: calc(100vh - var(--шапка, 80px));
                       width: auto; height: auto; }
/* ОДИН В ОДИН: пиксель в пиксель, страница прокручивается. Нужен, когда
   разбираешь мелкий текст и любое масштабирование его портит. */
body.один-в-один #screen { max-width: none; max-height: none;
                           width: auto; height: auto; }

/* Подсветка при перетаскивании: без неё непонятно, поймает ли страница файл. */
body.drop #stack { outline: 3px dashed var(--app-primary); outline-offset: -3px; }

/* ЗАПРОС КОДА. Раньше это был браузерный prompt(). В браузере он просто
   некрасив, а внутри нашего приложения оказался прямо вредным: диалог
   подписан «Сообщение с desk.it-ontime.ru», то есть выглядит как чужой сайт,
   влезший в программу. Ровно этому человека и учат не доверять.
   Своя форма заодно снимает старую оговорку: prompt в некоторых окружениях
   заблокирован, и тогда спросить код было нечем вовсе. */
#кодовое { position: fixed; inset: 0; z-index: var(--app-z-modal); display: flex;
           align-items: center; justify-content: center; background: rgba(0, 0, 0, .66); }
/* Свой display: flex перебивает штатное действие атрибута hidden, и без
   этой строки форма не пряталась бы вовсе. */
#кодовое[hidden] { display: none; }
#кодформа { width: min(420px, calc(100vw - 32px));
            background: var(--app-surface); border-radius: var(--app-radius-xl);
            box-shadow: var(--app-shadow-xl); padding: 22px 24px; }
#кодтекст { margin: 0 0 14px; color: var(--app-text);
            font-size: var(--app-fs-base); line-height: 1.6; }
#кодполе { width: 100%; height: 52px; text-align: center;
           font-family: var(--app-font-mono); font-size: var(--app-fs-h4);
           letter-spacing: 8px;
           background: var(--app-bg); color: var(--app-heading);
           border: 1px solid var(--app-gray-300); border-radius: var(--app-radius-lg); }
#кодполе:focus { outline: none; border-color: var(--app-primary);
                 box-shadow: var(--app-focus-ring); }
#кодформа .кнопки { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }

@media (max-width: 720px) {
  #bar { gap: 10px; }
  #stats, #подсказка { display: none; }
}
