/* SiteRadar — reset, primitives and page chrome (docs/handoff/IMPLEMENTATION.md §1, §2, §5, §6).
 *
 * Loaded after tokens.css and before the page sheet (cabinet.css | auth.css).
 * Every colour, radius, shadow and type role comes from a token: this file must
 * contain no literal colour. CSP forbids inline styles, so a visual state is a
 * class, never a style attribute.
 *
 * Class dictionary (docs/DESIGN_PROGRESS.md, docs/LOADER_MODAL_PROGRESS.md):
 * .container .logo .brand .btn .field .check .pill .stats/.stat .card .notice
 * .glow .hdr .foot .cookie .sr-only .spinner .progress .modal */

/* ---- reset & base ---------------------------------------------------------- */

*,
*::before,
*::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/* The UA rule `[hidden]{display:none}` loses to any author `display` (author
   styles beat UA styles), so `el.hidden = true` must win explicitly. */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-base);
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); text-decoration: underline; }

input, button, select, textarea { font-family: inherit; letter-spacing: inherit; }
input::placeholder, textarea::placeholder { color: var(--text-4); }

/* ---- accessibility (§6) ---------------------------------------------------- */

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- motion ---------------------------------------------------------------- */

/* THE ONLY ANIMATIONS IN THE SYSTEM (LOADER_AND_MODAL.md, «Общее»). Nothing
   else declares @keyframes: a component picks one of these five by name.
   sr-spin  — the 13px ring under the search field (.spinner)
   sr-slide — the indeterminate progress runner (.progress__bar)
   sr-fade  — the modal backdrop appearing (.modal)
   sr-pop   — the dialog rising into place (.modal__dialog)
   sr-check — the green tick scaling in (.modal__check) */
@keyframes sr-spin { to { transform: rotate(360deg); } }
@keyframes sr-slide { 0% { transform: translateX(-100%); } 100% { transform: translateX(340%); } }
@keyframes sr-fade { 0% { opacity: 0; } 100% { opacity: 1; } }
@keyframes sr-pop {
  0% { opacity: 0; transform: translateY(14px) scale(.97); }
  100% { opacity: 1; transform: none; }
}
@keyframes sr-check {
  0% { opacity: 0; transform: scale(.6); }
  60% { transform: scale(1.08); }
  100% { opacity: 1; transform: scale(1); }
}

/* One switch for all of it (§6). `animation: none` wins over every `both`
   fill-mode above, so an element that would animate simply renders its final
   state; `transition: none` freezes --t-bg and --t-progress the same way. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
    scroll-behavior: auto !important;
  }
}

/* ---- layout ---------------------------------------------------------------- */

/* Both shells are a full-height column, so the footer of a short page (/docs/…,
   the error page) sits at the bottom of the window instead of leaving a white
   band under it. .shell-auth does the same a few rules below, with its own
   padding and centring. */
.shell-app {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
/* The one growing item. `width: 100%` is load-bearing: the `margin: 0 auto` main
   carries (cabinet.css) is an auto cross-axis margin, which switches off the
   stretch of a flex item — without the explicit width a short page would shrink
   its column to fit-content instead of holding the 1088 band. */
.shell-app > main { flex: 1 0 auto; width: 100%; }

.container {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--container-pad);
}

/* The hero glow.
 *
 * CONTRACT for whoever paints it: the parent must be `position: relative;
 * overflow: hidden` — .hero (cabinet.css) and .glow-host (below) are the two
 * such parents. Body must not be the clipper: `overflow` on body propagates to
 * the viewport and would kill scrolling.
 *
 * TRAP: a page that lifts its children above the glow with `.hero > *
 * { position: relative }` silently kills it — that selector has the same
 * specificity as `.glow` here and wins by order, turning the ellipse into an
 * empty inline. Always exclude it: `.hero > :not(.glow)` — as cabinet.css does,
 * and as .shell-auth does for .glow-host below. */
.glow {
  position: absolute;
  left: 50%;
  top: var(--glow-top);
  width: var(--glow-w);
  height: var(--glow-h);
  transform: translateX(-50%);
  border-radius: 50%;
  background: var(--glow);
  pointer-events: none;
}

.glow-host {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 300px;
  overflow: hidden;
  pointer-events: none;
}

/* ---- logo (03-logo.html, variant 03) --------------------------------------- */

.logo {
  display: grid;
  place-items: center;
  flex: none;
  background: var(--logo-gradient);
  color: var(--on-accent);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-logo);
}

.logo--16 { width: 16px; height: 16px; border-radius: var(--r-logo-16); font-size: var(--fs-logo-16); box-shadow: var(--shadow-logo-16); }
.logo--22 { width: 22px; height: 22px; border-radius: var(--r-logo-22); font-size: var(--fs-logo-22); box-shadow: var(--shadow-logo-22); }
.logo--30 { width: 30px; height: 30px; border-radius: var(--r-logo-30); font-size: var(--fs-logo-30); box-shadow: var(--shadow-logo-30); }
.logo--52 { width: 52px; height: 52px; border-radius: var(--r-logo-52); font-size: var(--fs-logo-52); box-shadow: var(--shadow-logo-52); }

.brand {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text);
  font-size: var(--fs-brand);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-tight);
  text-decoration: none;
}
.brand:hover { color: var(--text); text-decoration: none; }
.brand--lg { gap: 11px; font-size: var(--fs-brand-lg); }

/* ---- button ---------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--tap);
  padding: 12px 22px;
  /* No border: in the mock-up only the ghost variant has one, and a transparent
     1px on the base made every solid button 2px taller than the design. */
  border: 0;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--on-accent);
  font-size: var(--fs-md);
  line-height: var(--lh-tight);
  font-weight: var(--fw-med);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: var(--t-bg);
}
.btn:hover { background: var(--accent-hover); color: var(--on-accent); text-decoration: none; }

.btn--primary { background: var(--accent); color: var(--on-accent); }
.btn--primary:hover { background: var(--accent-hover); color: var(--on-accent); }

/* --accent-hover, not --accent: blue text on the 10% blue fill needs 4.5:1 (§6). */
.btn--soft { background: var(--accent-soft); color: var(--accent-hover); }
.btn--soft:hover { background: var(--accent-soft-hover); color: var(--accent-hover); }

.btn--ghost { background: transparent; color: var(--text); border: 1px solid var(--hairline-strong); }
.btn--ghost:hover { background: var(--fill-2); color: var(--text); }

.btn--block { display: flex; width: 100%; font-size: var(--fs-btn); }

.btn[disabled],
.btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }
.btn.is-loading,
.btn[aria-busy="true"] { opacity: .6; cursor: progress; }

/* A submit/button that must read as a plain link (the "Выйти" form of the header). */
.link {
  padding: 0;
  border: 0;
  background: none;
  line-height: var(--lh-tight);
  color: var(--accent);
  font: inherit;
  letter-spacing: inherit;
  cursor: pointer;
}
.link:hover { color: var(--accent-hover); text-decoration: underline; }

/* ---- text field ------------------------------------------------------------ */

.field { display: block; }

.field__label {
  display: block;
  margin: 0 0 7px 2px;
  color: var(--text-2);
  font-size: var(--fs-cap);
  line-height: var(--lh-tight);
}
/* A label row that carries a trailing link ("Пароль … Забыли?"). */
.field__label--row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }

.field__input {
  width: 100%;
  min-height: var(--tap);
  padding: 14px 16px;
  border: 1px solid transparent;
  border-radius: var(--r-input);
  background: var(--surface-2);
  color: var(--text);
  font-size: var(--fs-input);
  transition: var(--t-bg);
}
.field__input:focus { border-color: var(--accent); background: var(--bg); }
.field__input[disabled] { opacity: .55; cursor: not-allowed; }

.field__error {
  margin: 7px 0 0 2px;
  color: var(--warn-text);
  font-size: var(--fs-cap);
  line-height: var(--lh-tight);
}

/* A caption under a field ("8–128 символов"). --text-3 gives 3.6:1 on white, so
   a caption that carries a rule uses --text-2 (§6 keeps --text-3/--text-4 for
   non-semantic labels). */
.field__hint {
  margin: 7px 0 0 2px;
  color: var(--text-2);
  font-size: var(--fs-cap);
  line-height: var(--lh-tight);
}

.field.has-error .field__input { border-color: var(--warn-text); }

/* ---- checkbox -------------------------------------------------------------- */

.check {
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--text-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-tight);
}
/* §6 asks for a 44px target "на тач"; with a mouse the extra 26px would only
   inflate the form, so the pointer type decides. */
@media (pointer: coarse) {
  .check { min-height: var(--tap); }
}
.check input {
  width: 16px;
  height: 16px;
  margin: 0;
  flex: none;
  accent-color: var(--accent);
}

/* ---- status pill ----------------------------------------------------------- */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  color: var(--text-2);
  font-size: var(--fs-pill);
  line-height: var(--lh-tight);
  font-weight: var(--fw-med);
  white-space: nowrap;
}
.pill--done { background: var(--ok-bg); color: var(--ok-text); }
.pill--manual { background: var(--warn-bg); color: var(--warn-text); }
/* --accent-hover for the same 4.5:1 reason as .btn--soft. */
.pill--running { background: var(--accent-soft); color: var(--accent-hover); }
/* Queued and cancelled are the same neutral grey: an ended state that costs the
   user nothing (the credit is back). The mock-up paints cancelled with the
   translucent --divider, but a see-through fill takes the contrast of whatever
   row it sits on — --text-2 on it is 4.44:1 over --bg-subtle, which is the
   hover of every row (.audits tbody tr:hover) — while the opaque --surface-2
   holds 4.66:1 on any background (§6, задача D5). */
.pill--queued,
.pill--cancelled { background: var(--surface-2); color: var(--text-2); }
/* Error: the warn palette (LOADER_AND_MODAL.md A5), which supersedes решение №8
   — a failed audit needs to read as a problem, not as a neutral end state. The
   refunded credit is what `cancelled` says, and that one stays grey. */
.pill--error { background: var(--warn-bg); color: var(--warn-text); }

/* ---- spinner (A1) ---------------------------------------------------------- */

/* The single ring of the page: it lives under the search field and nowhere else
   (LOADER_AND_MODAL.md A2 — «в строке ровно один индикатор — полоса»).
   `transparent` is the same stop as the mock-up's zero-alpha accent: a gradient
   interpolates in premultiplied alpha, so the fade stays blue instead of going
   through grey — and it costs no literal colour. */
.spinner {
  position: relative;
  width: 13px;
  height: 13px;
  flex: none;
  border-radius: 50%;
  background: conic-gradient(from 0deg, transparent, var(--accent));
  animation: sr-spin .9s linear infinite;
}
/* The hole. --bg, so the ring only reads on a white surface — which is where A1
   and the modal put it. */
.spinner::after {
  content: "";
  position: absolute;
  inset: 2px;
  border-radius: 50%;
  background: var(--bg);
}

/* ---- progress bar (A2) ----------------------------------------------------- */

/* CONTRACT: .progress pins itself to the top edge of its parent, so the parent
   must be `position: relative` (the running audit row, .card--flush cell, the
   /_ui track below). Markup:
     <span class="progress"><span class="progress__bar"></span></span>
   Add `progress--determinate data-percent="40"` and static/app.js
   (SiteRadar.progress.apply) sets the width through CSSOM — a style attribute
   is impossible under `style-src 'self'`.
   A11y: the indeterminate runner is decoration and takes `aria-hidden="true"`;
   a determinate one is `role="progressbar"` with aria-valuemin/max/now and a
   label, and apply() keeps aria-valuenow in step with the width (приёмка L5). */
.progress {
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 2px;
  background: var(--accent-soft);
  overflow: hidden;
}
.progress__bar {
  display: block;
  width: 30%;
  height: 100%;
  background: var(--accent);
  animation: sr-slide 1.5s cubic-bezier(.5, 0, .5, 1) infinite;
}
/* Gated on .js: without app.js the width can never be set, and a determinate
   bar would freeze at a meaningless 30%. Until then it keeps running. */
.js .progress--determinate .progress__bar {
  width: 0;
  animation: none;
  transition: var(--t-progress);
}

/* ---- metric cards ---------------------------------------------------------- */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
}

.stat {
  padding: 24px 26px;
  border-radius: var(--r-card);
  background: var(--surface-2);
}
.stat__num {
  margin: 0 0 8px;
  font-size: var(--fs-num);
  line-height: var(--lh-num);
  letter-spacing: var(--ls-num);
  font-weight: var(--fw-bold);
}
.stat__num--accent { color: var(--accent); }
.stat__label { margin: 0; color: var(--text-2); font-size: var(--fs-sm); line-height: var(--lh-tight); }

/* ---- card ------------------------------------------------------------------ */

.card {
  padding: 24px 26px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-card);
  background: var(--bg);
  box-shadow: var(--shadow-card);
}
/* A card whose children own the padding (the audits table). */
.card--flush { padding: 0; overflow: hidden; }

/* ---- notice ---------------------------------------------------------------- */

.notice {
  margin: 0 0 18px;
  padding: 14px 18px;
  border-radius: var(--r-card);
  background: var(--surface-2);
  color: var(--text);
  font-size: var(--fs-cap-2);
  line-height: var(--lh-cap);
}
.notice--ok { background: var(--ok-bg); color: var(--ok-text); }
/* Form and request errors are a warning, not a new colour (§1 has no error tone). */
.notice--warn { background: var(--warn-bg); color: var(--warn-text); }
.notice a { color: inherit; text-decoration: underline; }

/* ---- header ---------------------------------------------------------------- */

.hdr {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--glass);
  -webkit-backdrop-filter: var(--blur);
  backdrop-filter: var(--blur);
  border-bottom: 1px solid var(--hairline);
}

.hdr__inner {
  display: flex;
  align-items: center;
  gap: 26px;
  height: var(--hdr-h);
  font-size: var(--fs-cap-2);
  line-height: var(--lh-tight);
}

/* On >=768 the account panel dissolves so that its children are header flex
   items; `order` puts them back into the mock-up sequence (< 768 it becomes a
   dropdown, see the media query below). */
.hdr__panel { display: contents; }
.hdr .brand { order: 0; }
.hdr__nav { order: 1; display: flex; align-items: center; gap: 20px; }
.hdr__credits { order: 2; margin-left: auto; }
.hdr__email { order: 3; }
.hdr__logout { order: 4; margin: 0; }

.hdr__link { color: var(--text); font-size: var(--fs-cap-2); }
.hdr__link.is-active { opacity: .62; }
/* The only header link of a logged-out page ("Вход") sits on the right. */
.hdr__link--end { order: 2; margin-left: auto; }

.hdr__credits {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  background: var(--fill-2);
  color: var(--text);
  font-size: var(--fs-pill);
  text-decoration: none;
}
.hdr__credits:hover { color: var(--text); text-decoration: none; background: var(--hairline); }
.hdr__dot { width: 6px; height: 6px; flex: none; border-radius: 50%; background: var(--dot-live); }

/* .62, not .55: the mock-up's grey is 3.8:1 on the header glass, this is 4.7:1
   — the same value .hdr__link.is-active already uses (§6, R1 LOW-5). */
.hdr__email { color: var(--text); font-size: var(--fs-pill); opacity: .62; }
.hdr__logout .link { font-size: var(--fs-pill); }

.hdr__menu {
  order: 5;
  display: none;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  margin-right: -10px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
.hdr__menu span,
.hdr__menu span::before,
.hdr__menu span::after {
  display: block;
  width: 18px;
  height: 1.5px;
  border-radius: 2px;
  background: var(--text);
}
.hdr__menu span { position: relative; }
.hdr__menu span::before { content: ""; position: absolute; left: 0; top: -6px; }
.hdr__menu span::after { content: ""; position: absolute; left: 0; top: 6px; }

/* ---- footer ---------------------------------------------------------------- */

.foot {
  border-top: 1px solid var(--hairline);
  background: var(--bg-subtle);
}

.foot__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 32px;
  max-width: var(--container);
  margin: 0 auto;
  padding: 44px var(--container-pad) 40px;
}

.foot__col { display: flex; flex-direction: column; gap: 9px; font-size: var(--fs-cap); line-height: var(--lh-tight); }
.foot__col a { color: var(--text-2); }
.foot__col a:hover { color: var(--accent-hover); }
.foot__title { color: var(--text); font-weight: var(--fw-med); margin-bottom: 2px; }

.foot__brand { margin-bottom: 12px; }
.foot__about {
  margin: 0;
  max-width: 38ch;
  color: var(--text-2);
  font-size: var(--fs-cap-2);
  line-height: var(--lh-cap-2);
}

.foot__bottom {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  max-width: var(--container);
  margin: 0 auto;
  padding: 20px var(--container-pad) 40px;
  border-top: 1px solid var(--divider);
  /* Both halves of the line are meaningful text (the © notice and the licence
     number / entity / INN), so both run at --text-2 = 4.9:1 on --bg-subtle;
     --text-4 would be 2.5:1 (§6, задача D5). */
  color: var(--text-2);
  font-size: var(--fs-pill);
  line-height: var(--lh-tight);
}
.foot__legal { margin-left: auto; }

/* ---- cookie banner --------------------------------------------------------- */

.cookie {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  display: flex;
  justify-content: center;
  padding: 16px 16px 20px;
  pointer-events: none;
}

.cookie__panel {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  width: 100%;
  max-width: 760px;
  padding: 16px 18px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-card);
  background: var(--glass-strong);
  -webkit-backdrop-filter: var(--blur);
  backdrop-filter: var(--blur);
  box-shadow: var(--shadow-cookie);
  pointer-events: auto;
}

.cookie__text {
  flex: 1;
  min-width: 240px;
  margin: 0;
  color: var(--text);
  font-size: var(--fs-cap-2);
  line-height: var(--lh-cap);
}

.cookie__actions { display: flex; gap: 8px; flex: none; }
/* 13.5px and the mock-up's paddings (ghost 18, primary 20); the height stays
   at the 44px touch target of §6 instead of the mock-up's 38. */
.cookie__actions .btn { padding: 10px 18px; font-size: var(--fs-cap-2); }
.cookie__actions .btn--primary { padding-right: 20px; padding-left: 20px; }

/* The /_ui demo shows the panel in the flow instead of pinning it to the viewport. */
.cookie--inline { position: static; justify-content: flex-start; padding: 0; }

/* ---- modal (feature B) ----------------------------------------------------- */

/* Overlay + centred dialog. z-index 60 over the banner's 40, and static/app.js
   still holds the banner back: while a [data-cookie-banner] is on screen an
   open() is queued until the sr:consent event (LOADER_AND_MODAL.md B).
   `[hidden]{display:none!important}` at the top of this file is what closes it,
   so no .modal[hidden] rule of its own is needed — `el.hidden = true` wins over
   this `display: flex`. */
.modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  overflow-y: auto;
  background: var(--overlay);
  -webkit-backdrop-filter: blur(var(--blur-modal));
  backdrop-filter: blur(var(--blur-modal));
  animation: sr-fade .22s ease-out both;
}

/* Set on <html> while a modal is open, so the page behind it does not scroll. */
.is-modal { overflow: hidden; }

/* `margin: auto` and not only the `align-items` of the overlay: auto margins
   centre a flex item without the clipping a centred item suffers once it grows
   taller than the scroll port (a long domain on a 375-wide phone). */
.modal__dialog {
  width: 100%;
  max-width: 420px;
  margin: auto;
  padding: 34px 32px 26px;
  border-radius: var(--r-modal);
  background: var(--bg);
  text-align: center;
  box-shadow: var(--shadow-modal);
  animation: sr-pop .3s cubic-bezier(.2, .9, .3, 1) both;
}

.modal__check {
  display: grid;
  place-items: center;
  width: 60px;
  height: 60px;
  margin: 0 auto 20px;
  border-radius: 50%;
  background: var(--ok-bg);
  animation: sr-check .38s cubic-bezier(.2, .9, .3, 1) .08s both;
}
/* The tick: two borders of an empty box rotated −45°, no icon font, no SVG. */
.modal__check::after {
  content: "";
  display: block;
  width: 20px;
  height: 11px;
  border-left: 2.6px solid var(--ok-text);
  border-bottom: 2.6px solid var(--ok-text);
  border-radius: 1px;
  transform: rotate(-45deg) translate(1px, -2px);
}

.modal__title {
  margin: 0 0 8px;
  font-size: var(--fs-modal-title);
  line-height: var(--lh-tight);
  letter-spacing: var(--ls-modal-title);
  font-weight: var(--fw-bold);
}

.modal__text {
  margin: 0 0 6px;
  color: var(--text-2);
  font-size: var(--fs-modal-text);
  line-height: var(--lh-modal-text);
}
.modal__text strong { color: var(--text); font-weight: var(--fw-med); }

/* Sits on .pill, so the palette comes from .pill--manual | --done | --error. */
.modal__pill {
  margin: 0 0 24px;
  padding: 6px 13px;
  font-size: var(--fs-cap);
}

.modal__actions { display: flex; flex-direction: column; gap: 9px; }
/* The only control of the dialog is a little taller than the base button (the
   mock-up spends 15px of padding on it instead of 12/22). */
.modal__actions .btn { padding: 15px; }

/* The "Позже" text button: a pill-shaped hit area with no fill and no border. */
.modal__later {
  padding: 11px;
  border: 0;
  border-radius: var(--r-pill);
  background: none;
  color: var(--accent);
  font-size: var(--fs-modal-later);
  line-height: var(--lh-tight);
  font-weight: var(--fw-med);
  cursor: pointer;
}
.modal__later:hover { color: var(--accent-hover); }

/* --text-4 of the mock-up is 2.6:1 — a footnote still carries meaning (§6, D5). */
.modal__note {
  margin: 16px 0 0;
  color: var(--text-2);
  font-size: var(--fs-pill);
  line-height: var(--lh-tight);
}

/* ---- auth shell (login / register; the card itself is auth.css) ------------- */

.shell-auth {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 100vh;
  padding: 64px var(--container-pad) 48px;
  background: var(--bg-subtle);
}
/* Everything but the glow host is lifted above the glow; excluding it here is
   what keeps `.glow-host { position: absolute }` alive (see the .glow trap).
   The cookie banner is excluded for the same reason: this selector outranks
   `.cookie { position: fixed }` and used to pin the panel into the flow of the
   auth page instead of to the bottom of the window (задача D5). .modal is on the
   list for the same reason, before it ever reaches this shell. */
.shell-auth > :not(.glow-host):not(.cookie):not(.modal) { position: relative; }

.auth-main { width: 100%; max-width: 420px; margin-top: 52px; }

.auth__foot {
  margin-top: auto;
  padding-top: 56px;
  max-width: 520px;
  text-align: center;
}
.auth__about { margin: 0 0 12px; color: var(--text-2); font-size: var(--fs-cap); line-height: var(--lh-cap); }
.auth__links {
  display: flex;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
  margin: 0 0 10px;
  font-size: var(--fs-pill);
  line-height: var(--lh-tight);
}
/* --text-3 gives 3.5:1 on --bg-subtle; these four are navigation, not decoration. */
.auth__links a { color: var(--text-2); }
.auth__links a:hover { color: var(--accent-hover); }
/* Same as .foot__bottom: © plus the requisites, all of it meaningful (§6). */
.auth__legal { margin: 0; color: var(--text-2); font-size: var(--fs-fine); line-height: var(--lh-tight); }

/* ---- touch targets (§6) ---------------------------------------------------- */

/* "Все интерактивные элементы — минимум 44px по высоте на тач". With a mouse the
   extra height would only inflate the chrome, so the pointer type decides — the
   same rule .check and .audits__btn already follow.
   Scope: controls and navigation link lists. An inline link inside a sentence
   (.cookie__text a, .auth__note a, .doc__text a) keeps the height of its line
   box: growing it would break the paragraph, not the target. */
@media (pointer: coarse) {
  /* The only control of the dialog without a min-height of its own. */
  .modal__later { min-height: var(--tap); }

  .hdr .brand,
  .shell-auth > .brand,
  .hdr__link,
  .hdr__credits,
  .hdr__logout .link,
  .foot__col a,
  .auth__links a {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
  }
  /* The stacked link lists keep the mock-up's rhythm: the 44px boxes overlap the
     9px gap instead of adding to it. */
  .foot__col { gap: 0; }
  .auth__links { gap: 0 14px; }

  /* "Пароль … Забыли?": the trailing link is a control of its own, so the label
     row becomes the target and gives back the 7px it used to spend on a margin. */
  .field__label--row {
    align-items: center;
    min-height: var(--tap);
    margin-bottom: 0;
  }
  .field__label--row a { display: inline-flex; align-items: center; min-height: var(--tap); }
}

/* ---- responsive (§5) ------------------------------------------------------- */

/* 768–1040: the container is the window width — .container already does that. */

@media (max-width: 767.98px) {
  .hdr__inner { gap: 12px; }
  .hdr__nav { gap: 16px; }
  .hdr__menu { display: grid; }

  /* The account panel becomes a dropdown under the header. Without JS it stays
     a visible block (the links must never be unreachable); app.js marks the
     document with .js and only then the panel is collapsed until .is-open. */
  .hdr__panel {
    position: absolute;
    left: 0; right: 0; top: 100%;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
    padding: 14px var(--container-pad) 18px;
    /* Opaque, not --glass: a backdrop-filter inside an element that already has
       one (the header) has no page behind it to blur, and the links would be
       unreadable over the content. */
    background: var(--bg);
    border-bottom: 1px solid var(--hairline);
    box-shadow: var(--shadow-card);
  }
  .js .hdr__panel { display: none; }
  .js .hdr.is-open .hdr__panel { display: flex; }

  .foot__grid { grid-template-columns: minmax(0, 1fr); gap: 28px; padding-top: 36px; }
  .foot__legal { margin-left: 0; }

  .cookie { padding: 10px 10px 12px; }
  .cookie__panel { max-width: none; }
  .cookie__actions { width: 100%; }
  .cookie__actions .btn { flex: 1; }

  /* < 768: the dialog takes the width of the screen inside a 16px gutter. */
  .modal { padding: 16px; }
  .modal__dialog { max-width: none; }

  .shell-auth { padding-top: 44px; }
  .auth-main { margin-top: 36px; }
  .auth__foot { padding-top: 44px; }
}

/* ---- /_ui showcase (dev page only; a few pixels of scaffolding) ------------- */

.ui-note { color: var(--text-2); font-size: var(--fs-cap-2); line-height: var(--lh-cap-2); }
.ui-note code { font-size: var(--fs-cap); }

.ui-row { display: flex; align-items: flex-start; gap: 18px; flex-wrap: wrap; margin: 0 0 18px; }
.ui-row--baseline { align-items: flex-end; gap: 26px; }
.ui-row--wide { display: block; max-width: 420px; }

.ui-item { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 7px; }
.ui-item--wide { display: flex; }

.ui-label { color: var(--text-2); font-size: var(--fs-pill); }

.ui-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 18px; margin: 0 0 18px; }
.ui-grid .ui-label { display: block; margin-top: 7px; }

/* Stand-ins for the two hosts the cabinet provides in real markup: the caption
   under the search field (A1) and the audit row the bar pins itself to (A2). */
.ui-hint {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: var(--text-2);
  font-size: var(--fs-cap);
  line-height: var(--lh-tight);
}
.ui-track {
  position: relative;
  display: block;
  width: 100%;
  padding: 18px 24px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-card);
  background: var(--bg-subtle);
  color: var(--text-2);
  font-size: var(--fs-cap);
  line-height: var(--lh-tight);
  overflow: hidden;
}
