/* ---- Self-hosted brand font (spec §13.6). Falls back to Georgia if absent.
   Latin covers the "Perecle" wordmark; Cyrillic covers the "Перекл" footer
   mark (M3). Both subsets are same-origin — no external CDN. ---- */
@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/static/fonts/source-serif-4-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;
}
@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/static/fonts/source-serif-4-600-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* Weight 400 is the footer mini-wordmark "Perecle" (design/ResultsScreen.html);
   the browser cannot synthesize a lighter weight from the 600 face, so ship the
   400 subsets too. Same-origin subsets — no external CDN. */
@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/source-serif-4-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: "Source Serif 4";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/static/fonts/source-serif-4-400-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* ============================================================================
   Perecle web-search desktop redesign (PRC-833, design/redesign-2026-09/).

   Self-contained stylesheet for the redesigned SEARCH pages only (start,
   results, 404/429): fonts, tokens and every component they render. Pages
   still living on the 2026-08 design keep loading perecle.css — one page,
   one of the two files, never both. perecle.css itself is not modified.

   Owner decisions baked in (PRC-833):
   - the account circle in the capsule is replaced by the theme circle;
   - the footer is gone entirely (theme switcher moved into the capsule);
   - Картинки/account circles are off with their feature flags.
   Keyboard focus outlines are not in the mockups (owner backlog) — the
   existing :focus-visible rings are preserved, not extended. */

/* ---- Fonts (byte-identical @font-face set to perecle.css: the base.html
   preload URL must match the src here without ?v=) ---- */

/* ---- [hidden] wins, always (PRC-836).

   The UA sheet hides [hidden] with a plain `display: none`, so ANY author rule
   that sets `display` on the same element defeats it: the element keeps its
   box while templates and JS believe it is gone. That is not a hypothetical —
   an audit of every [hidden] element on every page found eight live cases,
   among them a red «Удалить» sitting next to «Сохранить» in the menu dialog.

   Fixing them one selector at a time only holds until the next `display` rule
   is written, so the guard is global and carries `!important`: it has to beat
   compound selectors too. Safe by inspection — no rule in any stylesheet ever
   makes a [hidden] element visible on purpose, and no script writes
   `style.display`. Per-element guards below are now redundant; they are kept
   as documentation of intent and cost nothing.

   Show an element by REMOVING the attribute, never by out-specifying it. ---- */
[hidden] { display: none !important; }

/* ---- Выключено — значит погашено, а не спрятано (PRC-839).

   Решение владельца 16.09.2026: «На проде должно быть как в макете,
   выключенные… Функции сейчас отключены, поэтому приглушены, но они должны
   быть. Кнопки пока что не прожимаются». Там, где функция снята флагом,
   макет РИСУЕТ её элемент — погашенным и ненажимаемым; прод убирал его из
   разметки и вместе с ним терял сам факт, что функция будет.

   Контракт — один атрибут data-soon на элементе, который ОСТАЁТСЯ в
   разметке вместо того, чтобы исчезнуть. Отсюда он берёт курсор «нельзя»;
   рядом с ним шаблон ставит aria-disabled="true" и title вида «Картинки —
   скоро», которым макет и объясняет состояние.

   Почему не pointer-events: none и не disabled — оба гасят и наведение, то
   есть и курсор, и всплывающую подсказку; объяснение пропало бы вместе с
   нажатием. Нажатие гасится иначе: у погашенного элемента нет своего
   обработчика, а делегированные слушатели отсеивают цель по тому же
   признаку — ровно одна такая точка на весь редизайн (summary.js, клики
   внутри лайтбокса пересказа).

   Тон — не здесь: погашенный элемент живёт на двух разных поверхностях, и
   одного цвета у класса нет (--soon-ink для пилюль и кружков сервисов,
   --soon-btn-* для кнопок в рамке). Форма одна, краска своя — поэтому тон
   стоит рядом со своим компонентом, а не в этом правиле.

   !important — по той же причине, что у [hidden] выше: у атрибута и класса
   вес одинаковый, а компонентные правила стоят ниже по файлу, и любое из них
   («.rmenu__pill { cursor: pointer }») забирает курсор себе. Без него
   защита держалась бы на порядке строк. Безопасно по построению: погашенный
   элемент не нажимается по определению, и «нельзя» для него верно всегда. */
[data-soon] { cursor: not-allowed !important; }

/* ---- Tokens. Same names as perecle.css where the value is shared, so the
   ported component blocks (iskra, summary, lightbox, translator) resolve
   without edits; new tokens carry the redesign-specific palette. ---- */
:root {
  --brand-font: "Source Serif 4", Georgia, serif;
  --u-rinput: 16px;
  --u-rpill: 12px;

  --content-col: 800px;
  /* The results header is WIDER than the result column: the bar is 848px and
     the capsule hangs 14px past its content box on each side, so the capsule
     ends up 828px against 800px of results (Results.dc.html). Two numbers,
     not one — reusing --content-col here made the capsule 752px. */
  --rheader-col: 848px;
  --page-pad: 24px;
  --summary-panel-w: 476px;

  /* ---- Light theme (default; mockup "светлая тема — токены прода") ---- */
  --bg-page: #edeae3;
  --surface: #ffffff;
  --border: #e7e3da;
  --border-card: #e7e3da;
  --text-strong: #1f1e1b;
  --text-body: #24211c;
  --result-title: #26355e;
  --result-snippet: #3a3630;
  --text-muted: #8a857a;
  --text-faint: #9a958b;
  --link-url: #54504a;
  --link-visited: #7c5c86;
  --spark: #c9694a;
  /* Mic while recording (VoiceInput.dc.html frame 02, [data-miclive]). */
  --spark-soft: rgba(201, 105, 74, .14);
  --spark-deep: #475377;
  --deep: #26355e;
  --on-deep: #ffffff;
  --danger: #b23c2e;
  --on-danger: #ffffff;
  --focus-ring: 3px solid rgba(38, 53, 94, .35);
  --hover-bg: rgba(31, 30, 27, .05);

  /* Capsule (results/search pill) — warm beige hover steps per mockup. */
  --cap-h: 60px;
  --cap-circle-bg: #efece5;
  --cap-circle-bg-hover: #e4dfd4;
  --cap-send-bg: #c9694a;
  --cap-send-hover: #c9694a;
  --cap-send-fg: #ffffff;
  --cap-hover: #f0ede6;
  --cap-tip-bg: #24211c;  /* подсказка кружка ряда (CapsuleRow 3) */
  --cap-tip-fg: #ffffff;
  --menu-pod-bg: #e3dfd5;
  --menu-pod-bg-pinned: rgba(227, 223, 213, .66);
  --menu-pill: #54504a;
  --menu-pill-active: #1f1e1b;
  --more-bg: #ffffff;
  --more-bg-hover: #f5f2ec;
  --sug-q: #8a857a;
  --sug-t: #24211c;
  --sug-hover: rgba(31, 30, 27, .05);
  --sug-spark: #c9694a;
  --sug-kbd-border: rgba(31, 30, 27, .09);
  --sug-kbd-hover-bg: rgba(31, 30, 27, .05);
  --sug-kbd-hover-border: rgba(31, 30, 27, .14);
  --sug-sep: #e7e3da;
  --startbar-hint: #8a857a;
  --startbar-toggle: #54504a;
  --startbar-mic: #54504a;
  /* Voice status strip (VoiceInput.dc.html): the status text and the
     recognizing dots carry their own fixed inks — the dots are one greige
     in BOTH themes, the dark status steps one shade below --text-muted. */
  --voice-status: #8a857a;
  --voice-dots: #a49c8e;
  /* Recording ring around the capsule (VoiceInput.dc.html frames 02-03):
     2px terracotta in both themes. */
  --voice-ring: 2px solid rgba(201, 105, 74, .22);
  /* Frame 01a «Включаю микрофон» (PRC-981): the mic between click and the
     engine's real onaudiostart gets its own grey-with-backdrop look — not
     idle grey (would read as inactive) and not the terracotta of a live
     tape (that would claim the mic is already recording, which is the bug). */
  --voice-connecting-bg: #efece5;
  --voice-connecting-fg: #54504a;
  --result-engines: #8a857a;
  --cap-glass-a: 1;
  --tone-sage: #26355e;
  --tone-lilac: #26355e;
  --tone-clay: #26355e;
  --result-site: #24211c;
  --result-path: #54504a;
  /* State screens (ResultsStates.dc.html frames 02-05): the display heading
     and the quiet caption/correction ink — one step deeper than --text-strong
     / --text-muted in the light theme (#100f0d / #6f6a60), the usual pair in
     the dark one (#f3f7ff / #8f96a6). */
  --state-title: #100f0d;
  --state-text: #6f6a60;
  --sum-active-bg: rgba(38, 53, 94, .07);
  /* Iskra failure states (IskraFailure.dc.html): the dimmed spark, the cut
     marker after the last written word, the rule under a broken answer. */
  --spark-off: #a49c8e;
  --caret-off: #b3aa99;
  --rule: #ece8e0;
  --fact-lead: #d8d2c6;
  /* Iskra card palette (IskraResults.dc.html light overrides) */
  --card-border: #e7e3da;
  --card-ink: #3a3630;
  --card-foot: #8a857a;
  --fact-value: #24211c;
  --chip-bg: #f2efe8;
  --chip-hover: #d8d2c6;
  --chip-ring: #e0dbd1;
  --chip-fg: #54504a;
  /* «Источники» label in the chips row (PRC-848): light keeps --text-muted's
     ink, dark steps one shade deeper (IskraAnswerDensity.dc.html [data-mut],
     Results.dc.html [data-meta]) — the same light/dark pair --result-engines
     carries. */
  --chips-title: #8a857a;
  --bubble-bg: #e3dfd5;
  --bubble-fg: #24211c;
  --photo-bg: #ece8e0;
  /* «Скоро» — выключенная флагом функция (PRC-839). Два тона, потому что
     погашенный элемент живёт на двух разных поверхностях: пилюля/кружок
     сервиса лежит на подложке без заливки (--soon-ink), кнопка панели
     лайтбокса — в своей рамке (--soon-btn-*). Числа сняты с
     Results.dc.html ([data-off]) и SummaryStates.dc.html. */
  --soon-ink: #8a857a;
  --soon-btn-ink: #b0aaa0;
  --soon-btn-bg: #faf8f4;
  --soon-btn-border: #ece8e0;
  /* Menu-items dialog (MenuItemsModal.dc.html): the light theme carries its
     own title ink, close ink, terracotta add button and a lighter card
     shadow/backdrop — dark reuses its current values unchanged. */
  --cmenu-title: #24211c;
  --cmenu-close: #54504a;
  --cmenu-add-ink: #a8512f;
  --cmenu-add-line: #dfd6c8;

  --cmenu-backdrop: rgba(31, 30, 27, .3);
  /* The editor's primary («Добавить»/«Сохранить») is TERRACOTTA in light
     (#c9694a on cream, hover #b95c3f); the grey #e2e6ee button is the
     mockup's dark base, not a theme-neutral default (acceptance return). */
  --cmenu-primary-bg: #c9694a;
  --cmenu-primary-fg: #fff8f4;
  --cmenu-primary-hover: #b95c3f;
  /* Icon picker (PRC-865, MenuItemsModal.dc.html data-icopt): the quiet tile
     and the lit «picked» step — light goes terracotta, dark lights the tile
     a white step up. */
  --cmenu-ic-bg: #f7f5f0;
  --cmenu-ic-line: #e7e3da;
  --cmenu-ic-ink: #54504a;
  --cmenu-ic-on-bg: rgba(201, 105, 74, .10);
  --cmenu-ic-on-line: #c9694a;
  --cmenu-ic-on-ink: #a8512f;
  /* List surface, row-icon tile, grip, inputs and delete/add hovers — the
     mock's rendered light theme (visual acceptance return, PRC-875):
     warmer tile #f4f1ea, quieter grip, cream inputs with a terracotta
     focus, accent-tinted add hover, terracotta delete ink. */
  --cmenu-list-bg: #faf8f4;
  --cmenu-list-line: #ebe6dc;
  --cmenu-icplate-bg: #f4f1ea;
  --cmenu-icplate-ink: #54504a;
  --cmenu-empty-ink: #54504a;
  --cmenu-grip-ink: #8a857a;
  --cmenu-input-bg: #f7f5f0;
  --cmenu-input-line: #e4dfd4;
  --cmenu-input-ink: #24211c;
  --cmenu-input-focus-line: #c9694a;
  --cmenu-input-focus-bg: #ffffff;
  --cmenu-danger-ink: #b0452b;
  --cmenu-danger-line: rgba(176, 69, 43, .5);
  --cmenu-danger-hover: rgba(176, 69, 43, .09);
  --cmenu-add-hover: rgba(201, 105, 74, .08);
  /* The window floats on a shadow instead of a hairline (PRC-982), the form's
     «Отмена» carries a hairline, and the row actions wear the muted ink. */
  --cmenu-modal-shadow: 0 24px 70px rgba(31, 30, 27, .22);
  --cmenu-cancel-line: #d9d4ca;
  --cmenu-cancel-ink: #54504a;
  --cmenu-row-act-ink: #54504a;
  --cmenu-row-act-hover: rgba(31, 30, 27, .06);
}

/* ---- Dark theme tokens ---- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg-page: #121317;
    --surface: #1c1d22;
    --border: #2f313a;
    --border-card: #2b2d35;
    --text-strong: #f3f7ff;
    --text-body: #d7dbe4;
    --result-title: #9fbfa6;
    --result-snippet: #c2c7d2;
    --text-muted: #8f96a6;
    --text-faint: #7f8695;
    --link-url: #a7adba;
    --link-visited: #b9a2c4;
    --spark: #e0855f;
    --spark-soft: rgba(224, 133, 95, .18);
    --spark-deep: #ece9e1;
    --deep: #ece9e1;
    --on-deep: #15171d;
    --danger: #e88d75;
    --on-danger: #1a120f;
    --focus-ring: 3px solid rgba(236, 233, 225, .30);
    --hover-bg: rgba(255, 255, 255, .05);

    --cap-circle-bg: #282a31;
    --cap-circle-bg-hover: #33363f;
    --cap-send-bg: #2f313a;
    --cap-send-hover: #3a3d47;
    --cap-send-fg: #e4e7ee;
    --cap-hover: #22242a;
    --cap-tip-bg: #f3f7ff;
    --cap-tip-fg: #121317;
    --menu-pod-bg: #222328;
    --menu-pod-bg-pinned: rgba(34, 35, 40, .66);
    --menu-pill: #a7adba;
    --menu-pill-active: #f3f7ff;
    --more-bg: #282a32;
    --more-bg-hover: #33363f;
    --sug-q: #8f96a6;
    --sug-t: #e6eaf2;
    --sug-hover: rgba(255, 255, 255, .028);
    --sug-spark: #ece9e1;
    --sug-kbd-border: rgba(255, 255, 255, .07);
    --sug-kbd-hover-bg: rgba(255, 255, 255, .05);
    --sug-kbd-hover-border: rgba(255, 255, 255, .12);
    --sug-sep: rgba(255, 255, 255, .07);
    --startbar-hint: #757575;
    --startbar-toggle: #d7dbe4;
    --startbar-mic: #8f96a6;
    --voice-status: #7f8695;
    --voice-ring: 2px solid rgba(201, 105, 74, .22);
    --voice-connecting-bg: #282a31;
    --voice-connecting-fg: #d7dbe4;
    --result-engines: #7f8695;
    --cap-glass-a: 1;
    /* R19 (owner, 16.09.2026): dark headings are the mockup's sage — the
       lilac/clay per-query variants collapse to it; light keeps one ink. */
    --tone-sage: #9fbfa6;
    --tone-lilac: #9fbfa6;
    --tone-clay: #9fbfa6;
    --result-site: #d7dbe4;
    --result-path: #7f8492;
    --state-title: #f3f7ff;
    --state-text: #8f96a6;
    --sum-active-bg: rgba(236, 233, 225, .07);
    --spark-off: #6f7686;
    --caret-off: #4a505e;
    --rule: #23252c;
    --fact-lead: #33363f;
    --card-border: #272931;
    --card-ink: #d7dbe4;
    --card-foot: #6f7686;
    --fact-value: #e4e7ee;
    --chip-bg: #282a31;
    --chip-hover: #33363f;
    --chip-ring: #2c2e36;
    --chip-fg: #c2c7d2;
    --chips-title: #7f8695;
    --bubble-bg: #2a2c34;
    --bubble-fg: #e4e7ee;
    --photo-bg: #23252c;
    --soon-ink: #6f7583;
    --soon-btn-ink: #5f6673;
    --soon-btn-bg: #191a1f;
    --soon-btn-border: #23252c;
    --cmenu-title: #e6eaf2;
    --cmenu-close: #8f96a6;
    --cmenu-add-ink: #d7dbe4;
    --cmenu-add-line: rgba(255, 255, 255, .16);

    --cmenu-backdrop: rgba(9, 10, 13, .62);
    --cmenu-primary-bg: #e2e6ee;
    --cmenu-primary-fg: #1b1c21;
    --cmenu-primary-hover: #f2f5fa;
    --cmenu-ic-bg: rgba(255, 255, 255, .04);
    --cmenu-ic-line: rgba(255, 255, 255, .09);
    --cmenu-ic-ink: #aab1c0;
    --cmenu-ic-on-bg: rgba(255, 255, 255, .12);
    --cmenu-ic-on-line: rgba(255, 255, 255, .34);
    --cmenu-ic-on-ink: #f3f7ff;
    --cmenu-list-bg: rgba(255, 255, 255, .025);
    --cmenu-list-line: rgba(255, 255, 255, .07);
    --cmenu-icplate-bg: #282a31;
    --cmenu-icplate-ink: #d7dbe4;
    --cmenu-empty-ink: #7f8695;
    --cmenu-grip-ink: #6b7180;
    --cmenu-input-bg: rgba(255, 255, 255, .04);
    --cmenu-input-line: var(--border);
    --cmenu-input-ink: #e6eaf2;
    --cmenu-input-focus-line: rgba(255, 255, 255, .30);
    --cmenu-input-focus-bg: rgba(255, 255, 255, .04);
    --cmenu-danger-ink: #e28075;
    --cmenu-danger-line: rgba(226, 128, 117, .55);
    --cmenu-danger-hover: rgba(226, 128, 117, .12);
    --cmenu-add-hover: rgba(255, 255, 255, .06);
    --cmenu-modal-shadow: 0 30px 80px rgba(0, 0, 0, .55);
    --cmenu-cancel-line: rgba(255, 255, 255, .16);
    --cmenu-cancel-ink: #d7dbe4;
    --cmenu-row-act-ink: #8f96a6;
    --cmenu-row-act-hover: rgba(255, 255, 255, .07);
  }
}

/* ---- Explicit switcher override — wins in both directions. ---- */
:root[data-theme="dark"] {
  --bg-page: #121317;
  --surface: #1c1d22;
  --border: #2f313a;
  --border-card: #2b2d35;
  --text-strong: #f3f7ff;
  --text-body: #d7dbe4;
  --result-title: #9fbfa6;
  --result-snippet: #c2c7d2;
  --text-muted: #8f96a6;
  --text-faint: #7f8695;
  --link-url: #a7adba;
  --link-visited: #b9a2c4;
  --spark: #e0855f;
  --spark-soft: rgba(224, 133, 95, .18);
  --spark-deep: #ece9e1;
  --deep: #ece9e1;
  --on-deep: #15171d;
  --danger: #e88d75;
  --on-danger: #1a120f;
  --focus-ring: 3px solid rgba(236, 233, 225, .30);
  --hover-bg: rgba(255, 255, 255, .05);

  --cap-circle-bg: #282a31;
  --cap-circle-bg-hover: #33363f;
  --cap-send-bg: #2f313a;
  --cap-send-hover: #3a3d47;
  --cap-send-fg: #e4e7ee;
  --cap-hover: #22242a;
  --cap-tip-bg: #f3f7ff;
  --cap-tip-fg: #121317;
  --menu-pod-bg: #222328;
  --menu-pod-bg-pinned: rgba(34, 35, 40, .66);
  --menu-pill: #a7adba;
  --menu-pill-active: #f3f7ff;
  --more-bg: #282a32;
  --more-bg-hover: #33363f;
  --sug-q: #8f96a6;
  --sug-t: #e6eaf2;
  --sug-hover: rgba(255, 255, 255, .028);
  --sug-spark: #ece9e1;
  --sug-kbd-border: rgba(255, 255, 255, .07);
  --sug-kbd-hover-bg: rgba(255, 255, 255, .05);
  --sug-kbd-hover-border: rgba(255, 255, 255, .12);
  --sug-sep: rgba(255, 255, 255, .07);
  --startbar-hint: #757575;
  --startbar-toggle: #d7dbe4;
  --startbar-mic: #8f96a6;
  --voice-status: #7f8695;
  --voice-ring: 2px solid rgba(201, 105, 74, .22);
  --voice-connecting-bg: #282a31;
  --voice-connecting-fg: #d7dbe4;
  --result-engines: #7f8695;
  --cap-glass-a: 1;
  /* R19 (owner, 16.09.2026): dark headings are the mockup's sage — the
     lilac/clay per-query variants collapse to it; light keeps one ink. */
  --tone-sage: #9fbfa6;
  --tone-lilac: #9fbfa6;
  --tone-clay: #9fbfa6;
  --result-site: #d7dbe4;
  --result-path: #7f8492;
  --state-title: #f3f7ff;
  --state-text: #8f96a6;
  --sum-active-bg: rgba(236, 233, 225, .07);
  --spark-off: #6f7686;
  --caret-off: #4a505e;
  --rule: #23252c;
  --fact-lead: #33363f;
  --card-border: #272931;
  --card-ink: #d7dbe4;
  --card-foot: #6f7686;
  --fact-value: #e4e7ee;
  --chip-bg: #282a31;
  --chip-hover: #33363f;
  --chip-ring: #2c2e36;
  --chip-fg: #c2c7d2;
  --chips-title: #7f8695;
  --bubble-bg: #2a2c34;
  --bubble-fg: #e4e7ee;
  --photo-bg: #23252c;
  --soon-ink: #6f7583;
  --soon-btn-ink: #5f6673;
  --soon-btn-bg: #191a1f;
  --soon-btn-border: #23252c;
  --cmenu-title: #e6eaf2;
  --cmenu-close: #8f96a6;
  --cmenu-add-ink: #d7dbe4;
  --cmenu-add-line: rgba(255, 255, 255, .16);

  --cmenu-backdrop: rgba(9, 10, 13, .62);
  --cmenu-primary-bg: #e2e6ee;
  --cmenu-primary-fg: #1b1c21;
  --cmenu-primary-hover: #f2f5fa;
  --cmenu-ic-bg: rgba(255, 255, 255, .04);
  --cmenu-ic-line: rgba(255, 255, 255, .09);
  --cmenu-ic-ink: #aab1c0;
  --cmenu-ic-on-bg: rgba(255, 255, 255, .12);
  --cmenu-ic-on-line: rgba(255, 255, 255, .34);
  --cmenu-ic-on-ink: #f3f7ff;
  --cmenu-list-bg: rgba(255, 255, 255, .025);
  --cmenu-list-line: rgba(255, 255, 255, .07);
  --cmenu-icplate-bg: #282a31;
  --cmenu-icplate-ink: #d7dbe4;
  --cmenu-empty-ink: #7f8695;
  --cmenu-grip-ink: #6b7180;
  --cmenu-input-bg: rgba(255, 255, 255, .04);
  --cmenu-input-line: var(--border);
  --cmenu-input-ink: #e6eaf2;
  --cmenu-input-focus-line: rgba(255, 255, 255, .30);
  --cmenu-input-focus-bg: rgba(255, 255, 255, .04);
  --cmenu-danger-ink: #e28075;
  --cmenu-danger-line: rgba(226, 128, 117, .55);
  --cmenu-danger-hover: rgba(226, 128, 117, .12);
  --cmenu-add-hover: rgba(255, 255, 255, .06);
  --cmenu-modal-shadow: 0 30px 80px rgba(0, 0, 0, .55);
  --cmenu-cancel-line: rgba(255, 255, 255, .16);
  --cmenu-cancel-ink: #d7dbe4;
  --cmenu-row-act-ink: #8f96a6;
  --cmenu-row-act-hover: rgba(255, 255, 255, .07);
}

* { box-sizing: border-box; }

html { background: var(--bg-page); }
body {
  margin: 0;
  background: var(--bg-page);
  color: var(--text-body);
  font-family: ui-sans-serif, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--link-url); text-decoration: none; }
a:hover { opacity: .8; }
::selection { background: rgba(201, 105, 74, .25); }

/* ---- Brand logo + spark (shared with the old design; the wordmark is the
   same drawn object) ---- */
.brand-logo {
  font-family: var(--brand-font);
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1;
  color: var(--text-strong);
  text-decoration: none;
  white-space: nowrap;
}
.brand-l { position: relative; display: inline-block; }
.spark { display: inline-block; }
.spark path { fill: var(--spark); }
.spark--logo {
  position: absolute;
  top: 0.06em;
  right: -0.22em;
  width: 0.3em;
  height: 0.3em;
  overflow: visible;
}
.spark--logo path { transform-box: fill-box; transform-origin: center; }
@keyframes sparkTwinkle {
  0%, 100% { opacity: .85; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.2); }
}
.spark--logo path { animation: sparkTwinkle 3.4s ease-in-out infinite; }
@keyframes sparkPulse { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .spark--logo path { animation: sparkPulse 3.4s ease-in-out infinite; }
}

/* ---- Result favicons (favicon.js swaps the letter for the /icon image;
   a missing icon stays a clean letter) ---- */
.favicon {
  position: relative;
  top: -0.5px;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-muted);
  user-select: none;
}
.favicon__img { width: 20px; height: 20px; object-fit: contain; display: block; }
.favicon--img { font-size: 0; color: transparent; }

/* ---- Search bar (the capsule). One base, three geometries: --start (60px
   start screen), --results (52px results header), --error (60px, message as
   placeholder). The pill is the positioning context for the busy rays,
   .suggest and .voice-live. ---- */
.searchbar {
  position: relative;
  display: flex;
  align-items: center;
  min-width: 0;
  border: none;
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-body);
  margin: 0;
}
.searchbar__input {
  flex: 1 1 auto;
  align-self: stretch;
  min-width: 0;
  height: 100%;
  padding: 0;
  margin: 0;
  border: none;
  outline: none;
  background: transparent;
  font: inherit;
  color: var(--text-body);
  text-align: left;
}
.searchbar__input::placeholder { color: var(--text-faint); }
.searchbar__input:focus-visible { outline: none; }
/* The spark submit is visually replaced by the mic but must stay in the DOM
   for the .searchbar__action selector contract (iskra-submit.js /
   search-busy.js); [hidden] alone loses to display rules. */
.searchbar__action[hidden] { display: none; }

/* ---- Capsule circles: 44px on the start pill, 40px in the results header. ---- */
.cap-circle {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-body);
  padding: 0;
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.cap-circle:hover { background: var(--cap-hover); color: var(--text-strong); }
.cap-circle:focus-visible { outline: var(--focus-ring); }
/* Кружок выключенной вертикали в ряду капсулы выдачи (PRC-839,
   Results.dc.html): тот же кружок на своём месте, погашенный, без
   подсветки на наведении. */
.cap-circle[data-soon],
.cap-circle[data-soon]:hover { background: transparent; color: var(--soon-ink); }
/* The services trigger keeps the filled chip look in both themes (mockup:
   button[aria-label="Сервисы"]); light reads #54504a (StartScreen.dc.html).
   [data-startbar], not .startbar: the results header is a .rheader that
   carries the same attribute — the old class selector never fired there
   and the loupe fell back to --text-body (T5). */
.cap-circle--toggle { background: var(--cap-circle-bg); }
[data-startbar] .cap-circle--toggle { color: var(--startbar-toggle); }
[data-startbar] .cap-circle--toggle:hover { background: var(--cap-circle-bg-hover); color: var(--text-strong); }
/* Decorative perecle mark in the error capsule — not a control. */
.cap-circle--mark { background: var(--cap-circle-bg); color: var(--link-url); cursor: default; }
.cap-circle--mark:hover { background: var(--cap-circle-bg); color: var(--link-url); }

/* ---- Theme circle (ThemeSwitch.dc.html; owner decision 2). theme.js
    toggles the [hidden] icon by data-icon; the dynamic title mirrors the
    active mode. The circle itself reads the warm ink in light / the bright
    one in dark (ThemeSwitch.dc.html, #54504a / #d7dbe4) — not --text-body. ---- */
.theme-switch { color: var(--startbar-toggle); }
.theme-switch .theme-icon { display: inline-flex; }
.theme-switch .theme-icon[hidden] { display: none; }

/* ---- Start screen (StartScreen.dc.html) ---- */
body.start { overflow: hidden; }
.start-hero {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
/* Vertical placement (mini.ya.ru, PRC-891): not dead-centre any more — a top
   spacer puts the pair's centre ~4.4rem ABOVE the viewport middle, so the row
   starts at 50vh − 5.3rem. On desktop, add 3px (PRC-947). The arithmetic:
   spacer + .startbar's padding-top (24px) + half the 60px pill = 50vh − 95.4 +
   54 = 50vh − 39.4px ≈ the 4.4rem lift of the reference, plus 3px on desktop.
   Bound to vh, tracks any window height. */
.start-hero__spacer {
  flex: none;
  height: calc(50vh - 5.3rem);
}
@media (min-width: 641px) {
  .start-hero__spacer {
    height: calc(50vh - 5.3rem + 3px);
  }
}
/* The pair's geometry is pure CSS (PRC-965), so the first painted frame is
   already the final one. start.js used to write --w-idle / --w-exp on
   DOMContentLoaded: a frame painted before that (the end-of-body scripts
   still on the network) showed the 612px fallback pill with the wordmark
   112px to the left, and a measure taken while the wordmark was still in
   Georgia put the pair 10px to the right until the webfont landed.

   --brand-w is the wordmark's box: Source Serif 4 600 «Перекл» at 34px is
   113.7px wide, which start.js rounded to 114 — the same number, so the pair
   sits exactly where the measured one did. Being a constant, it does not move
   when the webfont swaps in. The formula is start.js's old measure():
   the row is --w-exp wide with the wordmark ≥ 24px from the window edge, and
   the pill takes what the wordmark and the 18px gap leave (520px on desktop). */
.startbar {
  --brand-w: 114px;
  --w-exp: max(360px, min(520px + var(--brand-w) + 18px, 100vw - 84px - 2 * var(--brand-w)));
  --w-idle: max(280px, var(--w-exp) - var(--brand-w) - 18px);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 18px;
  width: 100%;
  max-width: calc(var(--w-exp) + 48px);
  margin: 0 auto;
  padding: 24px;
  box-sizing: border-box;
}
/* The text sits at the box's right edge — where it stood in its own
   113.7px box — and a wider fallback face overflows to the left, away from
   the pill. */
.startbar__brand {
  flex: none;
  display: flex;
  justify-content: flex-end;
  width: var(--brand-w);
  position: relative;
  top: -2.5px; /* optical alignment with the 60px pill (mockup) */
  font-size: 34px;
}
/* The field width is FIXED (owner decision 16.09.2026, S5 wave 1): the old
   520→652 expansion on focus/typing is cancelled — the pill keeps --w-idle
   (520px on desktop) in both states and the wordmark never travels. */
.startbar form {
  max-width: var(--w-idle);
}
.searchbar--start {
  flex: 0 0 auto;
  width: 100%;
  height: 60px;
  gap: 10px;
  padding: 0 10px;
}

.startbar__services {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
}
.startbar__services[hidden] { display: none; }
.startbar__services::-webkit-scrollbar { display: none; }

/* ---- The capsule row (account-spec §10; CapsuleRow.dc.html 1–9, PRC-1003):
   Войти/Аккаунт · Коллекции · Тема · Безопасный поиск. The circles themselves
   are .cap-circle — 44px on the start pill, 40px in the results header, which
   the rules above already size; this block is only what the row adds on top.

   Tooltips (CapsuleRow 3, 7): the mockup draws a bubble 400 ms after hover OR
   keyboard focus, centred under the circle. CSS-only, so focus gets it for
   free; the delay is a transition-delay on the way in and nothing on the way
   out, so leaving the circle dismisses it at once. `title` stays the
   accessible name (as on the theme circle). */
.caprow__circle {
  position: relative;
  color: var(--text-body);
}
.caprow__circle::after {
  content: attr(title);
  position: absolute;
  z-index: 30;
  top: calc(100% + 10px);
  left: 50%;
  transform: translateX(-50%);
  padding: 6px 10px;
  border-radius: 8px;
  background: var(--cap-tip-bg);
  color: var(--cap-tip-fg);
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity .12s ease-out;
}
.caprow__circle:hover::after,
.caprow__circle:focus-visible::after {
  opacity: 1;
  transition: opacity .12s ease-out .4s;
}
/* «Коллекции» на странице коллекций — тот же фон, что у кнопки ряда
   (CapsuleRow 9). */
/* Обе линии щита живут в одном <svg>;state переключает [hidden] (см.
   row_icon_safe и capsule-row.js — почему не перерисовка). */
.caprow__safe-on[hidden], .caprow__safe-off[hidden] { display: none; }
.caprow__circle--current {
  background: var(--cap-circle-bg);
  color: var(--text-strong);
}
.caprow__circle--current:hover { background: var(--cap-circle-bg-hover); }

/* Кнопка ряда у вошедшего: аватар или буква имени в круге того же размера,
   что и глиф гостя, — явные width/height у обоих, поэтому подмена не двигает
   вёрстку (AC-2, CapsuleRow 6). Буква — запасной вариант: она видна всегда,
   фото ложится сверху и снимает себя, если не загрузилось. */
.caprow__me {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  overflow: hidden;
  background: var(--spark);
  color: #ffffff;
  font-weight: 600;
  line-height: 1;
  user-select: none;
}
.startbar .caprow__me { font-size: 19px; }
.searchbar--results .caprow__me { font-size: 18px; }
.caprow__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* «Не удалось сохранить настройку» под рядом (CapsuleRow 8, §8.1). Показ —
   дело capsule-row.js, здесь только место и вид. */
.caprow__error {
  position: absolute;
  z-index: 30;
  top: calc(100% + 10px);
  left: 0;
  right: 0;
  margin: 0;
  text-align: center;
  font-size: 13.5px;
  line-height: 1.3;
  color: var(--danger);
  pointer-events: none;
}
.caprow__error[hidden] { display: none; }


/* Cascade (mockup circleIn/circleOut): per-circle delays come from start.js;
   reduced motion drops the cascade. */
@keyframes circleIn {
  from { opacity: 0; transform: scale(.7) translateX(-8px); }
  to { opacity: 1; transform: none; }
}
@keyframes circleOut {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: scale(.7) translateX(-8px); }
}
@media (prefers-reduced-motion: reduce) {
  .startbar__services .cap-circle { animation: none !important; }
}

/* The field: input + the centred hint layer. The hint is NOT the native
   placeholder (mockup): the input itself stays left-aligned so the caret
   sits left at once; only the hint text dissolves in place. */
.startbar__field {
  position: relative;
  flex: 1 1 auto;
  align-self: stretch;
  min-width: 0;
  display: flex;
}
.startbar__input { font-size: 16px; line-height: 52px; }
.startbar__hint {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  font-size: 16px;
  color: var(--startbar-hint);
  white-space: nowrap;
  overflow: hidden;
  opacity: 1;
  transition: opacity .22s ease-out;
}
.startbar__hint[data-off="1"] { opacity: 0; transition: opacity .12s ease-in; }
/* While the services row is out, the field steps aside rather than fighting
   it for space (mockup: menuVisible swaps the input for the circle row). */
.startbar__services:not([hidden]) ~ .startbar__field { display: none; }
@media (prefers-reduced-motion: reduce) {
  .startbar__hint { transition: none; }
}

/* Mic circle sits right of the field; voice.js drives it, without JS (or
   without SpeechRecognition) the click just focuses the field. The start
   screen's mic reads #54504a in light / #8f96a6 in dark (StartScreen.dc.html);
   the error screen keeps its own #8a857a (ErrorScreens.dc.html). */
.cap-mic { color: var(--text-muted); }
.startbar .cap-mic { color: var(--startbar-mic); }
.startbar .cap-mic:hover { color: var(--text-strong); }

@media (max-width: 640px) {
  .startbar {
    flex-direction: column;
    align-items: stretch;
    justify-content: center;
    gap: 22px;
    max-width: 100%;
  }
  .startbar form { max-width: none; }
  .startbar__brand { position: static; align-self: center; width: auto; font-size: 40px; }
}

/* ---- Suggest dropdown (SuggestDropdown.dc.html / StartScreen sug). Built
   by suggest.js inside the capsule; opens under the pill, its top corners
   follow the pill's radius flip. A list longer than the viewport scrolls
   INSIDE the container (PRC-874): the capsule is fixed on the results page,
   so no page scroll could ever reveal the rows cut by the screen edge —
   suggest.js clamps the box's bottom edge to the viewport and this rule lets
   the list scroll within it. A short list never overflows, so it renders
   exactly like the mockup's five rows. ---- */
.suggest {
  position: absolute;
  z-index: 3;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--surface);
  border-radius: 0 0 30px 30px;
  /* x keeps clipping to the rounded corners, y lets a clamped list scroll;
     contain stops the wheel from chaining into the page behind the list. */
  overflow: hidden auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--sug-sep) transparent;
  /* No shadow (owner, PRC-886), no border (owner, PRC-903): the surface
     background alone carries the edge; the top stays open where the panel
     meets the capsule. */
}
.suggest::-webkit-scrollbar { width: 8px; }
.suggest::-webkit-scrollbar-thumb { background: var(--sug-sep); border-radius: 4px; }
.suggest::-webkit-scrollbar-track { background: transparent; }
.suggest[hidden] { display: none; }
/* «Спросить Искру: <запрос>» — the first row of the dropdown, above the
   suggestions (StartScreen.dc.html). Its spark is always lit; the row sparks
   below only come up on hover. */
.suggest__ai {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  height: 48px;
  padding: 0 20px;
  font-family: inherit;
  font-size: 16px;
  line-height: 1;
  text-align: left;
  border: none;
  background: transparent;
  color: var(--text-body);
  cursor: pointer;
}
.suggest__ai:hover, .suggest__ai[aria-selected="true"] { background: var(--sug-hover); }
.suggest__ai:focus-visible { outline: var(--focus-ring); outline-offset: -3px; }
.suggest__ai-label {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--sug-t);
}
.suggest__ai-q { color: var(--sug-q); }
.suggest__kbd {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  box-sizing: border-box;
  height: 24px;
  padding: 0 7px;
  border: 1px solid var(--sug-kbd-border);
  border-radius: 7px;
  color: var(--sug-q);
  font-size: 14px;
  line-height: 1;
  letter-spacing: .02em;
  transition: background-color .12s ease-out, border-color .12s ease-out, color .12s ease-out, transform .12s ease-out;
}
.suggest__kbd-return { font-size: 13px; position: relative; top: 1.5px; }
.suggest__kbd:hover {
  background: var(--sug-kbd-hover-bg);
  border-color: var(--sug-kbd-hover-border);
  color: var(--text-strong);
  transform: translateY(1px) scale(.94);
}
.suggest__ai .suggest__spark { opacity: 1; cursor: inherit; }
.suggest__list { display: flex; flex-direction: column; padding-bottom: 10px; }
.suggest__row {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 48px;
  padding: 0 20px;
  font-size: 16px;
  line-height: 1;
  text-align: left;
  border: none;
  background: transparent;
  color: var(--text-body);
  cursor: pointer;
  font-family: inherit;
}
.suggest__row:hover, .suggest__row[aria-selected="true"] { background: var(--sug-hover); }
.suggest__row:focus-visible { outline: var(--focus-ring); outline-offset: -3px; }
.suggest__text {
  flex: 1 1 auto;
  min-width: 0;
  display: inline-flex;
  align-items: center;
  overflow: hidden;
  position: relative;
  top: -1px;
}
/* PRC-888: q and t live inside this one nowrap line (StartScreen.dc.html
   wraps {{ query }}&nbsp; and the completion in a single line span), so the
   color boundary stays within one inline context — no flex gap, no extra
   whitespace at the joint, and every space in the row renders equal. */
.suggest__line {
  flex: 1 1 auto;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.suggest__q { color: var(--sug-q); }
.suggest__t { color: var(--sug-t); }
/* No disc behind the spark any more: the owner dropped border-radius:50%
   from the suggest sparks, so it is the glyph alone (StartScreen.dc.html). */
.suggest__spark {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: none;
  background: transparent;
  color: var(--sug-spark);
  padding: 0;
  cursor: pointer;
  position: relative;
  top: 1px;
  opacity: 0;
  transition: opacity .15s ease;
}
.suggest__row:hover .suggest__spark, .suggest__spark:focus-visible { opacity: .5; }
.suggest__spark:hover { opacity: 1 !important; }
.suggest__spark:focus-visible { outline: var(--focus-ring); }
.suggest__spark .spark { width: 17px; height: 17px; }
.suggest__spark .spark path { fill: var(--sug-spark); }
/* A history row (account-spec §8.4, HistorySuggest.dc.html): the same row as a
   suggestion, with the cross «Удалить из истории» to the right of the spark —
   always visible, always muted, full strength on hover (1, 6). No clock icon:
   the cross is what tells a history row from a suggestion. The extra 18px of
   right padding is the cross's seat. */
.suggest__row--hist { padding-right: 18px; }
.suggest__x {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border: none;
  background: transparent;
  color: var(--text-muted);
  padding: 0;
  cursor: pointer;
  opacity: .5;
  transition: opacity .15s ease;
}
.suggest__x:hover, .suggest__x:focus-visible { opacity: 1; }
.suggest__x:focus-visible { outline: var(--focus-ring); }
/* The pill flips its bottom corners while the dropdown is open. */
.searchbar[data-sug="1"] { border-radius: 30px 30px 0 0; }

/* ---- Voice status (VoiceInput.dc.html): status text + live level bar /
   recognizing dots shown INSTEAD of the field while voice.js records.

   It used to be an opaque layer at inset:0 over the whole capsule, which
   covered the two circles the mockup keeps on screen — the services circle on
   the left and the mic on the right — and let the level bars run over the mic's
   box. The mockup puts the meter between the status text and the mic, so the
   status is a plain flex item in the field's place: circles stay put, nothing
   is painted over anything. ---- */
.voice-live {
  flex: 1 1 auto;
  min-width: 0;
  display: none;
  align-items: center;
  gap: 12px;
  pointer-events: none;
}
.voice-live[data-on="1"] { display: flex; }
/* While the voice is live the field steps aside — and so does the services row
   if it happened to be open, so the whole path stays inside the capsule. */
.searchbar[data-voice-on="1"] .startbar__field,
.searchbar[data-voice-on="1"] .rheader__field,
.searchbar[data-voice-on="1"] .startbar__services { display: none; }
.voice-live__text {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 15px;
  color: var(--voice-status);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.voice-live__bars { flex: none; display: inline-flex; align-items: center; gap: 3px; height: 30px; }
.voice-live__bar {
  flex: none;
  width: 3px;
  border-radius: 2px;
  background: var(--spark);
  /* Height/opacity are driven by voice.js from the live mic level (PRC-930);
     without a level they rest at the quiet end of the 7…30px band. */
  height: 7px;
  opacity: .49;
}
/* Mockup scale (VoiceInput.dc.html frame 02): 14 bars, 3px wide, 3px apart,
   7px in silence up to 30px on loud speech — the meter reads 81px wide. */
.voice-live__dots { flex: none; display: inline-flex; align-items: center; gap: 4px; }
/* One greige for both themes (mockup frame 03) — deliberately not
   --text-muted, which splits by theme. */
.voice-live__dots span {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--voice-dots);
  animation: voiceDot 1.2s ease-in-out infinite;
}
.voice-live__dots span:nth-child(2) { animation-delay: .15s; }
.voice-live__dots span:nth-child(3) { animation-delay: .3s; }
@keyframes voiceDot {
  0%, 100% { opacity: .35; transform: translateY(0); }
  50% { opacity: 1; transform: translateY(-2px); }
}
/* Recording ring around the capsule (mockup frames 02 AND 03: the ring
   marks the whole live session — «Слушаю» and «Распознаю» — and only those;
   «Готово» and «Не получилось» drop it). voice.js drives data-voice-ring;
   2px terracotta in both themes (see the --voice-ring token). */
.searchbar[data-voice-ring="1"] { outline: var(--voice-ring); }
/* The mic IS the stop button while recording, and the mockup marks it as one:
   filled terracotta for exactly as long as the tape runs ([data-miclive]).
   Recognising and failing are quiet again, so this hangs on the listening
   flag, not on the general voice flag. */
.searchbar[data-voice-listening="1"] [data-voice] {
  background: var(--spark-soft);
  color: var(--spark);
}
.searchbar[data-voice-listening="1"] [data-voice]:hover {
  background: var(--spark-soft);
  color: var(--spark);
}
/* Frame 01a «Включаю микрофон» (PRC-981): grey with its own backdrop —
   distinct from both idle (no backdrop) and listening (terracotta), so the
   button doesn't claim the mic is live before onaudiostart says it is. */
.searchbar[data-voice-connecting="1"] [data-voice],
.searchbar[data-voice-connecting="1"] [data-voice]:hover {
  background: var(--voice-connecting-bg);
  color: var(--voice-connecting-fg);
}
/* Frame 02a/02b «Слушаю · слова в строке» (PRC-981): the first recognised
   word must NOT take the recording indication away (problem 2 of the bug) —
   only the status text and the dots go; the field comes back to show the
   words while the ring, the bars and the terracotta button (all driven by
   data-voice-ring/-listening above) stay exactly as they were. This override
   has to win over the data-voice-on rule above that hides the field, so it
   is declared after it. */
.searchbar[data-voice-speaking="1"] .startbar__field,
.searchbar[data-voice-speaking="1"] .rheader__field {
  display: flex;
}
.searchbar[data-voice-speaking="1"] .voice-live__text,
.searchbar[data-voice-speaking="1"] .voice-live__dots {
  display: none;
}
/* Director's visual review of PR #557: with words in the field, the bars
   drifted ~100-340px away from the mic, leaving a gap. Cause: .voice-live is
   flex: 1 1 auto — fine when it is the ONLY thing in the row (02/03, field
   hidden), but once the field is ALSO shown (speaking) both are flex:1 and
   split the free space, so the now-mostly-empty .voice-live box (only the
   bars are left visible in it) grows and its flex-start-aligned bars land
   partway across the row instead of hugging the mic. Per mockup 02a/02b,
   the bars and the button never move or shrink — pin the box to its content
   width so the field (still flex: 1 1 auto) owns 100% of the growth, and the
   bars end up flush against the mic on both desktop and the narrower phone
   capsule (where the same bug left the field with ~0 width, i.e. blank). */
.searchbar[data-voice-speaking="1"] .voice-live {
  flex: none;
}
/* The engine writes the field, not the person (brief p.2): no visible caret,
   and voice.js's own mousedown guard stops a click from placing one. */
.searchbar[data-voice-speaking="1"] .searchbar__input {
  caret-color: transparent;
}
/* Frame 02b «Длинная фраза»: once the recognised text no longer fits, voice.js
   scrolls the field to the end and marks the overflow — the head of the
   phrase fades under a 28px mask instead of just clipping (spec
   VoiceInput.spec.md §02b). Frame 04 drops both the instant recording ends,
   since this rule is scoped to data-voice-speaking. */
.searchbar[data-voice-speaking="1"] .searchbar__input[data-voice-overflow="1"] {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 28px);
  mask-image: linear-gradient(to right, transparent 0, #000 28px);
}
@media (prefers-reduced-motion: reduce) {
  .voice-live__dots span { animation: none; }
  .voice-live__bar { animation: none; height: 14px; opacity: .7; }
}
/* ---- Search-in-flight rays (PRC-869, PRC-944) -------------------------
   The capsule's busy state is the design etalon's ray train (StartScreen /
   Results .dc.html, svg[data-rays]), drawn by the one rays component,
   window.PerecleRays in search-busy.js, on a <canvas> injected as the first
   child of the form — the same component draws «Искать ещё» (.more-btn
   below, .imore2 in Картинки). The layer carries its own inline styles and
   its own reduced-motion rule (one still frame), so no CSS here is needed
   and pages that do not load this file beam identically. ---- */

/* The bar is the positioning context for the busy rays layer (inset: 0) and
   the suggest dropdown. The base .searchbar rule already carries
   `position: relative`; this comment is what keeps it from being "cleaned
   up" a third time (it was removed 2026-08-27 with the dropdown and came
   back with the busy beam, docs/mvp-scope.md §3). */

/* ---- Results header (ResultsSummary.dc.html). The capsule + services pod
   live in the same 800px column as the results; the capsule is ALWAYS pinned
   (its in-flow seat is top:10px, so pinning never shifts it). Geometry vars
   --cap-l/--cap-w are written by start.js (results mode) from widths only;
   data-geo appears after the first successful measure so a no-JS page never
   flashes a fallback position. No transform/will-change/isolation here: any
   of those makes the capsule its own backdrop-root and the glass flickers. */
.rheader { position: relative; }
.rheader__bar {
  position: relative;
  max-width: var(--rheader-col);
  margin: 0 auto;
  padding: 10px 24px 16px;
}
.rheader__cap {
  position: relative;
  margin-left: -14px;
  margin-right: -14px;
  border-radius: 26px;
  transition: background-color .32s ease;
}
.rheader__slot { height: 52px; }
.searchbar--results {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 52px;
  gap: 8px;
  padding: 0 8px;
}
/* The blur hangs on the capsule permanently; only the tint changes between
   in-flow (opaque) and pinned (translucent) — toggling backdrop-filter
   itself is what made the glass flicker (mockup note). The `top` transition
   is the dialog mode's own (Results.dc.html [data-slot] form): the capsule
   glides down under the thread and back over .78s — without it the capsule
   teleported at both mode edges (owner №4, PRC-862). */
.rheader .searchbar--results {
  background: rgba(28, 29, 34, var(--cap-glass-a));
  -webkit-backdrop-filter: blur(15px) saturate(1.25);
  backdrop-filter: blur(15px) saturate(1.25);
  transition: background-color .28s ease, top .78s cubic-bezier(.4, .02, .14, 1);
}
:root[data-theme="light"] .rheader .searchbar--results,
:root:not([data-theme="dark"]) .rheader .searchbar--results { background: rgba(255, 255, 255, var(--cap-glass-a)); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .rheader .searchbar--results { background: rgba(28, 29, 34, var(--cap-glass-a)); }
}
.rheader[data-geo="1"] .searchbar--results {
  position: fixed;
  top: 10px;
  left: var(--cap-l, 24px);
  right: auto;
  width: var(--cap-w, 652px);
  max-width: none;
  z-index: 60;
}
.rheader[data-pinned="1"] { --cap-glass-a: .46; }
:root[data-theme="light"] .rheader[data-pinned="1"],
:root:not([data-theme="dark"]) .rheader[data-pinned="1"] { --cap-glass-a: .62; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .rheader[data-pinned="1"] { --cap-glass-a: .46; }
}
/* 40px circles inside the results capsule (44px on the start screen). */
.searchbar--results .cap-circle { width: 40px; height: 40px; }
/* Results capsule row walks a 6px gap — circle 40 + 6 = the mockup's 46px
   step (Results.dc.html); the start screen keeps the 8px gap of its 44px
   circles (StartScreen.dc.html). The row also HUGS its circles here: the base
   rule stretches it flex:1 for the start screen, where the open row replaces
   the field (mockup menuVisible/menuClosed swap) — on results the field stays
   (owner decision 17.09.2026, PRC-853: «текст запроса — сразу после последней
   иконки, если меню открыто»), so a stretched row pushed the typed text ~250px
   away from the icons (measured on prod: services spanned 282–573px with the
   input left edge at 581px, 1280px viewport). */
.searchbar--results .startbar__services {
  gap: 6px;
  flex: 0 0 auto;
}
/* The results mic reads the warm/bright pair like the start screen's
   (#54504a / #8f96a6, Results.dc.html circle at the capsule tail). The old
   selector targeted .cap-mic, but the template renders cap-mic--results —
   the rule never fired and the mic fell back to --text-body (T6). */
.searchbar--results .cap-mic--results { color: var(--startbar-mic); }
/* «Коллекции» circle of the Картинки capsule (search_header_2026
   active="images", ImagesShare.dc.html): the mockup paints it and the mic
   with one ink (--mu2), so it reads the mic's pair. */
.searchbar--results .cap-coll { color: var(--startbar-mic); }

.rheader__field { position: relative; flex: 1 1 auto; align-self: stretch; min-width: 0; display: flex; }
.rheader__field .searchbar__input { font-size: 15px; line-height: 52px; position: relative; top: -1px; }

/* Watermark wordmark inside the capsule: shown only below 1180px where the
   outer brand no longer fits (mockup media rule); faded to 10% until hover. */
/* The outer wordmark is absolute against the bar (IskraResults.dc.html):
   right:calc(100% + 15px) parks it left of the column with a 15px gap,
   top:calc(50% - 8px) + translateY(-50%) centres it on the capsule+pod
   block as a whole — the -8px is the mockup's optical correction. Out of
   the flow it can no longer slide under the pod's negative margin. */
.rheader__brand {
  position: absolute;
  top: calc(50% - 8px);
  right: calc(100% + 15px);
  left: auto;
  transform: translateY(-50%);
  font-size: 32px;
}
.cap-brand {
  position: absolute;
  right: 58px;
  top: calc(50% - 1.2px);
  transform: translateY(-50%);
  z-index: 2;
  display: none;
  align-items: center;
  font-family: var(--brand-font);
  font-weight: 600;
  font-size: 20px;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--text-strong);
  opacity: .1;
  white-space: nowrap;
  transition: opacity .09s linear;
}
.cap-brand:hover { opacity: 1; }
.cap-brand .spark--logo path { animation: none; }
@media (max-width: 1180px) {
  .rheader__brand { display: none; }
  .cap-brand { display: inline-flex; }
}
/* The same 1180px condition with the summary panel open, counted on the room
   left of the panel: 1180 + 476 = 1656 (PRC-957 / PRC-960, ResultsSummary.dc.html
   frame 1920, container query min-width:1181px). Without it the wordmark sat
   outside from window ≈ 1570 with 5…15px to the window edge, which never
   happens on a plain results page (min margin ≈ 44px). */
@media (min-width: 1100px) and (max-width: 1656px) {
  body.results.summary-open .rheader__brand { display: none; }
  body.results.summary-open .cap-brand { display: inline-flex; }
}
/* Same swap, driven by the column instead of the viewport: start.js sets
   data-brandfit="0" when the margin left of the column no longer holds the
   wordmark (the summary panel narrows the column at an untouched 1280px). */
.rheader[data-brandfit="0"] .rheader__brand { display: none; }
.rheader[data-brandfit="0"] .cap-brand { display: inline-flex; }
.cap-brand[data-hide="1"] { opacity: 0 !important; pointer-events: none; }

/* Services pod under the capsule: overlaps the capsule's bottom (margin-top
   -26px), dense pill row, glass that only shows while in flow. The pod is the
   PLATE (background, blur, rounded lower corners) and .rmenu__scroll below is
   the ROW — PRC-1031, MobileVoiceInput 19a (data-tray / data-trayscroll). One
   element that was both took the row's right-edge fade on itself, dissolving
   the plate with the pills; the split is what keeps the plate whole. */
.rmenu {
  position: relative;
  z-index: 0;
  margin-top: -26px;
  padding: 30px 12px 6px;
  background: var(--menu-pod-bg);
  border-radius: 0 0 26px 26px;
  overflow: hidden;
  -webkit-backdrop-filter: blur(26px) saturate(.88);
  backdrop-filter: blur(26px) saturate(.88);
  transition: background-color .32s ease;
}
/* Pinned, the pod rides over the results, so its tint thins out the same way
   the capsule's does; in flow it stays solid. The blur hangs permanently
   either way — toggling backdrop-filter is what flickers. */
.rheader[data-pinned="1"] .rmenu { background: var(--menu-pod-bg-pinned); }
/* The row itself: the scroller (the row the custom items join, so its length
   changes after load — start.js re-reads the fade on every change). */
.rmenu__scroll {
  display: flex;
  align-items: center;
  gap: 2px;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.rmenu__scroll::-webkit-scrollbar { display: none; }
.rmenu__pill {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 26px;
  padding: 0 10px;
  border: none;
  border-radius: 999px;
  background: transparent;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  color: var(--menu-pill);
  cursor: pointer;
  white-space: nowrap;
}
.rmenu__pill svg { width: 14px; height: 14px; display: block; flex: none; }
.rmenu__pill:hover { color: var(--menu-pill-active); }
.rmenu__pill:focus-visible { outline: var(--focus-ring); }
/* Искра reads as one more service until you are inside it: terracotta is how
   the pod marks the ACTIVE mode, and a permanently orange pill claimed that
   state on every plain SERP (Results.dc.html sIskra). */
.rmenu__pill--iskra { color: var(--menu-pill); }
.rmenu__pill--iskra:hover { color: var(--menu-pill-active); }
.rmenu__pill--iskra .spark { width: 13px; height: 13px; }
.rmenu__pill--iskra .spark path { fill: currentColor; }
/* A prepared answer keeps the spark terracotta after the mode is left
   (owner's edit №5, PRC-884 -> PRC-889): the mark follows the ANSWER in the
   thread, not the active mode — Results.dc.html draws exactly this split
   (iskraSpark: (hasHist || inI) ? terracotta : currentColor, the text stays
   service ink). Only the icon recolors, in both themes (--spark is
   per-theme); hover keeps lifting the whole pill, and the spark follows the
   mockup by NOT following it there — the mark is the icon's own. */
.rmenu__pill--iskra[data-answered] .spark path { fill: var(--spark); }
/* «Картинки» при снятом флаге (W1, PRC-839): пилюля остаётся на
   месте и гаснет. Геометрия — общая, от .rmenu__pill; своё у неё только
   тон, и наведение его не поднимает: подниматься нечему. */
.rmenu__pill[data-soon],
.rmenu__pill[data-soon]:hover { color: var(--soon-ink); }
/* The add button follows the mockup's compact pod plus (Results.dc.html
   s244: 26x26, tucked -4px into the pill row, 15px icon on a 1.8 stroke,
   faint ink dimmed to .55, hover restores full opacity and lights the
   active ink — no hover pad, the tiny circle has nothing to pad).
   Light has no mockup variant of the plus, so its tones come from the
   pod's own palette: --soon-ink rest, --menu-pill-active hover, the same
   .55 -> 1 opacity scheme. */
.rmenu__add {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  margin-left: -4px;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--soon-ink);
  opacity: .55;
  transition: opacity .16s ease;
  padding: 0;
  cursor: pointer;
}
.rmenu__add svg { width: 15px; height: 15px; display: block; }
.rmenu__add:hover { color: var(--menu-pill-active); opacity: 1; }
.rmenu__add:focus-visible { outline: var(--focus-ring); color: var(--menu-pill-active); opacity: 1; }
/* The dark rest ink is a mockup literal (#7f8695, s244), so it needs its own
   theme-scoped rest rule — and that rule outranks the plain :hover above,
   hence the lit state is repeated in the same scope. */
:root:not([data-theme="light"]) .rmenu__add { color: #7f8695; }
:root:not([data-theme="light"]) .rmenu__add:hover,
:root:not([data-theme="light"]) .rmenu__add:focus-visible { color: var(--menu-pill-active); }
/* Custom items render as icon pills in the pod (ResultsSummary.dc.html:
   26px pill, 999px radius, 14px icon, 13px/500 label). */
.rmenu .service-link--live,
.cmenu-bar .service-link--live {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 26px;
  padding: 0 10px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  line-height: 1;
  color: var(--menu-pill);
  white-space: nowrap;
}
.rmenu .service-link--live:hover,
.cmenu-bar .service-link--live:hover { color: var(--menu-pill-active); }
.rmenu .service-link--live:focus-visible,
.cmenu-bar .service-link--live:focus-visible { outline: var(--focus-ring); }
/* The active pill must win over the .service-link--live base above (it lost
   the source-order race before — R9): light #1f1e1b, dark #f3f7ff. */
.rmenu__pill--active,
.rmenu__pill.service-link--active,
.rmenu .service-link--live.service-link--active { color: var(--menu-pill-active); }
/* Pill icon (PRC-865): a 14px seat carrying the item's drawn glyph —
   the stroke inherits the pill's ink, so it recolors with the hover. */
.rmenu__pill-ic {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
}
.rmenu__pill-ic svg { width: 14px; height: 14px; display: block; }
.cmenu-bar { display: contents; }

/* ---- Results body (Results.dc.html <main>): the page carries the 24px side
    fields, the column itself is a bare 800px box — its own padding ate 48px
    of --content-col and left 752px of results (V1), while an asymmetric
    9px/2px page padding put the column 3.5px off the capsule's axis (V2).
    Now: 240…1040 against the capsule's 226…1054, both centred on 640.
    The open-summary state overrides these fields with its own layout — see
    the body.summary-open block by the summary panel rules. ---- */
.results-main {
  flex: 1;
  margin-top: -1px; /* cover the header/body seam against subpixel ripples */
  padding: 3px 24px 36px;
  display: flex;
  flex-direction: column;
  min-height: 60vh;
  /* The dialog mode's choreography (Results.dc.html main): the SERP steps
     down under the thread and back over .78s, its dim breathes over .6s —
     the transition lives on the BASE rule so the exit animates too (owner
     №4, PRC-862: declared only inside the mode rule, it vanished on exit
     and the SERP snapped back). */
  transition: margin-top .78s cubic-bezier(.4, .02, .14, 1), opacity .6s cubic-bezier(.4, 0, .2, 1);
}
.results-col {
  max-width: var(--content-col);
  width: 100%;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
}
.result-list { display: flex; flex-direction: column; gap: 12px; }

/* Title tones (mockup): sage/lilac/clay in the dark theme, one ink in
   light; the tone is a property of the query (app.main._title_tone). */
.result__title { color: var(--tone-sage); }
.results-main[data-tone="lilac"] .result__title { color: var(--tone-lilac); }
.results-main[data-tone="clay"] .result__title { color: var(--tone-clay); }
.result__title:visited, .result__title:visited:hover { color: var(--link-visited); }

.result {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px 14px;
  margin: 0 -14px;
  border-radius: 14px;
}
/* The result with the open summary carries the quiet active tint; the
    summary button mirrors it (mockup article[data-active]). */
.result.result--summary-active { background: var(--sum-active-bg); }
.result__row {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
}
/* Title + summary button sit in one shrinking wrapper (mockup): the button
   follows the title text at a 3px gap instead of the row's right edge. */
.result__headline {
  display: flex;
  align-items: center;
  gap: 3px;
  min-width: 0;
}
/* Inside the headline the button keeps its full 26px box (mockup) — the -3px
   vertical trim belongs to the old right-edge placement and shrinks the row
   below the mockup's 26px title line. */
.result__headline .summary-btn { margin: 0; }
.result__headline > .result__title {
  min-width: 0;
  font-size: 19px;
  font-weight: 500;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.result__title:hover { opacity: .78; }
.result__title:focus-visible { outline: var(--focus-ring); }
.summary-btn {
  position: relative;
  z-index: 2;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  background: transparent;
  border-radius: 8px;
  color: var(--text-faint);
  cursor: pointer;
}
.summary-btn svg { width: 15px; height: 15px; display: block; }
.summary-btn:hover { background: var(--hover-bg); color: var(--text-strong); }
.summary-btn:focus-visible { outline: var(--focus-ring); }
.result--summary-active .summary-btn { background: var(--hover-bg); color: var(--result-title); }
.result__meta {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding-left: 33px; /* favicon 22 + gap 11: text aligns with the title */
  font-size: 13px;
  line-height: normal; /* mockup: 15px box, not the body's 19.5px (R14) */
}
.result__site { flex: none; color: var(--result-site); }
.result__url {
  min-width: 0;
  color: var(--result-path);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.result__snippet {
  position: relative;
  z-index: 1;
  margin: 1px 0 0;
  padding-left: 33px;
  font-size: 15px;
  line-height: 1.5;
  color: var(--result-snippet);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  text-wrap: pretty;
}
.result__sources {
  margin-top: 2px;
  padding-left: 33px;
  font-size: 13px;
  line-height: normal; /* mockup: 15px box, not the body's 19.5px (R14) */
  color: var(--result-engines); /* light #8a857a, dark #7f8695 (R15) */
}
/* The §9.7 mark text rides the sources line through a middot — no plate,
   no extra row (ResultsStates.dc.html frame 01). */

/* «Искать ещё» (PRC-855): appends the next page's slice to the list —
   results-more.js fetches the /results/more fragment (progressive
   enhancement: without JS the href is a plain page-N+1 navigation, §13.3).
   The pill is 44px tall, so its 999px radius is the etalon's 22. */
.more-wrap { display: flex; justify-content: center; margin-top: 16px; }
.more-wrap[hidden] { display: none; }
.more-btn {
  position: relative; /* the positioning context for the rays layer */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 0 24px;
  border: none;
  border-radius: 999px;
  background: var(--more-bg);
  font: inherit;
  font-size: 15px;
  line-height: 1;
  color: var(--text-body);
  cursor: pointer;
  text-decoration: none;
}
.more-btn:hover { background: var(--more-bg-hover); color: var(--text-strong); opacity: 1; }
.more-btn:focus-visible { outline: var(--focus-ring); }
/* Rays around the button while the next page loads (the etalon is
   Results.dc.html's svg[data-rays-btn]): window.PerecleRays, attached by
   results-more.js (PRC-944). Loading also holds the hover fill and text with
   the pointer away (owner 02.10.2026; mockup ResultsStates 08 / ImagesStates 1f,
   PRC-1022) — the same two tokens as :hover, no new ones. One rule for both
   loading classes: the web button (.more-btn--loading, results-more.js) and
   the Images button (.imore2 .more-btn.is-loading, image-grid.js) behave
   alike, and on the phone, which has no pointer, alike as well. */
.more-btn--loading,
.imore2 .more-btn.is-loading {
  background: var(--more-bg-hover);
  color: var(--text-strong);
  cursor: progress;
}

/* Layout correction (ResultsStates.dc.html frame 02): one quiet line at the
   column's left edge — the mockup aligns it with the article favicon below,
   both are frame-content children there. Colour #6f6a60 / dark #8f96a6 (W7),
   the emphasis and the link keep their own tokens. */
.layout-correction {
  margin: 0 0 14px;
  font-size: 14px;
  color: var(--state-text);
}
.layout-correction strong { color: var(--text-body); font-weight: 600; }
.layout-correction__restore {
  margin-left: 10px;
  color: var(--tone-sage);
  white-space: nowrap;
}
.layout-correction__restore:hover { opacity: .78; }
.layout-correction__restore:focus-visible { outline: var(--focus-ring); background: var(--hover-bg); }

/* ---- Technical page (PRC-949, ResultsStates 03-05 / ErrorScreens /
   ImagesStates / ImagesCollections, README «Техническая страница»): ONE
   component for every state that is only a heading and a line of text — web
   empty / failed / nothing found, Картинки, поиск по картинке, Коллекции,
   404, 429, the dead Iskra link. The zone starts 110px from the page top,
   min-height 330px, content centred on both axes; no icons, no buttons. ---- */
.tstate {
  box-sizing: border-box;
  width: 100%;
  max-width: 800px;
  min-height: 330px;
  margin: -6px auto 0;
  padding: 0 24px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 9px;
  text-align: center;
}
.tstate[hidden] { display: none; }
.tstate__title {
  margin: 0;
  font-family: var(--brand-font);
  font-size: 27px;
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--state-title);
  text-wrap: balance;
  overflow-wrap: anywhere;
}
.tstate__text {
  margin: 0;
  max-width: 480px;
  font-size: 15px;
  line-height: 1.6;
  color: var(--state-text);
  text-wrap: pretty;
  overflow-wrap: anywhere;
}
/* A page that is only this state does not move (like body.start): no scroll,
   no rubber band. On a low screen — landscape phone, open keyboard — the zone
   would be cut, so there the page scrolls instead of clipping it. */
body.tech { overflow: hidden; }
@media (max-height: 520px) {
  body.tech { overflow-y: auto; }
}
/* .ipage already pulls itself 4px under the header: 2px more seats the zone at 110px. */
.ipage .tstate { margin-top: -4px; }
/* No rubber band at the top / bottom edge anywhere; panels with their own
   scroll keep `overscroll-behavior: contain`. */
html, body { overscroll-behavior-y: none; }

/* ---- «Мои пункты меню» dialog (MenuItemsModal.dc.html + the new macro in
   _macros.html). Desktop modal; the mobile sheet media query keeps parity
   with the old design's bottom sheet. Mechanics are prod's: icon via /icon,
   order by drag. ---- */
.cmenu-dialog {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px 24px 96px;
}
.cmenu-dialog[hidden] { display: none; }
.cmenu-dialog__backdrop {
  position: absolute;
  inset: 0;
  background: var(--cmenu-backdrop);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}
.cmenu-card {
  position: relative;
  width: 100%;
  max-width: 560px;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 26px;
  background: var(--surface);
  color: var(--text-body);
  /* The window floats on a shadow, not on a hairline
     (MenuItemsModal.dc.html data-modal: dark 0 30px 80px rgba(0,0,0,.55),
     light 0 24px 70px rgba(31,30,27,.22)). */
  box-shadow: var(--cmenu-modal-shadow);
}
.cmenu-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 20px 22px 14px;
}
.cmenu-head__text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
/* Head inks (MenuItemsModal.dc.html): the title reads #24211c / #e6eaf2 (not
   --text-strong), the close X #54504a in light (--text-muted's #8a857a is a
   step too pale there); dark keeps its current pair. */
/* line-height is pinned on the head and row text: the page's own 1.5 would
   otherwise grow both (the mockup draws them at `normal`), which is the same
   defect sheets.css pins for the phone. */
.cmenu-title { margin: 0; font-size: 18px; line-height: 1.15; font-weight: 600; letter-spacing: -.01em; color: var(--cmenu-title); }
.cmenu-sub { margin: 0; font-size: 13px; line-height: 1.15; color: var(--text-muted); }
.cmenu-ghost {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
}
.cmenu-ghost:hover { background: var(--hover-bg); color: var(--text-strong); }
.cmenu-ghost:focus-visible { outline: var(--focus-ring); }
.cmenu-back { margin-left: -6px; }
.cmenu-close { width: 34px; height: 34px; color: var(--cmenu-close); }
.cmenu-pane {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow-y: auto;
  /* PRC-897: a pane scrolled to its edge never chains into the page. */
  overscroll-behavior: contain;
  padding: 4px 22px 22px;
}
.cmenu-pane[hidden] { display: none; }
/* No hairline around the list (MenuItemsModal.dc.html data-tile, PRC-982):
   the tile is the soft fill alone. */
.cmenu-list {
  display: flex;
  flex-direction: column;
  border-radius: 18px;
  background: var(--cmenu-list-bg);
  overflow: hidden;
  position: relative;
}
/* Touch drag (custom-menu.js D1): the lifted row follows the finger while
   the gap marks the landing spot — the list is the positioning context. */
.cmenu-list--dragging { position: relative; touch-action: none; }
.cmenu-grip { touch-action: none; }
.cmenu-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  border: none;
  background: transparent;
  font: inherit;
  color: var(--text-body);
  text-align: left;
  cursor: pointer;
}
.cmenu-row:hover { background: var(--hover-bg); }
.cmenu-row:focus-visible { outline: var(--focus-ring); outline-offset: -3px; }
.cmenu-row.is-dragging { opacity: .85; }
/* Row actions (MenuItemsModal.dc.html it.edit / it.del): a pencil and a trash,
   both shown on row hover only, 32px squares. They appear on the desktop too
   since PRC-982 — deletion is one press from the row. */
.cmenu-row-acts { flex: none; display: flex; align-items: center; gap: 12px; opacity: 0; }
.cmenu-row:hover .cmenu-row-acts,
.cmenu-row:focus-within .cmenu-row-acts { opacity: 1; }
/* A touch screen has no hover to reveal them (the phone sheet shows its own
   always-on copy through body.m), so the desktop row keeps them visible. */
@media (hover: none) {
  .cmenu-row-acts { opacity: 1; }
}
.cmenu-row-act {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  border-radius: 9px;
  background: transparent;
  color: var(--cmenu-row-act-ink);
  cursor: pointer;
}
/* The mockup pulls the trash 8px back towards the pencil (it.del). */
.cmenu-row-act--delete { margin-left: -8px; color: var(--cmenu-row-act-ink); }
.cmenu-row-act:hover { background: var(--cmenu-row-act-hover); color: var(--text-strong); }
.cmenu-row-act--delete:hover { background: var(--cmenu-danger-hover); color: var(--cmenu-danger-ink); }
.cmenu-row-act:focus-visible { outline: var(--focus-ring); }
.cmenu-grip {
  flex: none;
  display: inline-flex;
  color: var(--cmenu-grip-ink);
  cursor: grab;
  opacity: .35;
}
.cmenu-row:hover .cmenu-grip { opacity: 1; }
.cmenu-grip svg { width: 16px; height: 16px; display: block; }
/* Row icon (MenuItemsModal.dc.html data-ic): the item's drawn glyph
   (PRC-865) in the 36x36 r11 tile; the stroke inherits the tile's ink. */
.cmenu-row-ic {
  flex: none;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 11px;
  background: var(--cmenu-icplate-bg);
  color: var(--cmenu-icplate-ink);
  overflow: hidden;
}
.cmenu-row-ic svg { width: 19px; height: 19px; display: block; }
.cmenu-row-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.cmenu-row-name {
  font-size: 15px;
  line-height: 1.15;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cmenu-row-url {
  font-size: 13px;
  line-height: 1.15;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cmenu-gap { height: 60px; border-top: 2px solid var(--tone-sage); border-radius: 2px; }
.cmenu-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 24px 26px 28px;
  text-align: center;
}
.cmenu-empty__plate {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 52px;
  border-radius: 15px;
  background: var(--cmenu-icplate-bg);
  color: var(--cmenu-empty-ink);
}
.cmenu-empty__text {
  margin: 0;
  max-width: 342px;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--text-muted);
  text-wrap: pretty;
}
/* «Добавить пункт» is terracotta-inked in light (#a8512f on a #dfd6c8
   border, MenuItemsModal.dc.html); dark keeps its current pair. */
.cmenu-add {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  height: 46px;
  margin-top: 14px;
  border: 1px solid var(--cmenu-add-line);
  border-radius: 15px;
  background: transparent;
  color: var(--cmenu-add-ink);
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
}
.cmenu-empty .cmenu-add { align-self: stretch; margin-top: 4px; }
.cmenu-add:hover:not(:disabled) { background: var(--cmenu-add-hover); }
.cmenu-add[hidden] { display: none; }
.cmenu-add:focus-visible { outline: var(--focus-ring); }
.cmenu-add:disabled { opacity: .5; cursor: not-allowed; }
.cmenu-limit { margin: 10px 0 0; font-size: 12.5px; color: var(--text-muted); text-align: center; }
.cmenu-field { display: flex; flex-direction: column; gap: 7px; margin-bottom: 18px; }
.cmenu-field__label { font-size: 13px; line-height: 1.15; color: var(--text-muted); }
.cmenu-field__input {
  height: 44px;
  padding: 0 14px;
  border: 1px solid var(--cmenu-input-line);
  border-radius: 13px;
  background: var(--cmenu-input-bg);
  color: var(--cmenu-input-ink);
  font: inherit;
  font-size: 15px;
}
/* Focus belongs to the dialog only: terracotta line on a white field in
   light, a white step in dark — never the page-wide --tone-sage. */
.cmenu-field__input:focus {
  outline: none;
  border-color: var(--cmenu-input-focus-line);
  background: var(--cmenu-input-focus-bg);
}
.cmenu-field__input.is-error { border-color: var(--danger); }
.cmenu-field__error { margin: 0; font-size: 12.5px; color: var(--danger); }
/* Icon picker (MenuItemsModal.dc.html, PRC-865): the «Иконка» label over a
   7-column grid of 44px tiles; the picked tile lights up (--cmenu-ic-on-*,
   terracotta in light / a white step in dark). The grid ships with the dialog
   shell but is built by custom-menu.js, like the rows. */
.cmenu-icpick { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
.cmenu-icpick .cmenu-field__label { margin: 0; }
.cmenu-icpick-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.cmenu-icpick-opt {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 44px;
  padding: 0;
  border: 1px solid var(--cmenu-ic-line);
  border-radius: 12px;
  background: var(--cmenu-ic-bg);
  color: var(--cmenu-ic-ink);
  cursor: pointer;
}
.cmenu-icpick-opt svg { width: 18px; height: 18px; display: block; }
.cmenu-icpick-opt:focus-visible { outline: var(--focus-ring); }
.cmenu-icpick-opt.is-on {
  background: var(--cmenu-ic-on-bg);
  border-color: var(--cmenu-ic-on-line);
  color: var(--cmenu-ic-on-ink);
}
.cmenu-line { height: 1px; background: var(--border); }
.cmenu-foot { display: flex; align-items: center; gap: 10px; margin-top: 18px; }
/* «Удалить пункт» (MenuItemsModal.dc.html data-danger, PRC-982): a hairline in
   the danger ink, 40px tall like the buttons beside it. */
.cmenu-danger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 14px;
  border: 1px solid var(--cmenu-danger-line);
  border-radius: 13px;
  background: transparent;
  color: var(--cmenu-danger-ink);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}
.cmenu-danger:hover { background: var(--cmenu-danger-hover); }
.cmenu-danger:focus-visible { outline: var(--focus-ring); }
.cmenu-foot__spacer { flex: 1 1 auto; }
/* «Отмена» in the form foot is an outlined ghost (MenuItemsModal.dc.html
   data-outline, PRC-982); the head's close cross stays a bare ghost. */
.cmenu-foot > .cmenu-ghost { height: 40px; padding: 0 16px; border-radius: 13px; font-size: 15px; }
.cmenu-outline { min-width: 0; border: 1px solid var(--cmenu-cancel-line); color: var(--cmenu-cancel-ink); }
.cmenu-outline:hover { background: var(--cmenu-row-act-hover); color: var(--text-strong); }
/* Editor primary: terracotta in light, the grey cream-on-ink button in dark
   (MenuItemsModal.dc.html base = dark, light lives in its [data-theme]
   override — the inverse of VoiceInput's base). */
.cmenu-btn-primary {
  height: 40px;
  padding: 0 18px;
  border: none;
  border-radius: 13px;
  background: var(--cmenu-primary-bg);
  color: var(--cmenu-primary-fg);
  font: inherit;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
}
.cmenu-btn-primary:hover { background: var(--cmenu-primary-hover); }
.cmenu-btn-primary:focus-visible { outline: var(--focus-ring); }

@media (max-width: 640px) {
  .cmenu-dialog { align-items: flex-end; padding: 0; }
  .cmenu-card { max-width: none; border-radius: 26px 26px 0 0; max-height: 86dvh; }
}

/* ============================================================================
   Translator block (translate-spec §5.2, design/translator-results.html).
   Sits between the search header and the collapsed iskra bar. FIXED FOOTPRINT:
   every state card (loading skeleton, ready, error) reserves the same
   min-height, so the result list and the iskra bar below never move when data
   arrives whatever the outcome — content swaps in place inside the same frame
   (CLS = 0). Uses only existing Perecle tokens — no hardcoded colours.
   ============================================================================ */
.tr { display: block; margin-bottom: 20px; }
.tr-card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--u-rinput);
  overflow: hidden;
  /* Fixed frame, reserved while the block is loading so the result list and the
     iskra bar below don't jump when data arrives (CLS = 0). Value = natural
     height of the skeleton, measured: desktop @1440 → 445px; mobile @375 →
     652px. The min-height is scoped to the loading skeleton via [data-tr]; the
     ready and error states size to their natural (compact) content — a
     dictionary-less translation no longer leaves dead space at the bottom
     (PRC-33 п.5). */
  min-height: var(--tr-frame, 445px);
  display: flex;
  flex-direction: column;
}
.tr-card:not([data-tr="loading"]) { min-height: 0; }
.tr-card > * { flex: none; }
@media (max-width: 640px) {
  .tr-card { --tr-frame: 652px; }
}

/* Head row: brand + language selectors + swap. */
.tr-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 16px; border-bottom: 1px solid var(--border);
}
.tr-brand { display: flex; align-items: center; gap: 6px; color: var(--spark); }
.tr-mark { width: 18px; height: 18px; flex: none; }
.tr-mark path { fill: currentColor; }
.tr-brand-name {
  font-family: var(--brand-font); font-size: 17px; font-weight: 400;
  letter-spacing: -0.01em; line-height: 1; color: var(--text-strong); white-space: nowrap;
}
.tr-langs { display: flex; align-items: center; gap: 6px; margin-left: auto; flex-wrap: wrap; }
.tr-lang {
  position: relative;
  display: inline-flex; align-items: center; gap: 5px;
  border: none; background: transparent; cursor: pointer;
  font-size: 13.5px; font-weight: 600; color: var(--deep); font-family: inherit;
  padding: 6px 9px; border-radius: 8px; white-space: nowrap;
}
.tr-lang:hover { background: var(--hover-bg); }
.tr-lang:focus-visible { outline: var(--focus-ring); }
.tr-lang svg { flex: none; color: var(--text-faint); }
.tr-swap {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border: none; background: transparent; border-radius: 8px;
  cursor: pointer; color: var(--text-muted);
}
.tr-swap:hover { color: var(--text-strong); background: var(--hover-bg); }
.tr-swap:focus-visible, .tr-iconbtn:focus-visible, .tr-chip:focus-visible,
.tr-dict-more:focus-visible, .tr-lang-opt:focus-visible {
  outline: var(--focus-ring);
}

/* Language chooser (PRC-35 п.13): a dropdown panel rendered in-flow below the
   head row. The card keeps overflow:hidden + a fixed frame, so the panel lives
   INSIDE the card (no popup clipping): a sticky search field over a capped,
   scrollable vertical list of up to ~100 languages. */
.tr-head { position: relative; }
.tr-lang-menu {
  display: flex; flex-direction: column; gap: 0;
  width: 100%; max-height: 320px;
  border-bottom: 1px solid var(--border);
  background: var(--bg-page);
}
.tr-lang-search {
  position: sticky; top: 0; z-index: 1;
  width: 100%; box-sizing: border-box;
  margin: 0; padding: 9px 12px;
  border: none; border-bottom: 1px solid var(--border);
  background: var(--surface);
  font: inherit; font-size: 13.5px; color: var(--text-body);
  outline: none;
}
.tr-lang-search:focus { outline: 2px solid var(--focus-color, var(--deep)); outline-offset: -2px; }
.tr-lang-search::placeholder { color: var(--text-faint); }
.tr-lang-list {
  overflow-y: auto; flex: 1; scroll-behavior: smooth;
  padding: 4px; scrollbar-width: thin;
}
.tr-lang-empty {
  margin: 0; padding: 14px 16px; text-align: center;
  font-size: 13px; color: var(--text-muted);
}
.tr-lang-opt {
  display: flex; align-items: baseline; gap: 8px; justify-content: space-between;
  width: 100%; box-sizing: border-box; text-align: left;
  border: none; background: transparent; color: var(--deep);
  border-radius: 6px; padding: 7px 11px; font: inherit; font-size: 13.5px;
  font-weight: 600; cursor: pointer;
}
.tr-lang-opt-ru { color: var(--deep); }
.tr-lang-opt-en {
  color: var(--text-muted); font-weight: 400; font-size: 12px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 42%;
}
.tr-lang-opt:hover { background: var(--hover-bg); }
.tr-lang-opt[data-active="true"] { background: var(--hover-bg); outline: 2px solid var(--focus-color, var(--deep)); outline-offset: -2px; }
.tr-lang-opt:focus-visible { outline: var(--focus-ring); }
.tr-lang-opt--sel { background: color-mix(in srgb, var(--deep) 12%, transparent); }

/* Panels: source + result side by side on desktop, stacked on mobile. The
   divider is a hairline between them in both orientations. */
.tr-panels { display: grid; grid-template-columns: 1fr 1fr; }
.tr-panel { padding: 14px 16px 12px; display: flex; flex-direction: column; gap: 8px; min-width: 0; position: relative; }
.tr-panel--src { border-right: 1px solid var(--border); }
@media (max-width: 640px) {
  .tr-panels { grid-template-columns: 1fr; }
  .tr-panel--src { border-right: none; border-bottom: 1px solid var(--border); }
}
.tr-text {
  font-size: 16px; line-height: 1.5; color: var(--text-body);
  min-height: 48px; /* 2 lines reserved — no jump when text arrives */
  word-break: break-word;
}
/* Editable source field: visually a plain text row (transport of the mock's
   static div), transparent chrome, font inherits the panel text. */
.tr-text--src {
  width: 100%; border: none; background: transparent; outline: none;
  font-family: inherit; padding: 0; resize: none;
  /* An <input> vertically centers its text in its content box, whereas the
     sibling output <div> top-aligns. The shared .tr-text min-height: 48px
     would force the input's single line down by ~12px, misaligning the two
     baselines (PRC-28 п.6). The source is always one line (maxlength 200,
     inputs don't wrap), so reset min-height: the field becomes exactly one
     line-box tall and its line sits on the same baseline as the output's
     first line. The 48px reservation only matters for the async output. */
  min-height: auto;
}

.tr-text--src::placeholder { color: var(--text-faint); }
.tr-text--out { font-weight: 600; color: var(--text-strong); padding-right: 40px; }
.tr-transcription {
  font-size: 13.5px; color: var(--text-muted);
  margin-top: -4px;
}
.tr-transcription[hidden] { display: none; }
.tr-panel-foot { display: flex; align-items: center; gap: 2px; margin-top: auto; }
/* Copy affordance at the top-right corner of the result panel (PRC-33 п.10).
   Absolutely placed against the position:relative .tr-panel, so it never
   disturbs the text flow; the result text has matching right padding. */
.tr-out-copy { position: absolute; top: 10px; right: 10px; }
.tr-spacer { flex: 1; }

/* Icon buttons: 32px hit area, muted ink, hover on hover-bg, visible focus,
   active/pressed state reflected via aria-pressed + deep accent. */
.tr-iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border: none; background: transparent; border-radius: 8px;
  cursor: pointer; color: var(--text-muted); position: relative;
}
.tr-iconbtn:hover { color: var(--text-strong); background: var(--hover-bg); }
.tr-iconbtn[aria-pressed="true"] { color: var(--deep); background: color-mix(in srgb, var(--deep) 12%, transparent); }
.tr-iconbtn[hidden] { display: none; }
/* Play buttons keep their 32px slot when hidden so the panel foot never jumps
   (PRC-44/2). visibility (not display) reserves the box and drops it from the
   a11y/focus order. */
.tr-iconbtn--vhidden { visibility: hidden; }
/* Playing indicator: three bars pulsing inside the button. */
.tr-eq { display: none; align-items: flex-end; gap: 2px; height: 12px; }
.tr-eq i { width: 2.5px; background: currentColor; border-radius: 1px; animation: trEq 0.9s ease-in-out infinite; }
.tr-eq i:nth-child(1) { height: 5px; animation-delay: 0s; }
.tr-eq i:nth-child(2) { height: 11px; animation-delay: .18s; }
.tr-eq i:nth-child(3) { height: 7px; animation-delay: .36s; }
@keyframes trEq { 0%,100%{ transform: scaleY(.55);} 50%{ transform: scaleY(1);} }
@media (prefers-reduced-motion: reduce) { .tr-eq i { animation: none; } }
.tr-iconbtn--playing { color: var(--deep); background: color-mix(in srgb, var(--deep) 12%, transparent); }
.tr-iconbtn--playing .tr-eq { display: inline-flex; }
.tr-iconbtn--playing .tr-ic-default { display: none; }
/* Copied confirmation */
.tr-copied {
  position: absolute; inset: 0; display: none; align-items: center; justify-content: center;
  color: var(--deep);
}
.tr-iconbtn--copied .tr-copied { display: inline-flex; }
.tr-iconbtn--copied .tr-ic-default { display: none; }
.tr-ic-default { display: inline-flex; }

/* Dictionary */
.tr-dict { border-top: 1px solid var(--border); padding: 14px 16px 12px; display: flex; flex-direction: column; gap: 12px; }
.tr-dict-title { font-size: 12px; font-weight: 600; letter-spacing: .03em; color: var(--text-muted); }
.tr-dict-group { display: flex; flex-direction: column; gap: 7px; }
.tr-dict-pos { font-size: 14px; color: var(--text-body); }
.tr-dict-pos b { font-weight: 600; color: var(--text-strong); }
.tr-dict-pos .pos { color: var(--spark); font-size: 12.5px; font-weight: 600; margin-left: 6px; }
.tr-dict-variants { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.tr-chip {
  border: 1px solid var(--border); background: var(--bg-page); color: var(--deep);
  border-radius: 999px; padding: 3px 11px; font-size: 13px; font-weight: 600; cursor: pointer;
  font-family: inherit;
}
.tr-chip:hover { background: var(--hover-bg); }
.tr-chip--main { background: color-mix(in srgb, var(--deep) 12%, transparent); border-color: transparent; }
.tr-dict-gloss { font-size: 13px; color: var(--text-muted); }
.tr-examples { display: flex; flex-direction: column; gap: 8px; }
.tr-examples-title { font-size: 12px; font-weight: 600; letter-spacing: .03em; color: var(--text-muted); }
.tr-example { display: flex; gap: 8px; align-items: flex-start; font-size: 13.5px; line-height: 1.5; }
.tr-example .mk { flex: none; color: var(--text-faint); margin-top: 1px; }
.tr-example-en { color: var(--text-body); }
.tr-example-en b { color: var(--text-strong); font-weight: 600; }
.tr-example-ru { color: var(--text-muted); font-size: 13px; }
.tr-dict-more-wrap { border-top: 1px solid var(--border); }
.tr-dict-more-wrap--sk { display: flex; justify-content: center; padding: 10px 16px; }
.tr-dict-more {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; border: none; background: transparent; cursor: pointer; font-family: inherit;
  padding: 10px 16px; font-size: 13px; font-weight: 650; color: var(--deep); border-radius: 0 0 var(--u-rinput) var(--u-rinput);
}
.tr-dict-more:hover { background: var(--hover-bg); }
.tr-dict-more svg { transition: transform .2s ease; }
.tr-dict-more[aria-expanded="true"] svg { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .tr-dict-more svg { transition: none; } }
.tr-dict-extra[hidden] { display: none; }

/* Error state: the block degrades quietly — one calm line, no alert colours,
   the results below stay fully usable. The line is top-aligned inside the SAME
   fixed frame (min-height), so a failure never moves the SERP either: the block
   does not collapse after an unsuccessful load. */
.tr-error { display: flex; align-items: center; gap: 10px; padding: 14px 16px; font-size: 13.5px; color: var(--text-muted); }
.tr-error svg { flex: none; color: var(--text-faint); }

/* Loading skeleton: pulsing bars fill the whole reserved frame — head, both
   panels, the dictionary zone and the «Показать ещё» strip — so the skeleton's
   footprint equals the ready state exactly and the result list below stays
   pixel-locked while data loads. */
@keyframes trSk { 0%,100%{opacity:.45;} 50%{opacity:1;} }
@media (prefers-reduced-motion: reduce) { .tr-sk { animation: none !important; opacity: .6; } }
.tr-sk { background: var(--hover-bg); border-radius: 7px; animation: trSk 1.6s ease-in-out infinite; }
.tr-sk-fill { flex: 1 1 auto; } /* stretches so the skeleton always fills the frame */

/* ============================================================================
   Images vertical (images-plan §3, design/ImagesResults.dc.html).
   Reuses the shared theme tokens; image-specific layout tokens scoped to .images.
   ============================================================================ */
.images {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  --img-col: 1080px;
  --tile-gap: 14px;
  --masonry-cols: 4;
  --just-row-h: 200px;
  --land-search: 600px;
}
@media (max-width: 980px) { .images { --masonry-cols: 3; } }
@media (max-width: 640px) {
  .images {
    --masonry-cols: 2;
    --tile-gap: 8px;
    --just-row-h: 120px;
    --land-search: 100%;
  }
}

/* ---- iskra-1 AI overview (ai-plan §9.15, ported from design/IskraResults.html).
   Sits above the result list in the same column; a single flat surface card —
   no border, no heavy shadow (owner №7, PRC-885) — so it never outshouts the
   SERP. The spark is the only warm accent; [n] footnotes and sources use the
   deep/muted inks. ---- */
/* The dialog is a flat column of messages (IskraResults.dc.html,
   Results.dc.html after entering the mode): the question that opened it, the
   answer card, then every follow-up — siblings 14px apart, the same 14px the
   thread itself uses, so the first turn is spaced like all the others
   (PRC-839). */
.iskra { display: flex; flex-direction: column; gap: 14px; }
.iskra[hidden] { display: none; }

/* ---- Iskra dialog mode (Results.dc.html): the thread lives in a fixed
   panel over the top two-thirds of the viewport (68vh − 26px, the mockup's own
   arithmetic), sliding down over the page; the SERP dims to .38 and the
   capsule steps under the panel. The panel is a SIBLING of main (results.html,
   PRC-862), so the dim never touches the dialog. Entry/exit gestures and the
   pod's chip-toggle/«Поиск» exits are iskra.js's; these rules are pure
   state-on-body styling. The panel is transparent — it floats over the page
   background exactly like the mockup, with soft masks fading its top and
   bottom edges. The top mask stays fully transparent through 66px and the
   inner's top padding is 84px so the fixed «Поделиться диалогом» button
   (y 33–65 at 1280, 16–48 at 375) never overlaps thread text. ---- */
.iskra-thread-panel {
  position: fixed; left: 0; right: 0; top: 0; height: calc(68vh - 26px);
  z-index: 55; overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: none; display: flex; flex-direction: column-reverse;
  pointer-events: none; transform: translateY(-100%);
  transition: transform .78s cubic-bezier(.4, .02, .14, 1);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, transparent 66px, #000 84px, #000 calc(100% - 22px), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, transparent 66px, #000 84px, #000 calc(100% - 22px), transparent 100%);
}
.iskra-thread-panel::-webkit-scrollbar { width: 0; height: 0; }
.iskra-thread-inner {
  box-sizing: border-box; width: 100%; max-width: 848px; margin: 0 auto;
  padding: 84px 24px 18px; display: flex; flex-direction: column; gap: 14px;
}
.iskra-thread-inner .iskra { margin: 0; }
body[data-imode="iskra"] .iskra-thread-panel { pointer-events: auto; transform: translateY(0); }
/* The wordmark stays clickable in the dialog mode (PRC-880): the panel is
   transparent, so the mark shows through it — but the panel's pointer
   surface (z-index 55) swallowed every click, and the logo led nowhere.
   Lift it one level above the panel: it hangs 15px left of the 848px column
   (the thread-inner shares that column), so it covers no thread content.
   Below 1180px (and data-brandfit="0") the outer mark is hidden and the
   capsule watermark takes over — the capsule travels below the panel, so
   its link was never covered. */
body[data-imode="iskra"] .rheader__brand { z-index: 56; }
/* The capsule travels down under the thread; the wordmark stays where it is.
   Moving the whole header by margin instead left the capsule pinned at
   top:10px (it is fixed) and sent the wordmark down alone (Results.dc.html). */
body[data-imode="iskra"] .rheader[data-geo="1"] .searchbar--results { top: calc(68vh - 26px); }
/* The mode dims the SERP only (Results.dc.html dims its main): the dialog
   panel is a sibling of main (results.html, PRC-862), so the thread, its
   text and its hover never lose saturation (owner №2). Hovering the SERP
   lifts its own dim, exactly the mockup's main:hover. */
body[data-imode="iskra"] .results-main {
  margin-top: calc(68vh - 40px);
  opacity: .38;
}
body[data-imode="iskra"] .results-main:hover { opacity: .72; }

/* «Отправить» — the Iskra circle in the capsule's button row, shown only
   while the dialog mode is on: the mockup's filled data-send (#2f313a, hover
   #3a3d47; light theme: spark orange with a white arrow). The old quiet-X
   exit circle beside it is gone (owner №3, PRC-862 — Results.dc.html draws
   no exit control in the capsule). */
.cap-send { display: none; background: var(--cap-send-bg); color: var(--cap-send-fg); }
body[data-imode="iskra"] .cap-send { display: inline-flex; }
.cap-send:hover { background: var(--cap-send-hover); color: var(--cap-send-fg); }
.cap-send:focus-visible { outline: var(--focus-ring); }
/* The «Искра» pod chip reads as the active service while the dialog is on
   (the mockup's data-miskra active state). */
body[data-imode="iskra"] .rmenu__pill--iskra { color: var(--spark); }
body[data-imode="iskra"] .rmenu__pill--iskra:hover { color: var(--spark); }
/* The «Поиск» pill must NOT read as the active service while the dialog is
   on (owner 23.09.2026, PRC-901): the mode belongs to the «Искра» chip, so
   the pill dims to the plain pill ink and hovers like an ordinary pill
   (server render keeps service-link--active — outside the mode it is the
   active one). aria-current rides along (iskra.js enter/exitMode). */
body[data-imode="iskra"] .rmenu .service-link--live[data-menu-search] { color: var(--menu-pill); }
body[data-imode="iskra"] .rmenu .service-link--live[data-menu-search]:hover { color: var(--menu-pill-active); }

.iskra-spark { width: 15px; height: 15px; flex: none; }
.iskra-spark path { fill: var(--spark); }
.iskra-spark--anim path {
  transform-box: fill-box; transform-origin: center;
  animation: sparkTwinkle 1.5s ease-in-out infinite;
}

/* Overview card (streaming / ready) */
/* Card chrome (IskraAnswerDensity.dc.html data-card): 14/16/12 padding, 14px
   radius, 11px rows — one shape for the answer card and every thread card.
   Owner №7 (PRC-885): no border — the surface tone alone separates the card
   from the page, both themes (#fff / #1c1d22 are the mockup's own surfaces). */
.iskra-card {
  background: var(--surface); border: 0; border-radius: 14px;
  padding: 14px 16px 12px; display: flex; flex-direction: column; gap: 11px;
}
.iskra-card--streaming {
  gap: 0;
}
.iskra-card--streaming .iskra-head {
  min-height: 28px; align-items: center;
}
/* Failure states (IskraFailure.dc.html, PRC-833 — replaces the PRC-653
   translator-style notice): ONE quiet card for every no-answer failure — the
   spark dims to grey (the mark stays, the voice does not), the copy says what
   to do next, never the reason. A mid-stream break keeps the written text:
   faded through an alpha mask, capped with the quiet cut marker, with the
   notice riding a hairline rule under it. Theme variables only, so dark is
   free. */
.iskra-card--error { padding: 14px 16px 13px; border-radius: 14px; }
.iskra-fail { display: flex; align-items: flex-start; gap: 11px; }
.iskra-fail .iskra-spark { margin-top: 3px; }
.iskra-fail__text {
  margin: 0; font-size: 14.5px; line-height: 1.55;
  color: var(--card-ink); text-wrap: pretty;
}
.iskra-fail--rule { padding-top: 12px; margin-top: 2px; border-top: 1px solid var(--rule); }
.iskra-spark--off { opacity: .45; }
.iskra-spark--off path { fill: var(--spark-off); }
/* Registration gate (auth_required): the fail row's quiet card, but the copy
   carries the registration ask and a text CTA into /auth/login under it. */
.iskra-gate { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.iskra-gate__cta {
  align-self: flex-start; font-size: 14px; font-weight: 600;
  color: var(--link-url); text-decoration: none;
}
.iskra-gate__cta:hover { text-decoration: underline; }
.iskra-gate__cta:focus-visible { outline: var(--focus-ring); }
/* The broken answer itself: everything received stays readable, the bottom
   fades out — the mask is alpha-only, so it works in both themes untouched.
   Looser 1.75 line-height is the mockup's own for this state. */
.iskra-answer-cut {
  margin: 0; line-height: 1.75;
  -webkit-mask-image: linear-gradient(to bottom, #000 62%, rgba(0, 0, 0, .35) 100%);
  mask-image: linear-gradient(to bottom, #000 62%, rgba(0, 0, 0, .35) 100%);
}
.iskra-caret-off {
  display: inline-block; width: 2px; height: 1.05em; margin-left: 1px;
  vertical-align: -2px; background: var(--caret-off);
}
.iskra-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.iskra-brand { display: flex; align-items: center; gap: 8px; }
.iskra-name {
  font-size: 14px; font-weight: 600; letter-spacing: .01em;
  color: var(--text-strong); white-space: nowrap;
}
.iskra-status { font-size: 13px; color: var(--text-muted); white-space: nowrap; }

.iskra-toggle {
  display: inline-flex; align-items: center; gap: 6px; border: none; background: transparent;
  cursor: pointer; font-family: inherit; font-size: 13px; color: var(--text-muted);
  padding: 4px 7px; border-radius: 8px;
}
.iskra-toggle:hover { color: var(--text-strong); background: var(--hover-bg); }
.iskra-toggle:focus-visible { outline: var(--focus-ring); }
.iskra-toggle svg { flex: none; }

.iskra-answer { font-size: 15px; line-height: 1.75; color: var(--card-ink); text-wrap: pretty; }
.iskra-print { white-space: pre-wrap; }
/* Flat answer card (IskraResults.dc.html / IskraAnswerDensity.dc.html,
   PRC-833): the whole answer is one block of paragraphs — 15/1.75, the
   mockup's own line height for this state — no head, no «Подробнее» fold. */
.iskra-answer-p { margin: 0; }
.iskra-answer-p + .iskra-answer-p { margin-top: 12px; }
/* Fact bullets: quiet dash list under the paragraph, same ink. */
.iskra-bullets { margin: 10px 0 0; padding: 0; list-style: none; }
.iskra-bullets li { position: relative; padding-left: 16px; font-size: 14px; line-height: 1.6; }
.iskra-bullets li + li { margin-top: 4px; }
.iskra-bullets li::before {
  content: ""; position: absolute; left: 2px; top: .72em;
  width: 5px; height: 5px; border-radius: 50%; background: var(--spark);
}
/* Fact table «ключ — значение» (IskraAnswerDensity.dc.html): a grid of rows
   filling the card's full width, three columns of them; each row is key,
   dotted leader, value — the mockup's dotted leaders included. Key is muted
   small caps-ish, value is tabular. Absent facts render nothing at all. */
.iskra-facts {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: 28px; margin: 0; padding: 8px 0 0;
  border-top: 1px solid var(--rule);
}
.iskra-fact { display: flex; align-items: baseline; gap: 7px; padding: 4px 0; margin: 0; }
/* PRC-893: a value is never allowed to overlap its neighbours or leave the
   card, at any length — it shrinks within its grid column and wraps by words
   (long unbreakable tokens break too). The dotted lead yields: it stretches
   when the row is short and collapses when the value takes the width. The
   key keeps the mockup's flex:none but is capped at 60% of the row so a
   pathological key wraps instead of pushing the value out of the card. */
.iskra-fact dt { flex: none; max-width: 60%; overflow-wrap: anywhere; font-size: 12.5px; color: var(--text-muted); }
.iskra-fact__lead { flex: 1 1 auto; position: relative; top: -3px; height: 0; border-bottom: 1px dotted var(--fact-lead); }
.iskra-fact dd { flex: 0 1 auto; min-width: 0; overflow-wrap: anywhere; margin: 0; font-size: 13.5px; color: var(--fact-value); font-variant-numeric: tabular-nums; }
.iskra-caret {
  display: inline-block; width: 2px; height: 1.05em; background: var(--spark);
  margin-left: 3px; vertical-align: -3px; animation: caretBlink 1.05s step-end infinite;
}

/* Answer row (IskraResults.dc.html): the paragraph(s) and, when a photo
   landed, ONE cover-cropped 190px frame stretching with the text (min-height
   118px) — gap 16px. Everything else the card carries (bullets, fact table,
   sources, footnote) is a full-width sibling UNDER this row, never squeezed
   into the text column beside the photo: the mockup's fact table spans the
   whole card. */
.iskra-row { display: flex; align-items: stretch; gap: 16px; }
.iskra-row .iskra-answer { flex: 1 1 auto; min-width: 0; }
/* Top-1 photo (PRC-129; box per IskraResults.dc.html): 190px wide, cover —
   the redesign mockup explicitly crops; the PRC-218 letterbox posture is
   superseded by it. The photo column (PRC-977, design/iskra-photo-mark/):
   the frame plus its own §9.7 line stacked 6px apart; without a mark the
   column is pixel-for-pixel the frame alone. */
.iskra-photo-col { flex: 0 0 190px; display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.iskra-photo {
  position: relative; display: block; flex: 1 1 auto; min-height: 118px;
  border-radius: 9px; overflow: hidden; background: var(--photo-bg);
}
.iskra-photo:focus-visible { outline: var(--focus-ring); }
.iskra-photo__img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
}
.iskra-photo--sk { animation: trSk 1.6s ease-in-out infinite; }
/* The photo's own §9.7 line — same look as .iskra-disclaimer (it carries that
   class too); this is only a placement/selector hook. */
.iskra-photo-mark { margin: 0; }

@media (max-width: 640px) {
  /* Row collapses to one column: photo full-width, capped at 190px, directly
     under the leading answer text (reading order: text -> photo -> extras). */
  .iskra-row { flex-direction: column; gap: 12px; }
  .iskra-photo-col { flex: none; width: 100%; }
  .iskra-photo { flex: none; min-height: 0; height: 190px; }
}

/* Sources as chips (IskraResults.dc.html): ONE row — the quiet «Источники»
   label, one pill per source (favicon through /icon + the bare host) and the
   «ещё N» overflow pressed to the right edge. Replaces the numbered list —
   no per-chip summary buttons. */
.iskra-chips {
  display: flex; align-items: center; flex-wrap: wrap; gap: 7px;
  padding-top: 10px; border-top: 1px solid var(--rule);
}
.iskra-chips-title {
  font-size: 12px; color: var(--chips-title); /* light #8a857a, dark #7f8695 (PRC-848) */
}
.iskra-chip {
  display: inline-flex; align-items: center; gap: 6px; height: 24px;
  padding: 0 7px; border-radius: 999px; background: var(--chip-bg);
  font-size: 12.5px; color: var(--chip-fg); text-decoration: none;
}
.iskra-chip:hover { background: var(--chip-hover); color: var(--text-strong); }
.iskra-chip:focus-visible { outline: var(--focus-ring); }
.iskra-chip__fav { width: 13px; height: 13px; border-radius: 3px; display: block; }
.iskra-chip--more {
  margin-left: auto; height: 24px; padding: 0 7px; background: transparent;
  border: 1px solid var(--chip-ring); color: var(--text-muted);
}
.iskra-chip--more:hover { background: var(--chip-hover); color: var(--text-strong); }
/* «Просмотрено N страниц» — the card's own coverage line (the mockup's short
   form; the chips themselves show what made it into the answer). */
.iskra-pages { margin: 0; font-size: 11.5px; line-height: 1.4; color: var(--text-faint); text-wrap: pretty; }
.iskra-disclaimer { margin: 0; font-size: 11.5px; line-height: 1.4; color: var(--card-foot); text-wrap: pretty; }
/* Share-by-link (PRC-892, design/redesign-2026-09/IskraShare.spec.md). The
   card's last row becomes a flex line: the disclaimer stays as it was, the
   quiet link glyph sits at its right end. The −6px margins eat the 28px hit
   box, so the card keeps its height and the glyph lands on the content edge. */
.iskra-foot { display: flex; align-items: center; gap: 12px; }
.iskra-foot .iskra-disclaimer { flex: 1 1 auto; min-width: 0; }
.iskra-foot { position: relative; }
.iskra-share, .iskra-share-dialog {
  display: inline-flex; align-items: center; box-sizing: border-box;
  border: 0; border-radius: 999px; background: transparent; color: var(--text-muted);
  font: inherit; font-weight: 500; line-height: 1; white-space: nowrap; cursor: pointer;
  transition: color .15s ease;
}
.iskra-share svg, .iskra-share-dialog svg { flex: none; }
.iskra-share {
  flex: none; height: 28px; min-width: 28px; padding: 0 6px; justify-content: center;
  margin: -6px -6px -6px 0; font-size: 12px;
}
/* PRC-950 (IskraShare.spec.md §3): hover and the open panel only brighten the glyph — no pill. */
.iskra-share:hover, .iskra-share[aria-expanded="true"] { color: var(--text-strong); }
.iskra-share:focus-visible, .iskra-share-dialog:focus-visible { outline: var(--focus-ring); outline-offset: 0; }
.iskra-share[aria-busy="true"] { opacity: .45; cursor: progress; }
/* «Поделиться диалогом» (IskraShare.spec.md §2): fixed above the thread panel,
   centred on the thread column (the window's middle; with the summary panel
   open, the middle of what is left of it) on the wordmark's line — top 33px,
   32px tall. Quiet: --text-faint, 12.5px/400, brightens on hover, no pill.
   Dialog mode only; it rides in and out with the panel. `transform` is the
   entrance (translateY) AND the centring (-50%) in one function. */
.iskra-share-dialog {
  position: fixed; z-index: 56; top: 33px; height: 32px; padding: 0 10px;
  font-size: 12.5px; font-weight: 400; color: var(--text-faint);
  left: 50%;
  opacity: 0; pointer-events: none; transform: translate(-50%, -14px);
  transition: color .15s ease, opacity .4s ease, transform .78s cubic-bezier(.4, .02, .14, 1);
}
.iskra-share-dialog[hidden] { display: none; }
.iskra-share-dialog svg { margin-right: 6px; }
body[data-imode="iskra"] .iskra-share-dialog { opacity: 1; pointer-events: auto; transform: translate(-50%, 0); }
.iskra-share-dialog:hover, .iskra-share-dialog[aria-expanded="true"] { color: var(--text-strong); }
body[data-imode="iskra"] .iskra-share-dialog[aria-busy="true"] { opacity: .45; cursor: progress; }
body[data-imode="iskra"] .iskra-share-dialog[aria-disabled="true"] { opacity: .45; cursor: default; }
.iskra-share-dialog[aria-disabled="true"]:hover { color: var(--text-faint); }
/* The panel under each button (§4.3): 280 wide, shadowed — it lies over the thread. */
.sharepanel--iskra { width: 280px; box-shadow: var(--ig-popsh); }
/* The error state (IskraShare.dc.html «Ошибка»): the caption and the line right under it —
   the emptied link row must not add a second gap, the line has the plain leading. */
.sharepanel--iskra.is-error .sharepanel__row { display: none; }
.sharepanel--iskra .sharepanel__err { line-height: normal; }
.sharepanel--dialog { position: fixed; z-index: 57; top: 73px; left: 50%; transform: translateX(-50%); }
body:not([data-imode="iskra"]) .sharepanel--dialog { display: none; }
.iskra-foot .sharepanel--answer { position: absolute; z-index: 5; right: 0; top: calc(100% + 14px); }
@media (min-width: 1100px) {
  body.results.summary-open .iskra-share-dialog,
  body.results.summary-open .sharepanel--dialog { left: calc((100vw - var(--summary-panel-w)) / 2); }
}
@media (max-width: 639px) {
  .iskra-foot { align-items: flex-end; }
  .iskra-share-dialog { top: 16px; }
  .sharepanel--dialog { top: 56px; }
}
@media (prefers-reduced-motion: reduce) {
  .iskra-share, .iskra-share-dialog { transition: none; }
}
/* "По общим данным" badge (PRC-128): the answer is the model's own knowledge, not
   our sources. Deliberately quiet — the PRC-125 layout is not approved yet, so the
   whole look is this one rule. */
.iskra-general {
  align-self: flex-start; display: inline-flex; align-items: center;
  margin-top: 2px; padding: 2px 9px; border: 1px solid var(--border);
  border-radius: 999px; font-size: 12px; color: var(--text-muted);
}
.iskra-answer .iskra-general { margin-top: 6px; }

/* Follow-up dialog thread (M-AI-3, IskraResults.dc.html): user bubbles and
   iskra answer CARDS as siblings, 14px apart — every answer carries the same
   card chrome and its own footnote, exactly as the mockup renders a thread. */
.iskra-thread { display: flex; flex-direction: column; gap: 14px; }
.iskra-turn-q { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
/* User bubble (data-ubub): 62% max width, 11/15 padding, 16/16/6/16 corners,
   its own fill — no border in either theme. */
.iskra-bubble {
  max-width: 62%; background: var(--bubble-bg);
  border-radius: 16px 16px 6px 16px; padding: 11px 15px;
  font-size: 15px; line-height: 1.5; color: var(--bubble-fg); text-wrap: pretty;
}
.iskra-corrected { font-size: 12.5px; color: var(--text-faint); }

/* Collapsed bar */
.iskra-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 16px;
  padding: 12px 16px;
}
.iskra-bar-left { display: flex; align-items: center; gap: 9px; min-width: 0; }
.iskra-bar-hint {
  font-size: 13px; color: var(--text-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.iskra-bar .iskra-toggle {
  color: var(--deep); font-weight: 650;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.iskra-bar .iskra-toggle:hover { color: var(--deep); opacity: .8; background: transparent; }

@keyframes caretBlink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .iskra-spark--anim path { animation: sparkPulse 3.4s ease-in-out infinite; }
  .iskra-caret { animation: none; opacity: 1; }
  .iskra-photo--sk { animation: none; opacity: .6; }
}
/* ---- Lightbox (A-IMG1.6, design/ImagesResults.dc.html:191-216) ---- */
/* One continuous card (18px radius) wrapping stage + panel; backdrop 10/9/8/.74. */
body.ilb-open { overflow: hidden; }
.ilb {
  position: fixed; inset: 0; z-index: 100; display: flex; align-items: center;
  justify-content: center; padding: 26px;
}
.ilb[hidden] { display: none; }
.ilb__backdrop { position: absolute; inset: 0; background: rgba(10,9,8,.74); }
.ilb__card {
  position: relative; z-index: 1; display: flex; align-items: stretch;
  width: min(var(--lb-w, 1000px), 100%); max-height: calc(100vh - 52px);
  background: var(--surface); border: 0;
  border-radius: 18px; overflow: hidden;
}
/* The stage is a dark room in BOTH themes (SummaryStates.dc.html
   [data-lb-stage]: #15171d) — the image floats on it; the panel keeps the
   card's own surface. */
.ilb__stage {
  flex: 1 1 auto; min-width: 0; min-height: var(--lb-img-min, 300px);
  display: flex; align-items: center; justify-content: center; background: #15171d;
}
.ilb__img {
  max-width: 100%; max-height: 100%; object-fit: contain;
  border-radius: 0; background: var(--surface);
}
/* Lightbox preload state (images-plan §4): the full image is fetched+decoded
   off-DOM before the visible <img> swaps, so the stage and the panel update in
   the same frame. While .ilb--loading is on the root, the stale image is hidden
   and a spinner rides over the stage; the panel is dimmed to signal the swap.
   Additive only — no existing rule is altered. */
.ilb__stage { position: relative; }
.ilb--loading .ilb__img { opacity: 0; }
.ilb--loading .ilb__panel { opacity: .45; }
/* Spinner over the dark stage (SummaryStates.dc.html frame 03): the ring is
   translucent white, the lit arc cream — readable on #15171d in both themes. */
.ilb__stage::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 34px; height: 34px; margin: -17px 0 0 -17px; border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, .22); border-top-color: #ece9e1;
  opacity: 0; pointer-events: none;
}
.ilb--loading .ilb__stage::after { opacity: 1; animation: ilb-spin .8s linear infinite; }
@keyframes ilb-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .ilb--loading .ilb__stage::after { animation: none; }
}
.ilb__panel {
  flex: none; width: var(--lb-panel, 320px); max-width: 40vw; padding: 20px;
  display: flex; flex-direction: column; gap: 15px; overflow: auto;
  border-left: 1px solid var(--border);
}
/* Panel order (design): title → favicon+domain → dims → attribution → actions → RKN. */
.ilb__title { font-size: 16px; font-weight: 600; color: var(--text-strong); line-height: 1.35; }
.ilb__site { display: flex; align-items: center; gap: 9px; min-width: 0; }
.ilb__favicon {
  flex: none; width: 24px; height: 24px; border-radius: 50%; background-size: cover;
  background-position: center; background-color: var(--hover-bg); color: var(--text-muted);
  display: inline-flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 600;
}
.ilb__domain {
  min-width: 0; font-size: 14px; color: var(--link-url); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.ilb__domain:hover { opacity: .8; }
.ilb__dims { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text-muted); }
.ilb__dims svg { flex: none; }
.ilb__rkn { font-size: 12px; line-height: 1.35; color: var(--text-faint); padding-top: 2px; }
.ilb__actions { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.ilb__act {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 11px 14px;
  border: 1px solid var(--border); border-radius: var(--u-rpill, 10px); background: var(--surface);
  color: var(--card-ink); font: inherit; font-size: 14px; font-weight: 600; cursor: pointer; text-align: center;
}
.ilb__act svg { flex: none; }
.ilb__act:hover { background: var(--hover-bg); opacity: 1; }
/* Primary action (SummaryStates.dc.html [data-lb-primary]): 279×38 at
   14px/500, radius 10, icon-to-label gap 7 — line-height 1 keeps the box at
   38px (11+11 padding + 14 line + 2 border) against the old 45. */
.ilb__act--primary {
  gap: 7px; font-weight: 500; line-height: 1; border-radius: 10px;
  background: var(--deep); border-color: var(--deep); color: var(--on-deep);
}
.ilb__act--primary:hover { background: var(--deep); }
.ilb__action-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.ilb__act--icon { flex-direction: column; gap: 5px; min-height: 58px; padding: 11px 4px; font-size: 11.5px; font-weight: 500; }
/* Кнопка выключенной функции в панели лайтбокса (S6, PRC-839,
   SummaryStates.dc.html): «В коллекцию» и «Найти похожие» стоят на своих
   местах погашенными — тише заливка, тише рамка, тише подпись; наведение
   ничего не поднимает. */
.ilb__act[data-soon],
.ilb__act[data-soon]:hover {
  background: var(--soon-btn-bg);
  border-color: var(--soon-btn-border);
  color: var(--soon-btn-ink);
}
/* Share: the button is a normal grid cell; the popover hangs above it (images.js
   opens the native sheet instead on touch devices, so it never shows there). */
.ilb__share { position: relative; display: grid; }
.ilb__share > .ilb__act { width: 100%; height: 100%; }
.ilb-sharepop {
  position: absolute; right: 0; bottom: calc(100% + 8px); z-index: 3;
  width: 272px; max-width: 78vw; padding: 12px; text-align: left;
  display: flex; flex-direction: column; gap: 8px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 14px;
}
.ilb-sharepop[hidden] { display: none; }
.ilb-sharepop__label { font-size: 12px; color: var(--text-muted); }
.ilb-sharepop__row { display: flex; gap: 6px; }
.ilb-sharepop__url {
  flex: 1 1 auto; min-width: 0; padding: 8px 10px; border: 1px solid var(--border);
  border-radius: var(--u-rpill, 10px); background: var(--hover-bg); color: var(--text-body);
  font: inherit; font-size: 12.5px; text-overflow: ellipsis;
}
.ilb-sharepop__copy {
  flex: none; padding: 8px 13px; border: 1px solid var(--deep); border-radius: var(--u-rpill, 10px);
  background: var(--deep); color: var(--on-deep); font: inherit; font-size: 12.5px;
  font-weight: 600; line-height: 1.2; cursor: pointer; white-space: nowrap;
}
.ilb-sharepop__copy--done { background: var(--surface); border-color: var(--border); color: var(--text-muted); }
/* Close + nav sit INSIDE the card (mockup markup) and are placed against
   it: a quiet blurred glass, 40×40, icon rgba(255,255,255,.88) on
   rgba(16,15,13,.26) (SummaryStates.dc.html). «вперёд» parks 14px left of
   the PANEL (right: 320 + 14 = the mockup's right:334), never on top of it. */
.ilb__close, .ilb__nav {
  position: absolute; z-index: 2; display: inline-flex; align-items: center; justify-content: center;
  border: none; background: rgba(16, 15, 13, .26); color: rgba(255, 255, 255, .88); cursor: pointer; border-radius: 50%;
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}
.ilb__close:hover, .ilb__nav:hover { background: rgba(28, 25, 22, .78); }
.ilb__close { top: 16px; right: 18px; width: 40px; height: 40px; }
.ilb__nav { top: 50%; transform: translateY(-50%); width: 40px; height: 40px; }
.ilb__nav--prev { left: 14px; }
.ilb__nav--next { right: calc(var(--lb-panel, 320px) + 14px); }
@media (max-width: 760px) {
  .ilb { flex-direction: column; padding: 12px; }
  .ilb__card { flex-direction: column; max-height: calc(100vh - 24px); }
  .ilb__stage { flex: 1 1 auto; width: 100%; min-height: 200px; }
  .ilb__panel { width: 100%; max-width: 100%; border-left: none; border-top: 1px solid var(--border); max-height: 42vh; }
  .ilb__img { max-height: 52vh; }
  .ilb__nav { display: none; }
  /* No Web Share API (e.g. Firefox Android): the popover becomes a bottom sheet
     instead of hanging inside the scrolling panel, where it would be clipped. */
  .ilb-sharepop {
    position: fixed; right: 12px; left: 12px; bottom: 12px; width: auto; max-width: none;
    border-radius: 16px; padding: 14px;
  }
}

/* ---- Page-summary panel (PRC-118 task A, design/SummaryPanel.html, PRC-123) ----
   Trigger icon lives in .result__meta (web results only). The panel markup is
   rendered once per page (results.html) and filled/streamed by summary.js.
   Reuses the existing spark / caret / skeleton keyframes (sparkTwinkle,
   caretBlink, trSk) — no new animation is introduced. No new colors either:
   every rule below reads existing tokens only. */
/* Redesign (PRC-833): the mockup panel is a fixed 476px rail. */
:root { --summary-panel-w: 476px; }

/* 1. Trigger icon in the result row. */
.summary-btn {
  position: relative; flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; margin: -3px 0 -3px -2px; padding: 0;
  border: 0; border-radius: 8px; background: transparent; color: var(--text-faint);
  cursor: pointer; transition: background-color 120ms cubic-bezier(.4,0,.2,1), color 120ms cubic-bezier(.4,0,.2,1);
}
.summary-btn svg { width: 15px; height: 15px; display: block; }
.summary-btn:hover { background: var(--hover-bg); color: var(--text-strong); }
.summary-btn:focus-visible { outline: var(--focus-ring); }
.summary-btn.is-active { color: var(--deep); background: color-mix(in srgb, var(--deep) 12%, transparent); }
/* Dark: the mockup's active tint is 14% (ResultsSummary article[data-active]
   button), a step above the light 12%. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .summary-btn.is-active { background: rgba(236, 233, 225, .14); }
}
:root[data-theme="dark"] .summary-btn.is-active { background: rgba(236, 233, 225, .14); }
/* Mobile: 44×44 tap target via an out-of-flow pseudo-element (padding would
   grow .result__meta's height). */
@media (max-width: 640px) {
  .summary-btn::after { content: ""; position: absolute; inset: -9px; }
}

/* 2. Panel shell — side on desktop (≥1100px), bottom sheet below it. */
.summary-panel {
  position: fixed; top: 0; right: 0; bottom: 0; width: var(--summary-panel-w); z-index: 120;
  display: flex; flex-direction: column;
  box-sizing: border-box;
  padding: 10px 12px 12px 0;
  transform: translateX(calc(100% + 12px)); transition: transform 200ms cubic-bezier(.4,0,.2,1);
}
.summary-panel[hidden] { display: none; }
/* Redesign (PRC-833): the panel is a floating rounded card in a transparent
   rail (ResultsSummary.dc.html), not a full-height side sheet. Owner №6
   (PRC-885): flat card — no border, no shadow, the surface tone alone
   separates it from the page in both themes. */
.summary-panel__card {
  flex: 0 1 auto; min-height: 0; max-height: 100%;
  display: flex; flex-direction: column;
  border-radius: 18px; background: var(--surface); overflow: hidden;
}
.summary-panel.is-open { transform: translateX(0); }
.summary-panel__handle { display: none; }
.summary-panel__head { position: relative; padding: 16px 46px 12px 18px; display: flex; flex-direction: column; gap: 4px; }
.summary-panel__site { display: flex; align-items: center; gap: 8px; min-width: 0; }
.summary-panel__domain { font-size: 13px; color: var(--link-url); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.summary-panel__title {
  margin: 0; font-size: 16px; font-weight: 600; line-height: 1.35; letter-spacing: -.005em; color: var(--text-strong);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* 236-ФЗ label — a quiet line, not a banner (spec §9.7). */
.summary-panel__mark { margin: 1px 0 0; font-size: 12.5px; line-height: 1.4; color: var(--text-faint); }
.summary-panel__mark[hidden] { display: none; }
.summary-panel__close {
  position: absolute; top: 10px; right: 10px; width: 30px; height: 30px; display: grid; place-items: center;
  padding: 0; border: 0; border-radius: 8px; background: transparent; color: var(--text-muted);
  font-size: 17px; line-height: 1; cursor: pointer;
}
.summary-panel__close svg { width: 14px; height: 14px; display: block; }
.summary-panel__close:hover { background: var(--hover-bg); color: var(--text-strong); }
.summary-panel__close:focus-visible { outline: var(--focus-ring); }
.summary-panel__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0 18px 14px; display: flex; flex-direction: column; gap: 14px; }
/* Excerpt from the result DOM: the panel is filled at 0ms, no request. The
   separator lives on the wrapper, not the clamped paragraph — padding on a
   -webkit-line-clamp element reveals a 4th line inside the padding box. */
.summary-panel__excerpt { padding-bottom: 14px; border-bottom: 1px solid var(--border); }
.summary-panel__snippet {
  margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--text-muted);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.summary-panel__dynamic { display: flex; flex-direction: column; gap: 14px; }
.summary-panel__status { margin: 0; display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-muted); }
.summary-spark { width: 13px; height: 13px; flex: none; }
.summary-spark path { fill: var(--spark); }
.summary-spark--anim path { transform-box: fill-box; transform-origin: center; animation: sparkTwinkle 1.5s ease-in-out infinite; }
/* Skeleton — same trSk mechanic as the translator card. */
.summary-skel { display: flex; flex-direction: column; gap: 10px; }
.summary-skel span { display: block; height: 13px; border-radius: 7px; background: var(--hover-bg); animation: trSk 1.6s ease-in-out infinite; }
/* Points: 3–5 short theses, a list — never a solid paragraph. */
.summary-points { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 12px; }
.summary-points li { display: flex; gap: 10px; font-size: 14.5px; line-height: 1.6; color: var(--text-body); text-wrap: pretty; }
.summary-points li::before { content: ""; flex: none; width: 5px; height: 5px; margin-top: .58em; border-radius: 50%; background: var(--text-faint); }
.summary-caret { display: inline-block; width: 2px; height: 1.05em; background: var(--spark); margin-left: 3px; vertical-align: -3px; animation: caretBlink 1.05s step-end infinite; }
/* Refusal (SummaryStates.dc.html frame 01): ONE quiet card for all six
   failure reasons — dimmed spark + a single line; the footer's «Открыть
   страницу» is the way out. Reuses the iskra failure row; the summary spark
   is a touch less dimmed (.5 vs Iskra's .45). */
.summary-fail .iskra-spark--off { opacity: .5; }
.summary-panel__foot {
  flex: none; border-top: 1px solid var(--border); padding: 7px 18px 9px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px 14px; flex-wrap: wrap;
}
/* One line at one scale (PRC-885 principle, PRC-953/955 scale): the whole foot
   row — caption, toggle, «Открыть страницу» — runs 12.5px; spark 10px, arrow
   11px, gap 5px (12.5/14 of the former 11/12/6). Values: SummaryTranslateToggle.spec.md §0.1. */
.summary-panel__disclaimer {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12.5px; line-height: 1.4; color: var(--text-faint); white-space: nowrap;
}
.summary-panel__disclaimer .spark { width: 10px; height: 10px; flex: none; display: block; }
.summary-panel__disclaimer[hidden] { display: none; }
/* PRC-900 translate toggle — the quiet text action that replaces the caption
   for a non-Russian page (SummaryTranslateToggle.html/.spec.md §4/§5.1): same
   slot and scale as «Открыть страницу», no fill, no frame; the modes differ by
   the label only. Ink (PRC-953): light --deep blue #26355e, dark --text-body
   #d7dbe4 (the summary bullets' ink); hover brightens the text only — light
   #324b99, dark --text-strong — no pill. The radius serves the focus ring. */
.summary-panel__translate {
  display: inline-flex; align-items: center; gap: 5px; height: 26px;
  margin-left: -10px; padding: 0 10px; border: 0; border-radius: 8px;
  background: none; font: inherit; font-size: 12.5px; line-height: 1.4;
  color: var(--deep); white-space: nowrap; cursor: pointer;
}
.summary-panel__translate .spark { width: 10px; height: 10px; flex: none; display: block; }
.summary-panel__translate:hover { color: #324b99; }
.summary-panel__translate:focus-visible { outline: var(--focus-ring); outline-offset: 0; }
.summary-panel__translate[disabled] { color: var(--text-faint); cursor: default; pointer-events: none; }
.summary-panel__translate[hidden] { display: none; }
:root[data-theme="dark"] .summary-panel__translate { color: var(--text-body); }
:root[data-theme="dark"] .summary-panel__translate:hover { color: var(--text-strong); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .summary-panel__translate { color: var(--text-body); }
  :root:not([data-theme="light"]) .summary-panel__translate:hover { color: var(--text-strong); }
}
/* Loading («Переводим…»): dimmed label, the spark pulses — the only motion on
   the panel that is not the typewriter. */
.summary-panel__translate.is-loading .spark { animation: sparkPulse 1.6s ease-in-out infinite; }
/* Dark loading/disabled ink: --text-faint again (the mockup's #7f8695 + .75).
   These selectors must out-rank the dark color rule above (0,4,0 > 0,3,0) —
   otherwise --deep wins and «Переводим…» stays cream (visual-acceptance
   rework note, 2026-09-23). is-loading rides along in case the JS ever
   toggles the class without the disabled attribute. */
:root[data-theme="dark"] .summary-panel__translate[disabled],
:root[data-theme="dark"] .summary-panel__translate.is-loading {
  color: var(--text-faint); opacity: .75;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .summary-panel__translate[disabled],
  :root:not([data-theme="light"]) .summary-panel__translate.is-loading {
    color: var(--text-faint); opacity: .75;
  }
}
@keyframes sparkPulse { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }
@media (prefers-reduced-motion: reduce) { .summary-panel__translate.is-loading .spark { animation: none; } }
.summary-panel__open {
  display: inline-flex; align-items: center; gap: 5px; height: 26px; padding: 0 10px;
  margin-right: -10px; border-radius: 8px;
  font-size: 12.5px; font-weight: 500; line-height: 1; color: var(--deep); white-space: nowrap; text-decoration: none;
}
/* opacity: 1 beats the global a:hover { opacity: .8 } — hover only brightens the ink. */
.summary-panel__open:hover { color: #324b99; opacity: 1; }
:root[data-theme="dark"] .summary-panel__open { color: var(--text-body); }
:root[data-theme="dark"] .summary-panel__open:hover { color: var(--text-strong); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .summary-panel__open { color: var(--text-body); }
  :root:not([data-theme="light"]) .summary-panel__open:hover { color: var(--text-strong); }
}
.summary-panel__open:focus-visible { outline: var(--focus-ring); border-radius: 8px; }
.summary-panel__open svg { width: 11px; height: 11px; flex: none; }
.summary-panel__open[hidden] { display: none; }

/* 3. Backdrop + bottom-sheet mode (< 1100px). Deliberately lighter than the
   lightbox/menu dialogs (.45 vs .74, no blur): a summary augments the list
   rather than replacing the screen, so the list must stay legible behind it. */
.summary-backdrop { position: fixed; inset: 0; z-index: 119; background: rgba(10, 9, 8, .45); }
.summary-backdrop[hidden] { display: none; }
.summary-panel--sheet {
  top: auto; left: 0; right: 0; bottom: 0; width: auto; max-height: 78%;
  border-left: 0; border-top: 1px solid var(--border-card);
  border-radius: 18px 18px 0 0;
  transform: translateY(100%);
}
.summary-panel--sheet.is-open { transform: translateY(0); }
.summary-panel--sheet .summary-panel__handle {
  display: block; width: 36px; height: 4px; margin: 10px auto 6px; border-radius: 2px; background: var(--border);
}
.summary-panel--sheet .summary-panel__head { padding: 4px 52px 12px 16px; }
.summary-panel--sheet .summary-panel__close { top: 10px; right: 10px; }
.summary-panel--sheet .summary-panel__body { padding: 0 16px 16px; }
.summary-panel--sheet .summary-panel__foot { padding: 12px 16px calc(16px + env(safe-area-inset-bottom, 0px)); }

/* 4. Page shift (desktop only): .results gets a right gutter the exact width
   of the panel, so the header/list/footer move together and the search bar
   stays above the (now narrower) column — the sheet overlays instead. */
@media (min-width: 1100px) {
  body.results.summary-open { padding-right: var(--summary-panel-w); }
  /* The thread is position:fixed, so the body's right padding never reaches
     it: its 848px inner column would recentre on the FULL viewport and butt
     its right edge into the summary panel. Constrained to the same shifted
     frame as the header/capsule (ResultsSummary.dc.html carries the same
     padding-right:476px), the column recentres over the shifted capsule —
     the dialog keeps its place above the capsule, the panel its own rail.
     summary-open is never set in sheet mode, so this is desktop-only. */
  body.results.summary-open .iskra-thread-panel { right: var(--summary-panel-w); }
  /* The open-panel state has its OWN layout (ResultsSummary.dc.html — its
     page carries the same padding-right:476px): the bar goes full-width with
     12/19 side fields and the capsule drops both -14 overhangs (12…785,773),
     the body takes 26/33 so the column lands at 26…771 (745) and the result
     rows overhang to sit flush with the capsule's edges (12…785), the
     favicon 14px inside it. The pre-series-3 9px/2px asymmetry reproduced
     these numbers by accident in this one state; this is the deliberate
     replacement (PRC-837 acceptance). */
  body.results.summary-open .rheader__bar {
    max-width: none;
    margin: 0;
    padding-left: 12px;
    padding-right: 19px;
  }
  body.results.summary-open .rheader__cap { margin-left: 0; margin-right: 0; }
  body.results.summary-open .results-main { padding-left: 26px; padding-right: 33px; }
}
/* PRC-957 / PRC-960 (ResultsSummary.dc.html, frame 1920): once the room left
   of the panel holds the normal header (window 1335 = 476 + 859) the open
   panel keeps the usual widths — header 848 with -14 overhangs (capsule and
   pod 828), results 800 — centred in that room. Below it the frame-1280
   layout above is untouched. 859 (not 848) is where that layout's L-31 /
   L-59 already equal 828 / 800, so nothing jumps: 1334 → 827/799,
   1335 → 828/800. The outer wordmark: outside from window 1657 (the
   same ≤1180 condition as without the panel, counted on the room left of it —
   see the .rheader__brand swap above); data-brandfit stays the fallback. */
@media (min-width: 1335px) {
  body.results.summary-open .rheader__bar {
    max-width: var(--rheader-col);
    margin: 0 auto;
    padding-left: 24px;
    padding-right: 24px;
  }
  body.results.summary-open .rheader__cap { margin-left: -14px; margin-right: -14px; }
  body.results.summary-open .results-main { padding-left: 24px; padding-right: 24px; }
}
/* Mobile sheet: page scroll is locked, only the sheet body scrolls (same
   mechanic as body.ilb-open). */
body.summary-sheet-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .summary-panel { transition: none; }
  .summary-skel span, .summary-caret, .summary-spark--anim path { animation: none !important; }
}

/* 5. Image strip below the summary theses (PRC-191, summary-images-plan.md
   §6.4/§7.4). New classes only — no existing .ilb*/.summary-panel* rule above
   is touched. Space is never reserved: summary.js appends/removes the
   whole .sumstrip node, it is not toggled with [hidden]. */
.sumstrip { display: flex; flex-direction: column; gap: 8px; }
.sumstrip__title { margin: 0; font-size: 12px; font-weight: 600; letter-spacing: .03em; color: var(--text-muted); }
.sumstrip__track {
  display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none;
  padding-bottom: 2px;
}
.sumstrip__track::-webkit-scrollbar { display: none; }
/* Edge fades (owner №9, PRC-885) are "content hidden this way" indicators, so
   summary.js draws them from the track's scroll position — never statically.
   Right fade ⇔ hidden content further right (scrolled to the end, it goes);
   left fade ⇔ hidden content further left; a strip that fits shows neither.
   The 12%/88% stops are the static mask's own geometry, mirrored. */
.sumstrip__track--fade-r {
  -webkit-mask-image: linear-gradient(to right, #000 88%, transparent);
  mask-image: linear-gradient(to right, #000 88%, transparent);
}
.sumstrip__track--fade-l {
  -webkit-mask-image: linear-gradient(to left, #000 88%, transparent);
  mask-image: linear-gradient(to left, #000 88%, transparent);
}
.sumstrip__track--fade-l.sumstrip__track--fade-r {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(to right, transparent 0, #000 12%, #000 88%, transparent);
}
.sumstrip__item {
  flex: none; display: block; width: 92px; height: 64px; padding: 0; overflow: hidden;
  border: 1px solid var(--border); border-radius: 8px; background: var(--hover-bg); cursor: pointer;
  transition: border-color 120ms cubic-bezier(.4,0,.2,1);
}
.sumstrip__item:hover { border-color: color-mix(in srgb, var(--deep) 35%, var(--border)); }
.sumstrip__item:focus-visible { outline: var(--focus-ring); }
.sumstrip__thumb { display: block; width: 100%; height: 100%; object-fit: cover; }
.sumstrip__more {
  flex: none; width: 120px; height: 64px; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 3px; padding: 6px 8px; text-align: center; background: var(--bg-page);
  border: 1px solid var(--border); border-radius: 8px; text-decoration: none;
  transition: border-color 120ms cubic-bezier(.4,0,.2,1);
}
.sumstrip__more:hover { border-color: color-mix(in srgb, var(--deep) 35%, var(--border)); }
.sumstrip__more:focus-visible { outline: var(--focus-ring); }
.sumstrip__more-text { font-size: 11.5px; line-height: 1.25; color: var(--text-muted); }
.sumstrip__more-link { font-size: 11px; line-height: 1.2; font-weight: 500; color: var(--deep); }

/* 6. Summary-panel lightbox (PRC-191): a second, independent .ilb instance
   (own #summary-lightbox node, results.html), same action set as "Картинки"
   (owner decision, 2026-08-17). The shared .ilb* rules above render it
   identically; .ilb--sum only adds what differs — raised above the summary
   panel/sheet (dialog z-index, design/SummaryPanel.spec.md §4), the resolution
   icon+text as an inline group so it sits beside the position counter in the
   same .ilb__dims row, and the counter itself, which the shared component
   doesn't have. No rule above is modified. */
.ilb--sum { z-index: 130; }
.ilb--sum [data-sumlb-dims] { display: inline-flex; align-items: center; gap: 7px; }
.ilb--sum [data-sumlb-dims][hidden] { display: none; }
.ilb--sum .ilb__count { margin-left: auto; font-size: 13px; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.ilb--sum .ilb__nav[hidden] { display: none; }

@media (prefers-reduced-motion: reduce) {
  .sumstrip__item, .sumstrip__more { transition: none; }
}

/* 7. Account-data sync choice dialog (Ф7, account-spec §10.2/AC-2): the
   one-time first-login question when this device and the account hold
   different settings. Same tokens as the invite card; no registry names,
   no hidden counters (red line №7). */
.async-dialog {
  position: fixed; inset: 0; z-index: 150; display: flex;
  align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--bg-page) 60%, transparent);
}
.async-dialog__card {
  max-width: 460px; margin: 1rem; padding: 1.5rem 1.6rem; text-align: center;
  background: var(--surface); color: var(--text-strong);
  border: 1px solid var(--border); border-radius: 14px;
}
.async-dialog__card h2 { margin: 0 0 .5rem; font-size: 1.15rem; }
.async-dialog__card p { margin: 0 0 1.1rem; color: var(--text-muted); }
.async-dialog__actions { display: flex; gap: .7rem; justify-content: center; flex-wrap: wrap; }
.async-dialog__actions button {
  padding: .55rem 1.1rem; border-radius: var(--u-rpill);
  border: 1px solid var(--border); background: none; color: inherit;
  font: inherit; cursor: pointer;
}
.async-dialog__actions button:hover { border-color: var(--deep); }


/* === /i/ — одна картинка по ссылке (PRC-911) === */
/* PRC-917, design/redesign-2026-09/ImagesShare.dc.html: the viewer card —
   picture left (max 679×600), description and actions right (320px), one
   1000px card under the shared capsule, no footer. Flat like every surface
   since PRC-886: no shadow on the card or the popover — the popover steps
   one tone off the card instead. The mockup's own tokens (--br, --acc,
   --moreBg, --goBg…) live here as --ilink-* because the global palette has
   no twin for them; everything that has one reuses the global token.
   Below 640px (§3.8): one column, the picture on top, no mockup. */
.ilink {
  --ilink-br: #dcd6cb;
  /* --btn2 (ImagesShare.dc.html, PRC-982): beige action tiles in light. */
  --ilink-more: #efece5;
  --ilink-more-hov: #f5f2ec;
  --ilink-go-bg: #c9694a;
  --ilink-go-fg: #ffffff;
  --ilink-mu2: #6b665d;
  --ilink-hov2: rgba(31, 30, 27, .06);
  --ilink-pop: #f3f0ea;
  --ilink-target-br: #dcd6cb;
  padding: 14px 24px 60px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ilink {
    --ilink-br: #272931;
    --ilink-more: #282a32;
    --ilink-more-hov: #33363f;
    --ilink-go-bg: #f3f7ff;
    --ilink-go-fg: #121317;
    --ilink-mu2: #8f96a6;
    --ilink-hov2: rgba(255, 255, 255, .06);
    --ilink-pop: #282a32;
    --ilink-target-br: #3a3d47;
  }
}
:root[data-theme="dark"] .ilink {
  --ilink-br: #272931;
  --ilink-more: #282a32;
  --ilink-more-hov: #33363f;
  --ilink-go-bg: #f3f7ff;
  --ilink-go-fg: #121317;
  --ilink-mu2: #8f96a6;
  --ilink-hov2: rgba(255, 255, 255, .06);
  --ilink-pop: #282a32;
  --ilink-target-br: #3a3d47;
}
.ilink__card {
  max-width: 1000px;
  height: 660px;
  margin: 0 auto;
  display: flex;
  align-items: stretch;
  border-radius: 18px;
  background: var(--surface);
  color: var(--text-body);
}
.ilink__media {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 18px 0 0 18px;
  overflow: hidden;
}
.ilink__img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: 679px;
  max-height: 600px;
  object-fit: contain;
}
.ilink__gone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 0 24px;
  text-align: center;
  color: var(--ilink-mu2);
}
.ilink__gone-title { margin: 0; font-size: 17px; font-weight: 600; line-height: 1.35; color: var(--text-strong); }
.ilink__gone-text { margin: 0; max-width: 340px; font-size: 14px; line-height: 1.5; color: var(--link-url); text-wrap: pretty; }
.ilink__gone--broken { display: none; }
.ilink__card.is-broken .ilink__img { display: none; }
.ilink__card.is-broken .ilink__gone--broken { display: flex; }
/* The dead screen (ImagesShare 1b): the heading alone on the page, no card
   and no icon, its top 150px under the capsule (the header's 16px + 14px of
   .ilink + 120px). */
.ilink__dead {
  margin: 120px 0 0;
  font-size: 17px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text-strong);
  text-align: center;
  overflow-wrap: anywhere;
}
.ilink__aside {
  flex: none;
  width: 320px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 24px 20px 20px;
  border-left: 1px solid var(--ilink-br);
}
.ilink__head { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.ilink__site { display: flex; align-items: center; gap: 8px; min-width: 0; }
.ilink__fav {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--cap-circle-bg);
  color: var(--text-body);
  font-size: 10.5px;
  font-weight: 700;
}
.ilink__fav img { width: 100%; height: 100%; object-fit: contain; }
.ilink__domain { min-width: 0; font-size: 13.5px; color: var(--link-url); overflow-wrap: anywhere; }
/* A title is untrusted length: wrapped anywhere (a 300-char run with no
   space included) and clamped to five lines, so it never pushes the actions
   out of the fixed-height card. */
.ilink__title {
  margin: 0;
  font-size: 21px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text-strong);
  overflow-wrap: anywhere;
  text-wrap: pretty;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 5;
  overflow: hidden;
}
.ilink__meta { margin: 0; font-size: 13.5px; color: var(--ilink-mu2); }
.ilink__card.is-broken .ilink__meta { display: none; }
/* §9.7: a readable line of its own, never hover-only, never ellipsized. */
.ilink__rkn { margin: 0; font-size: 12.5px; line-height: 1.4; color: var(--text-muted); }
.ilink__go {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 46px;
  padding: 0 20px;
  border-radius: 999px;
  background: var(--ilink-go-bg);
  color: var(--ilink-go-fg);
  font-size: 15px;
  font-weight: 600;
}
.ilink__go:hover { opacity: .9; }
.ilink__go-broken { display: none; }
.ilink__card.is-broken .ilink__go-ok { display: none; }
.ilink__card.is-broken .ilink__go-broken { display: inline; }
.ilink__actions { position: relative; }
.ilink__card.is-broken .ilink__actions { display: none; }
.ilink__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
/* PRC-918: «Сохранить» filled once saved (the popover-owned state). */
.ilink__act.is-saved { color: var(--spark); }
.ilink__act.is-saved svg { fill: currentColor; }
.ilink__form { margin: 0; display: flex; }
.ilink__act {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  height: 66px;
  border: none;
  border-radius: 16px;
  background: var(--ilink-more);
  color: var(--text-body);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
}
.ilink__act:hover,
.ilink__act[aria-expanded="true"] { background: var(--ilink-more-hov); color: var(--text-strong); }
.ilink__pop {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 14px;
  border-radius: 18px;
  background: var(--ilink-pop);
}
.ilink__pop-title { margin: 0; font-size: 12.5px; font-weight: 600; color: var(--text-faint); }
.ilink__pop-row { display: flex; gap: 8px; }
.ilink__pop-url {
  flex: 1 1 auto;
  min-width: 0;
  height: 40px;
  padding: 0 12px;
  border: none;
  border-radius: 12px;
  background: var(--surface);
  color: var(--text-body);
  font: inherit;
  font-size: 13.5px;
  text-overflow: ellipsis;
  /* Focused and selected by image-link.js on open: the selection is the cue. */
  outline: none;
}
.ilink__pop-copy {
  flex: none;
  height: 40px;
  padding: 0 14px;
  border: none;
  border-radius: 999px;
  background: var(--ilink-go-bg);
  color: var(--ilink-go-fg);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}
.ilink__targets { display: flex; flex-wrap: wrap; gap: 6px; }
.ilink__target {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--ilink-target-br);
  border-radius: 999px;
  font-size: 13px;
  color: var(--link-url);
}
.ilink__target:hover { opacity: 1; color: var(--text-strong); background: var(--ilink-hov2); }
.ilink__note { margin: auto 0 0; font-size: 12px; line-height: 1.45; color: var(--text-faint); opacity: .6; text-wrap: pretty; }
@media (max-width: 639px) {
  .ilink { padding: 8px 12px 40px; }
  .ilink__card { flex-direction: column; height: auto; }
  .ilink__media { border-radius: 18px 18px 0 0; min-height: 180px; }
  .ilink__img { height: auto; max-height: 60vh; }
  .ilink__card.is-broken .ilink__media { padding: 40px 0; }
  .ilink__aside { width: auto; padding: 18px 16px 16px; border-left: none; border-top: 1px solid var(--ilink-br); }
  .ilink__note { margin-top: 0; }
  /* In flow on a phone: an overlay would run past the card's bottom edge. */
  .ilink__pop { position: static; margin-top: 8px; }
  .ilink__dead { margin-top: 96px; }
}

/* === Картинки: палитра (PRC-918) === */
/* The mockup's own tokens (design/redesign-2026-09/ImagesResults.dc.html,
   [data-art]) live here as --ig-*: the global palette has no twin for most of
   them. `.imgs` is the /images body class; `.isp` is the save popover, which
   is appended to <body> on pages that are not /images (/i/, the viewer), so
   it carries the same tokens itself. Light is the default, dark follows the
   system unless the switcher says otherwise — the same three blocks as the
   global tokens above. */
.imgs, .srch, .isp, .sharepanel, .ilink {
  --ig-pop: #ffffff;
  --ig-st: #1f1e1b;
  --ig-tx: #24211c;
  --ig-mu: #54504a;
  --ig-mu2: #6b665d;
  --ig-fa: #8a857a;
  --ig-br: #dcd6cb;
  --ig-trk: #cfc9bd;
  --ig-trk-on: #c9694a;
  --ig-sp: #c9694a;
  --ig-save: #c9694a;
  --ig-save-tx: #ffffff;
  --ig-hov: #f0ede6;
  --ig-hov2: rgba(31, 30, 27, .06);
  --ig-acc: #efece5;
  --ig-tab-on: #ffffff;
  --ig-go-bg: #c9694a;
  --ig-go-tx: #ffffff;
  --ig-cap-rgb: 255, 255, 255;
  --ig-pin-a: .62;
  /* --glassA (ImagesReverse/Results/Share/Lightbox .dc.html, PRC-982): the
     filter panels sit on their own, fuller glass, not on the capsule's
     pinned alpha. */
  --ig-glass-a: .8;
  --ig-popsh: 0 14px 40px rgba(31, 30, 27, .16);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .imgs, :root:not([data-theme="light"]) .srch, :root:not([data-theme="light"]) .isp, :root:not([data-theme="light"]) .sharepanel, :root:not([data-theme="light"]) .ilink {
    --ig-pop: #1c1d22;
    --ig-st: #f3f7ff;
    --ig-tx: #d7dbe4;
    --ig-mu: #a7adba;
    --ig-mu2: #8f96a6;
    --ig-fa: #7f8695;
    --ig-br: #272931;
    --ig-trk: #3a3d47;
    --ig-trk-on: #8f96a6;
    --ig-sp: #e0855f;
    --ig-save: #f3f7ff;
    --ig-save-tx: #121317;
    --ig-hov: #22242a;
    --ig-hov2: rgba(255, 255, 255, .06);
    --ig-acc: #282a31;
    --ig-tab-on: #282a31;
    --ig-go-bg: #f3f7ff;
    --ig-go-tx: #121317;
    --ig-cap-rgb: 28, 29, 34;
    --ig-pin-a: .46;
    --ig-glass-a: .74;
    --ig-popsh: 0 14px 40px rgba(0, 0, 0, .5);
  }
}
:root[data-theme="dark"] .imgs, :root[data-theme="dark"] .srch, :root[data-theme="dark"] .isp, :root[data-theme="dark"] .sharepanel, :root[data-theme="dark"] .ilink {
  --ig-pop: #1c1d22;
  --ig-st: #f3f7ff;
  --ig-tx: #d7dbe4;
  --ig-mu: #a7adba;
  --ig-mu2: #8f96a6;
  --ig-fa: #7f8695;
  --ig-br: #272931;
  --ig-trk: #3a3d47;
  --ig-trk-on: #8f96a6;
  --ig-sp: #e0855f;
  --ig-save: #f3f7ff;
  --ig-save-tx: #121317;
  --ig-hov: #22242a;
  --ig-hov2: rgba(255, 255, 255, .06);
  --ig-acc: #282a31;
  --ig-tab-on: #282a31;
  --ig-go-bg: #f3f7ff;
  --ig-go-tx: #121317;
  --ig-cap-rgb: 28, 29, 34;
  --ig-pin-a: .46;
  --ig-glass-a: .74;
  --ig-popsh: 0 14px 40px rgba(0, 0, 0, .5);
}

/* === Картинки: страница, стартовая и состояния (PRC-918) === */
/* ImagesStart / ImagesStates. The header is the shared capsule; the page
   under it is one column, full width of the window (the grid is wider than the
   800px web column, as drawn). No footer. */
.ipage { margin-top: -4px; padding: 0 24px 40px; } /* the header's own bottom room is 4px more than drawn */
.imgs--start .ipage,
.srch--start .ipage {
  min-height: calc(100vh - 170px);
  display: flex;
  align-items: center;
  justify-content: center;
}
/* /search start (PRC-963): the block is centred in the room under the header
   with 120px kept free at the bottom (MobileSearchStart.spec, phone). */
.srch--phone .ipage { padding-bottom: 78px; }
.ipage__start {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--ig-mu2);
}
.ipage__start-title {
  margin: 0;
  font-family: var(--brand-font);
  font-weight: 600;
  font-size: 32px;
  letter-spacing: -.01em;
  line-height: 1;
  color: var(--ig-mu2);
}
.iend { margin: 40px 0 0; text-align: center; font-size: 15px; color: var(--ig-mu); }
.imore2 { margin-top: 36px; }
/* Loading on Images: the rays around the pill (ImagesResults.dc.html,
   svg[data-rays-btn], image-grid.js → window.PerecleRays) and the fill of the
   hover state — the rule itself lives with .more-btn above, one for both
   buttons (PRC-1022). */

/* Chips of the applied filters (ImagesResults): the cross removes at once. */
.ichips { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; min-height: 44px; margin: -12px 0 6px; }
.ichip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  padding: 0 9px 0 12px;
  border: 1px solid var(--ig-br);
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ig-tx);
  text-decoration: none;
}
.ichip:hover { color: var(--ig-st); background: var(--ig-hov2); }
.ichip svg { opacity: .6; }
.ichips__reset { padding: 0 8px; font-size: 13px; color: var(--ig-fa); text-decoration: none; }
.ichips__reset:hover { color: var(--ig-st); }
/* «Безопасный поиск выключен» (ImagesStates f, ImagesReverse 1b/1c). With
   SAFE_SEARCH_ENABLED it is a control, not a note: it opens the capsule row,
   where the mode lives (В33); the row itself is search.css's other half, the
   handler is the one that owns `[data-capsule-row-open]`. With the flag off
   the plate stays a plain span, exactly as before the wave (§13). */
.ichips__safe { margin-left: 6px; font-size: 13px; color: var(--ig-fa); }
/* The button form resets the UA's own font — `font: inherit` would bring the
   page's 15px in and lose the plate's 13px, so family and size are named. */
button.ichips__safe {
  padding: 0;
  border: none;
  background: none;
  font-family: inherit;
  font-size: 13px;
  /* --fa, not `inherit`: this selector beats the plain `.ichips__safe` one, so
     inheriting here would take --ig-tx from .ichips and the plate would read as
     body text (the mockup's `color:var(--fa)`, both themes). */
  color: var(--ig-fa);
  cursor: pointer;
}
button.ichips__safe:hover { color: var(--ig-st); }

/* The deferred guest save's failure line (§10.1, §12.1 «Не удалось сохранить
   картинку»): under the header, above the page, as quiet as the rest. */
.isp-error {
  margin: 0 0 8px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--ig-mu2);
}
.isp-error[hidden] { display: none; }

/* === Картинки: сетка и плитка (PRC-918) === */
/* The grid + tile component (templates/_image_grid.html, static/js/image-grid.js):
   results now, «Похожие картинки» and collections in stage 3. Etalon
   ImagesResults.dc.html + ImagesMarkAndSave.spec.md §1. Rows 200px and gap
   10px as drawn; even rows for Яндекс/Google/Bing, mosaic for stock sources. */
.imgs { --ig-row-h: 200px; --ig-gap: 10px; --ig-cols: 6; }
@media (max-width: 1180px) { .imgs { --ig-cols: 5; } }
@media (max-width: 900px) { .imgs { --ig-cols: 4; --ig-row-h: 160px; } }
.ig--justified { display: flex; flex-wrap: wrap; gap: var(--ig-gap); }
.ig-just { flex-shrink: 1; min-width: 0; }
.ig-just .ig-tile { width: 100%; }
.ig-spacer { flex-grow: 999999; flex-basis: 0; height: 0; }
/* image-grid.js lays the rows out itself (a full row is SHRUNK to the width,
   never stretched; the last one keeps the target height). Without JS the
   flex-grow above still fills the rows. */
.ig--laid .ig-just { flex-grow: 0; flex-shrink: 0; }
.ig--laid .ig-spacer { display: none; }
/* Columns: at most --ig-cols, never narrower than 140px, so the §9.7 line of a
   2:1 tile stays whole on narrow windows (3 columns at 540-600px, 2 at 390). */
.ig--masonry { column-count: var(--ig-cols); column-width: 140px; column-gap: var(--ig-gap); }
.ig--masonry .ig-tile { width: 100%; margin: 0 0 var(--ig-gap); break-inside: avoid; }
/* PRC-928: the trimmed bottom while «Искать ещё» is on the page. A mosaic tile keeps its place
   (the columns must not reshuffle); an even-row cell leaves the flow. Both stay in the DOM. */
.ig-just[data-ig-trim] { display: none; }
/* A mosaic with «Искать ещё» is placed by image-grid.js (data-ig-cols): every tile at an
   absolute place, so appending a page moves nothing that is already drawn. */
.ig--masonry[data-ig-cols] { position: relative; column-count: auto; column-width: auto; }
.ig--masonry[data-ig-cols] .ig-tile { position: absolute; margin: 0; }
.ig--masonry[data-ig-cols] .ig-tile[data-ig-trim] { display: none; }

.ig-tile {
  position: relative;
  display: block;
  border-radius: 12px;
  overflow: hidden;
  background: var(--ig-acc);
  cursor: pointer;
}
.ig-tile__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ig-tile__broken {
  position: absolute;
  inset: 0;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 7px;
  background: var(--ig-acc);
  color: var(--ig-fa);
  font-size: 11.5px;
}
.ig-tile--broken .ig-tile__img { display: none; }
.ig-tile--broken .ig-tile__broken { display: flex; }
/* The §9.7 backing is always there, only on marked tiles (spec §1.1): the same
   in both themes — the text lies on the picture, not on the page. The hover
   backing goes over it. */
.ig-tile--rkn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(to top, rgba(14, 12, 10, .74), rgba(14, 12, 10, 0) 64%);
  pointer-events: none;
}
.ig-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0;
  transition: opacity .16s ease;
  background: linear-gradient(to bottom, rgba(14, 12, 10, .5), rgba(14, 12, 10, 0) 40%),
    linear-gradient(to top, rgba(14, 12, 10, .6), rgba(14, 12, 10, 0) 46%);
  pointer-events: none;
}
.ig-tile:hover::after, .ig-tile:focus-within::after { opacity: 1; }
.ig-tile__ov {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  /* bottom-first: when site + title + §9.7 line do not fit, the top is what is
     cut — the §9.7 line always stands 10px from the bottom edge (spec §1.1) */
  flex-direction: column-reverse;
  justify-content: space-between;
  padding: 10px;
  overflow: hidden;
  pointer-events: none;
}
.ig-tile__site {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  padding-right: 38px;
  opacity: 0;
  transition: opacity .16s ease;
  order: 2;
  flex: 0 100 auto;
  min-height: 0;
  overflow: hidden;
}
.ig-tile__favicon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .92) center / 12px 12px no-repeat;
  color: #3a3632;
  font-size: 10px;
  font-weight: 700;
}
.ig-tile__domain { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; color: #fff; }
/* Bottom column: the title stands ABOVE the §9.7 line (gap 5px). On a low tile
   the title (then the site line) gives way — no room is kept for them. */
.ig-tile__bottom { order: 1; display: flex; flex-direction: column; justify-content: flex-end; gap: 5px; min-width: 0; min-height: 0; flex: 0 1 auto; }
.ig-tile__title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.3;
  color: #fff;
  opacity: 0;
  transition: opacity .16s ease;
  flex: 0 100 auto;
  min-height: 0;
}
.ig-tile:hover .ig-tile__site, .ig-tile:hover .ig-tile__title,
.ig-tile:focus-within .ig-tile__site, .ig-tile:focus-within .ig-tile__title { opacity: 1; }
/* §9.7 (RKN_MARK_TEXT): a quiet line of text — no icon, pill or alarm colour;
   wraps by words and hyphenates, never clipped (spec §1.1). Visible at rest
   and on hover. */
.ig-tile__mark {
  flex: none;
  font-size: 11.5px;
  font-weight: 500;
  line-height: 1.35;
  color: rgba(255, 255, 255, .92);
  text-shadow: 0 1px 2px rgba(0, 0, 0, .55);
  -webkit-hyphens: auto;
  hyphens: auto;
  overflow-wrap: break-word;
  text-wrap: pretty;
}
.ig-tile__save {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: #fff;
  opacity: 0;
  cursor: pointer;
  transition: opacity .16s ease, background-color .16s ease;
}
.ig-tile:hover .ig-tile__save, .ig-tile:focus-within .ig-tile__save, .ig-tile__save.is-saved { opacity: 1; }
.ig-tile__save:hover, .ig-tile__save.is-saved { background: rgba(18, 16, 14, .55); }
/* Saved: the bookmark is terracotta (--sp, mockup `saveIc`), filled; at rest it
   is white. The circle under it is the dark scrim in both states. */
.ig-tile__save.is-saved { color: var(--ig-sp); }
.ig-tile__save.is-saved svg { fill: currentColor; }

/* === Картинки: фильтры (PRC-918) === */
/* The «Фильтры» circle in the capsule and the panel under it (ImagesResults
   «За кнопкой»). Flat: no shadow, a 1px border instead (PRC-886 / the PRC-912
   decision). Unsupported values are grey and not pressable. */
.searchbar--results .cap-filters { position: relative; color: var(--startbar-mic); }
.cap-filters.is-on { background: var(--cap-hover); color: var(--menu-pill-active); }
.cap-filters__dot { fill: var(--ig-pop); }
.cap-filters__badge {
  position: absolute;
  top: 3px;
  right: 1px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  box-sizing: border-box;
  border-radius: 8px;
  background: var(--ig-sp);
  color: #fff;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}
.ifp {
  position: absolute;
  top: calc(100% + 10px);
  left: 0;
  right: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 20px 22px 18px;
  line-height: normal; /* the mockup's rows are `normal`, not the page's 1.5 (PRC-926) */
  border-radius: 22px;
  background: rgba(var(--ig-cap-rgb), var(--ig-glass-a));
  box-shadow: var(--ig-popsh);
  -webkit-backdrop-filter: blur(26px) saturate(.88);
  backdrop-filter: blur(26px) saturate(.88);
  color: var(--ig-tx);
}
.ifp[hidden] { display: none; }
/* The capsule is position:fixed once the header pins (data-geo, start.js), so
   a panel absolute inside the scrolling .rheader__cap rode away with the page:
   «Фильтры» opened it above the viewport (PRC-926). Pinned, the panel is fixed
   under the capsule and the «Поиск / Картинки» row (--ifp-top, start.js syncMenu;
   72px = 10 + 52 + 10 when the row is tucked under the capsule) on the same
   --cap-l / --cap-w. */
.rheader[data-geo="1"] .ifp {
  position: fixed;
  top: var(--ifp-top, 72px);
  left: var(--cap-l, 24px);
  right: auto;
  width: var(--cap-w, 652px);
  max-height: calc(100vh - var(--ifp-top, 72px) - 16px);
  overflow-y: auto;
  box-sizing: border-box;
}
/* A see-through panel over the big start heading blurs it into a light patch
   (owner: «свечение внутри»): the heading steps aside while a panel is open. */
body:has(.ifp:not([hidden])) .ipage__start { visibility: hidden; }
.ifp__sec { display: flex; flex-direction: column; gap: 9px; }
.ifp__label { font-size: 12.5px; font-weight: 600; color: var(--ig-fa); }
.ifp__row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.ifp__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 28px; }
.ifp__opt { position: relative; display: inline-flex; cursor: pointer; }
.ifp__opt input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.ifp__opt span {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--ig-br);
  border-radius: 999px;
  font-size: 13.5px;
  font-weight: 500;
  color: var(--ig-tx);
  white-space: nowrap;
}
.ifp__grid .ifp__opt span { font-weight: 400; }
.ifp__opt:hover span { color: var(--ig-st); }
.ifp__opt input:checked + span { background: var(--ig-tab-on); border-color: transparent; color: var(--ig-st); font-weight: 600; }
.ifp__opt input:focus-visible + span { outline: 2px solid var(--ig-sp); outline-offset: 2px; }
.ifp__opt--src span { height: 34px; padding: 0 14px; font-size: 14px; color: var(--ig-mu); }
.ifp__opt--src input:checked + span { color: var(--ig-st); }
.ifp__opt--sw { margin: 0 2px; }
.ifp__opt--sw span {
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  background: var(--ifp-sw);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .15);
}
.ifp__opt--sw input:checked + span { background: var(--ifp-sw); box-shadow: 0 0 0 2px var(--ig-pop), 0 0 0 4px var(--ig-sp); }
.ifp__opt.is-off { cursor: not-allowed; }
.ifp__opt.is-off span { color: var(--ig-fa); opacity: .45; }
.ifp__foot { display: flex; align-items: center; gap: 10px; padding-top: 14px; border-top: 1px solid var(--ig-br); }
.ifp__spacer { flex: 1 1 auto; }
.ifp__safe {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 32px;
  padding: 0;
  border: none;
  background: transparent;
  font: inherit;
  font-size: 14px;
  color: var(--ig-tx);
  cursor: pointer;
}
.ifp__track { position: relative; flex: none; width: 34px; height: 20px; border-radius: 999px; background: var(--ig-trk); transition: background .16s; }
.ifp__knob { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0, 0, 0, .3); transition: left .16s; }
.ifp__safe[aria-checked="true"] .ifp__track { background: var(--ig-trk-on); }
.ifp__safe[aria-checked="true"] .ifp__knob { left: 16px; }
.ifp__reset, .ifp__go {
  height: 38px;
  border: none;
  border-radius: 999px;
  font: inherit;
  font-size: 14px;
  cursor: pointer;
}
.ifp__reset { padding: 0 16px; background: transparent; font-weight: 500; color: var(--ig-mu); }
.ifp__reset:hover { color: var(--ig-st); }
.ifp__go { padding: 0 18px; background: var(--ig-go-bg); color: var(--ig-go-tx); font-weight: 600; }

/* === Картинки: всплывашка сохранения (PRC-918) === */
/* ONE component for the tile bookmark, the viewer and /i/
   (static/js/save-popover.js, ImagesMarkAndSave.spec.md §2). Flat: a border
   instead of the mockup's shadow. Appears at once, no animation. */
.isp {
  position: fixed;
  z-index: 200;
  box-sizing: border-box;
  width: 284px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  border: 1px solid var(--ig-br);
  border-radius: 20px;
  background: var(--ig-pop);
  color: var(--ig-tx);
  font-size: 14px;
}
.isp__head { display: flex; align-items: center; gap: 8px; padding: 8px 10px 6px; font-size: 15px; font-weight: 600; line-height: 1.3; color: var(--ig-st); }
/* В42: the head's cross «Закрыть» — 28px, right-aligned by the auto margin,
   --mu2 at rest, --hov / --st on hover (ImagesResults 1d′). */
.isp__close {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  margin: -4px -6px -4px auto;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--ig-mu2);
  cursor: pointer;
}
.isp__close:hover { background: var(--ig-hov); color: var(--ig-st); }
/* The saved bookmark itself: terracotta (--sp) in both themes — the mockup's
   `saveIc` / `saveColor` since 30.09 (ImagesResults, ImagesLightbox 1b,
   ImagesShare 1a). The circle it sits on stays the dark scrim. */
.isp__head svg { flex: none; color: var(--ig-sp); }
.isp__list { display: flex; flex-direction: column; gap: 2px; overflow-y: auto; }
.isp__rule { flex: none; height: 1px; margin: 6px 8px; background: var(--ig-br); }
.isp__row, .isp__add {
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  box-sizing: border-box;
  padding: 8px;
  border: none;
  border-radius: 14px;
  background: transparent;
  font: inherit;
  text-align: left;
  color: inherit;
  cursor: pointer;
}
.isp__row { min-height: 50px; }
.isp__add { height: 48px; font-weight: 500; }
.isp__row:hover, .isp__add:hover { background: var(--ig-hov); }
.isp__thumb { flex: none; width: 34px; height: 34px; border-radius: 9px; overflow: hidden; background: var(--ig-acc); }
.isp__thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.isp__text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.isp__name {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
  font-weight: 500;
  line-height: 1.3;
  color: var(--ig-tx);
}
.isp__count { font-size: 12px; color: var(--ig-fa); }
.isp__check {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  box-sizing: border-box;
  border: 1.5px solid var(--ig-trk);
  border-radius: 50%;
  color: var(--ig-save-tx);
}
.isp__check svg { opacity: 0; }
.isp__check.is-on { border: none; background: var(--ig-save); }
.isp__check.is-on svg { opacity: 1; }
.isp__plus {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  box-sizing: border-box;
  border: 1.5px dashed var(--ig-trk);
  border-radius: 9px;
  color: var(--ig-mu2);
}
.isp__new { display: flex; gap: 6px; padding: 4px; }
.isp__input {
  flex: 1 1 auto;
  min-width: 0;
  height: 38px;
  padding: 0 12px;
  box-sizing: border-box;
  border: 1px solid var(--ig-br);
  border-radius: 12px;
  background: transparent;
  font: inherit;
  font-size: 14px;
  color: var(--ig-tx);
  outline: none;
}
.isp__input:focus { border-color: var(--ig-save); }
.isp__go {
  flex: none;
  height: 38px;
  padding: 0 14px;
  border: none;
  border-radius: 999px;
  background: var(--ig-go-bg);
  color: var(--ig-go-tx);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}
.isp__go.is-idle { opacity: .4; cursor: default; }
.isp__open { display: flex; align-items: center; height: 38px; padding: 0 10px; font-size: 13.5px; color: var(--ig-mu); text-decoration: none; }
.isp__open:hover { color: var(--ig-st); }

/* === PRC-921: Картинки — коллекции (десктоп) === */
/* templates/images_collections_desktop.html + static/js/collections-desktop.js.
   Etalon design/redesign-2026-09/ImagesCollections.dc.html: the name centred
   under the capsule with «⋯», the collections as a text row with counts and
   «+», the shared masonry grid (.ig, .ig-tile — «Картинки: сетка и плитка»)
   with a cross where the results have the bookmark. Flat: a 1px border, no
   shadow, as the other popovers. */
.cpage { padding-top: 0; padding-bottom: 80px; }
.cpage__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  margin-bottom: 22px;
  padding: 8px 0 6px;
  text-align: center;
}
.cpage__row { display: flex; align-items: center; justify-content: center; gap: 6px; max-width: 100%; }
.cpage__title {
  margin: 0;
  min-width: 0;
  font-size: 34px;
  font-weight: 600;
  letter-spacing: -.015em;
  line-height: 1.2;
  color: var(--ig-st);
  overflow-wrap: anywhere;
}
.cpage__rename {
  box-sizing: border-box;
  width: 380px;
  max-width: 100%;
  padding: 0 0 2px;
  border: none;
  border-bottom: 2px solid var(--ig-sp);
  background: transparent;
  font: inherit;
  font-size: 34px;
  font-weight: 600;
  letter-spacing: -.01em;
  line-height: 1.2;
  color: var(--ig-st);
  outline: none;
  text-align: center;
}
.cpage__rename[hidden], .cpage__title[hidden], .cpage__menuwrap[hidden], .cpage__menu[hidden],
.cpage__undo[hidden], .cpage .ig[hidden], .cpage__head[hidden] { display: none; }
.cpage__menuwrap { position: relative; flex: none; }
.cpage__menu-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--ig-mu2);
  cursor: pointer;
}
.cpage__menu-btn:hover, .cpage__menu-btn[aria-expanded="true"] { background: var(--ig-hov2); color: var(--ig-st); }
.cpage__menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 40;
  display: flex;
  flex-direction: column;
  min-width: 200px;
  padding: 6px;
  border: 1px solid var(--ig-br);
  border-radius: 16px;
  background: var(--ig-pop);
}
.cpage__menu button {
  display: flex;
  align-items: center;
  height: 36px;
  padding: 0 12px;
  border: none;
  border-radius: 10px;
  background: transparent;
  font: inherit;
  font-size: 14px;
  color: var(--ig-tx);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}
.cpage__menu button:hover { background: var(--ig-hov2); color: var(--ig-st); }
.cpage__tabs { display: flex; flex-wrap: wrap; justify-content: center; align-items: baseline; gap: 4px 20px; max-width: 100%; font-size: 14px; }
.cpage__tab {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
  max-width: 260px;
  padding: 2px 0;
  border: none;
  background: transparent;
  font: inherit;
  font-weight: 500;
  color: var(--ig-mu);
  cursor: pointer;
}
.cpage__tab:hover, .cpage__tab--on { color: var(--ig-st); }
.cpage__tab--on { font-weight: 600; }
.cpage__tab-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cpage__tab-count { flex: none; font-size: 12px; font-weight: 500; color: var(--ig-fa); }
.cpage__tab--new { align-items: center; color: var(--ig-fa); }
.cpage__undo {
  position: fixed;
  left: 50%;
  bottom: 24px;
  z-index: 60;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 14px;
  box-sizing: border-box;
  max-width: calc(100vw - 32px);
  height: 46px;
  padding: 0 8px 0 18px;
  border: 1px solid var(--ig-br);
  border-radius: 999px;
  background: var(--ig-pop);
  font-size: 14px;
  color: var(--ig-tx);
  white-space: nowrap;
}
.cpage__undo-text { display: inline-flex; min-width: 0; }
.cpage__undo-name { min-width: 0; max-width: 320px; overflow: hidden; text-overflow: ellipsis; }
.cpage__undo-btn {
  flex: none;
  height: 32px;
  padding: 0 14px;
  border: none;
  border-radius: 999px;
  background: var(--ig-hov2);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--ig-st);
  cursor: pointer;
}

/* PRC-921 (visual review): the cross reads on a light picture, the bookmark of
   the capsule is filled — we are on the collections page. */
.cpage .ig-tile__del { background: rgba(18, 16, 14, .55); }
.imgs--collections .searchbar--results .cap-coll { background: transparent; color: var(--menu-pill-active); }
.imgs--collections .searchbar--results .cap-coll svg { fill: currentColor; }

/* === Картинки: поиск по картинке (PRC-920) === */
/* design/redesign-2026-09/ImagesReverse.dc.html: the camera circle in the
   capsule, the upload panel under it (templates/_image_upload.html — the
   filters panel's surface, .ifp), the page-wide drop overlay, the picture
   chip in the capsule field and the «Похожие картинки» heading. Behaviour:
   static/js/image-upload.js. */
/* No «on» look while the panel is open: the mockup keeps the circle plain
   (unlike «Фильтры»); aria-expanded carries the state. */
.searchbar--results .cap-cam { color: var(--startbar-mic); }
.cap-cam svg { position: relative; top: -1px; }

.iup { gap: 14px; padding-top: 18px; }
.iup__idle { display: flex; flex-direction: column; gap: 14px; }
.iup__idle[hidden], .iup__busy[hidden] { display: none; }
.iup__drop {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 9px;
  height: 196px;
  margin: 0;
  box-sizing: border-box;
  border: 1.5px dashed var(--ig-trk);
  border-radius: 18px;
  text-align: center;
  color: var(--ig-mu2);
  transition: background-color .15s, border-color .15s;
}
.iup.is-drag .iup__drop { border-color: var(--ig-sp); background: var(--ig-hov2); }
.iup__drop-title { font-size: 16px; font-weight: 500; color: var(--ig-st); }
.iup__drop-hint { display: flex; align-items: center; gap: 5px; font-size: 13.5px; color: var(--ig-mu); }
.iup__drop-hint kbd {
  /* Fixed 18px box: ⌘ (U+2318) comes from a fallback font whose metrics made
     it 1px taller than Ctrl/V; every key now shares one height. */
  display: inline-flex;
  align-items: center;
  box-sizing: border-box;
  height: 18px;
  padding: 0 6px;
  border: 1px solid var(--ig-br);
  border-radius: 6px;
  font-family: inherit;
  font-size: 12px;
  color: var(--ig-tx);
}
.iup__drop-hint kbd:first-child { margin-left: 3px; }
.iup__pick {
  position: relative;
  display: inline-flex;
  align-items: center;
  margin-top: 4px;
  height: 36px;
  padding: 0 16px;
  box-sizing: border-box;
  border: 1px solid var(--ig-br);
  border-radius: 999px;
  background: var(--ig-pop);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  color: var(--ig-tx);
  cursor: pointer;
}
.iup__pick:hover { color: var(--ig-st); background: var(--ig-hov); }
.iup__pick:focus-within { outline: 2px solid var(--ig-sp); outline-offset: 2px; }
.iup__pick input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.iup__url { display: flex; gap: 8px; margin: 0; }
.iup__url-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 42px;
  padding: 0 16px;
  box-sizing: border-box;
  border: 1px solid var(--ig-br);
  border-radius: 999px;
  background: transparent;
  font: inherit;
  font-size: 14px;
  color: var(--ig-tx);
  outline: none;
}
.iup__url-input::placeholder { color: var(--ig-fa); }
/* The same visible ring as «Выбрать файл» and «Найти» (a text field
   matches :focus-visible on a click too — that is fine here). A refused
   link keeps its text; its border stays as drawn (m11, no error tone). */
.iup__url-input:focus-visible { outline: 2px solid var(--ig-sp); outline-offset: 2px; }
.iup__go {
  flex: none;
  height: 42px;
  padding: 0 18px;
  border: none;
  border-radius: 999px;
  background: var(--ig-go-bg);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--ig-go-tx);
  cursor: pointer;
}
.iup__go:focus-visible { outline: 2px solid var(--ig-sp); outline-offset: 2px; }
.iup__err { font-size: 13.5px; color: var(--ig-sp); overflow-wrap: anywhere; }
.iup__err[hidden] { display: none; }
.iup__note { font-size: 12.5px; color: var(--ig-fa); }
.iup__busy { display: flex; align-items: center; gap: 18px; padding: 4px 0 6px; }
/* Like the capsule chip: the Картинки icon holds the square, a file's
   preview covers it (a link has none — never an empty square). */
.iup__busy-thumb {
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 96px;
  height: 96px;
  border-radius: 14px;
  overflow: hidden;
  background: var(--ig-acc);
  color: var(--ig-mu2);
}
.iup__busy-thumb img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; }
.iup__busy-col { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.iup__busy-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 15px; font-weight: 500; color: var(--ig-st); }
.iup__bar { height: 4px; border-radius: 2px; background: var(--ig-acc); overflow: hidden; }
.iup__bar span { display: block; width: 0; height: 100%; border-radius: 2px; background: var(--ig-sp); }
/* The real progress is unknown (the browser is loading the next page): the
   bar runs towards the Lens deadline and waits near the end. */
.iup__busy.is-going .iup__bar span { animation: iupBar 6s cubic-bezier(.2, .6, .3, 1) forwards; }
@keyframes iupBar { from { width: 4%; } to { width: 92%; } }
.iup__busy-text { font-size: 13.5px; color: var(--ig-mu); }

.iup-drag {
  position: fixed;
  inset: 12px;
  z-index: 300;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  box-sizing: border-box;
  border: 2px dashed var(--ig-sp);
  border-radius: 16px;
  background: rgba(var(--ig-cap-rgb), .78);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--ig-mu2);
  text-align: center;
  pointer-events: none;
}
.iup-drag[hidden] { display: none; }
.iup-drag__box { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.iup-drag__title { font-size: 22px; font-weight: 600; color: var(--ig-st); }
.iup-drag__hint { font-size: 14px; color: var(--ig-mu); }

/* The searched picture as a chip at the head of the capsule field. */
.rheader__field .cap-rev {
  flex: none;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  margin-right: 8px;
  padding: 0 4px;
  box-sizing: border-box;
  border-radius: 12px;
  background: var(--ig-acc);
  max-width: 60%;
}
/* The square always holds the Картинки icon; the preview, when there is one
   and it loads, covers it (no preview or a failed one — the icon, not an
   empty square). */
.cap-rev__thumb {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  overflow: hidden;
  background: var(--ig-hov);
  color: var(--ig-mu2);
}
.cap-rev__thumb img { position: absolute; inset: 0; display: block; width: 100%; height: 100%; object-fit: cover; }
.cap-rev__name { min-width: 0; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13.5px; color: var(--ig-tx); }
.cap-rev__clear {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  color: var(--ig-mu2);
}
.cap-rev__clear:hover { background: var(--ig-hov); color: var(--ig-st); }
/* Too narrow for a readable name (image-upload.js fitChip): picture and cross only. */
.cap-rev--bare .cap-rev__name { display: none; }

.irev__title { margin: 12px 0 14px; font-size: 18px; font-weight: 600; line-height: 1.3; color: var(--ig-st); }

/* === Картинки: просмотр (PRC-919) === */
/* Desktop viewer, design/redesign-2026-09/ImagesLightbox.dc.html: a 1000px card
   over a dimmed page, the picture on the left, a 320px description column on
   the right. Markup templates/_image_viewer.html, behaviour js/image-viewer.js.
   Palette: the --ig-* tokens of `.imgs`; the two action-button tokens the
   mockup has and the palette does not (--moreBg / --moreHov) are --iv-btn /
   --iv-btn-hov here, in the same three theme blocks. Own class prefix `iv`:
   nothing of the phone lightbox (.ilb*, perecle.css) is reused or touched.
   Column order as in the mockup: description, «Перейти на сайт», the three
   buttons, a spacer, the copyright line. The card is as tall as the picture,
   never lower than the column, never higher than min(868px, 100vh − 52px)
   (PRC-927; image-viewer.js pins the height in px, so paging glides). Every
   line above the §9.7 line is bounded (domain one line, title three, author
   two, licence tag one; ellipsis, full text in title=), so the line is never
   clipped or covered, whatever the lengths, with the share panel open. The share panel takes the place of the
   copyright line under the buttons; when the card is too low for it the
   column under the counter and the cross scrolls (never past the §9.7 line;
   the head row stays); the save popover opens under the
   buttons too (keepClear: .iv__rkn) — neither lies on .iv__rkn. */
/* --btn2 (ImagesLightbox/ImagesShare/ImagesCollections .dc.html, PRC-982):
   the action tiles are beige in light (#efece5) instead of white; dark keeps
   the grey it has always had. */
.iv {
  --iv-btn: #efece5;
  --iv-btn-hov: #f5f2ec;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .iv { --iv-btn: #282a32; --iv-btn-hov: #33363f; }
}
:root[data-theme="dark"] .iv { --iv-btn: #282a32; --iv-btn-hov: #33363f; }

.iv {
  position: fixed;
  inset: 0;
  z-index: 100;
  box-sizing: border-box;
  padding: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(10, 9, 8, .74);
  color: var(--ig-tx);
  font-family: inherit;
}
.iv[hidden] { display: none; }
body.iv-open { overflow: hidden; }
.iv__card {
  position: relative;
  display: flex;
  align-items: stretch;
  width: 1000px;
  max-width: 100%;
  /* the picture sets the height (PRC-927): the script measures it at `auto` —
     the taller of the picture and the column — and pins it in px; «Поделиться»
     and «Сохранить» never grow it */
  max-height: min(868px, calc(100vh - 52px));
  transition: height .22s ease;
  border-radius: 18px;
  background: var(--ig-pop);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .35);
}
@media (prefers-reduced-motion: reduce) {
  .iv__card { transition: none; }
}
.iv__media {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  min-height: 300px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 18px 0 0 18px;
  overflow: hidden;
}
.iv__img {
  display: block;
  max-width: 100%;
  object-fit: contain;
  background: var(--ig-acc);
  transition: filter .3s ease;
}
.iv__img:not([src]) { visibility: hidden; }
.iv__img.is-blur { filter: blur(14px); }
.iv__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(28, 25, 22, .5);
  color: #fff;
  cursor: pointer;
}
.iv__nav:hover { background: rgba(28, 25, 22, .78); }
.iv__nav[hidden] { display: none; }
.iv__nav--prev { left: 14px; }
.iv__nav--next { right: 14px; }
.iv__loading {
  position: absolute;
  left: 50%;
  bottom: 20px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  height: 32px;
  padding: 0 14px;
  border-radius: 999px;
  background: rgba(28, 25, 22, .6);
  font-size: 13px;
  color: #fff;
  white-space: nowrap;
}
.iv__loading[hidden] { display: none; }

.iv__aside {
  flex: none;
  width: 320px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 0;
  padding: 16px 20px 20px;
  border-left: 1px solid var(--ig-br);
}
/* everything under the counter and the cross: a card as low as its picture
   scrolls this part for an open share panel, the head row stays put (PRC-927) */
.iv__body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* out to the column's edges, so focus rings are not clipped; the content
     stays where it was */
  margin: -4px -20px;
  padding: 4px 20px;
}
.iv__head { flex: none; display: flex; align-items: center; justify-content: space-between; }
.iv__counter { font-size: 13.5px; color: var(--ig-fa); }
.iv__close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  margin: -6px -8px -6px 0;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--ig-mu2);
  cursor: pointer;
}
.iv__close:hover { background: var(--ig-hov); color: var(--ig-st); }

/* the description takes its own height and never shrinks (.iv__body scrolls
   instead); every long line in it is bounded, so the §9.7 line stays whole and
   never runs under the buttons */
.iv__desc {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.iv__desc > * { flex: none; }
.iv__site { display: flex; align-items: center; gap: 8px; min-width: 0; color: var(--ig-mu); text-decoration: none; }
.iv__favicon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--ig-acc) center / 14px 14px no-repeat;
  color: var(--ig-tx);
  font-size: 10.5px;
  font-weight: 700;
}
.iv__domain { min-width: 0; font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.iv__title {
  font-size: 21px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--ig-st);
  text-wrap: pretty;
  overflow-wrap: anywhere;
  /* whole lines with an ellipsis, the full text is the element's title */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  overflow: hidden;
}
.iv__title[hidden], .iv__meta[hidden], .iv__lic[hidden], .iv__rkn[hidden] { display: none; }
.iv__meta { font-size: 13.5px; color: var(--ig-mu2); }
.iv__lic { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.iv__lic-tag {
  padding: 1px 6px;
  border: 1px solid var(--ig-br);
  border-radius: 5px;
  font-size: 11px;
  font-weight: 600;
  color: var(--ig-mu);
  text-decoration: none;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.iv__author {
  min-width: 0;
  font-size: 13.5px;
  color: var(--ig-mu);
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}
/* §9.7: a quiet line under the meta (ImagesMarkAndSave.spec.md §1.2) — wraps
   by words, never clipped, never a badge */
.iv__rkn {
  font-size: 13px;
  line-height: 1.45;
  font-weight: 400;
  color: var(--ig-mu2);
  text-wrap: pretty;
  overflow-wrap: break-word;
}

.iv__actions { flex: none; position: relative; display: flex; flex-direction: column; gap: 10px; }
.iv__spacer { flex: 1 1 auto; position: relative; min-height: 0; margin-top: -6px; }
.iv__aside.is-sharing .iv__note { display: none; }
.iv__go {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 46px;
  padding: 0 20px;
  border-radius: 999px;
  background: var(--ig-go-bg);
  color: var(--ig-go-tx);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
}
.iv__go[hidden] { display: none; }
.iv__row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.iv__act {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 66px;
  padding: 0;
  border: none;
  border-radius: 16px;
  background: var(--iv-btn);
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--ig-tx);
  text-decoration: none;
  cursor: pointer;
}
.iv__act:hover, .iv__act.is-on { background: var(--iv-btn-hov); color: var(--ig-st); }
.iv__act:disabled { opacity: .6; cursor: default; }
.iv__act.is-saved svg { fill: var(--ig-sp); color: var(--ig-sp); }
.iv__act.is-saved { color: var(--ig-st); }

/* The share panel (PRC-950): one block for the viewer of «Картинки» and for Искра
   (macro _share_panel.html, share-panel.js). Where it lies — under the picture
   here, under the share buttons in Искра — is the caller's rule, below. */
.sharepanel {
  display: flex;
  flex-direction: column;
  box-sizing: border-box;
  gap: 12px;
  padding: 14px;
  border-radius: 18px;
  background: var(--ig-pop);
  border: 1px solid var(--ig-br);
}
.sharepanel[hidden], .sharepanel__link[hidden], .sharepanel__copy[hidden], .sharepanel__targets[hidden], .sharepanel__err[hidden] { display: none; }
.sharepanel__label { font-size: 12.5px; font-weight: 600; color: var(--ig-fa); }
.sharepanel__row { display: flex; gap: 8px; }
.sharepanel__link {
  flex: 1 1 auto;
  min-width: 0;
  display: block;
  height: 40px;
  padding: 0 12px;
  border-radius: 12px;
  background: var(--ig-acc);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 13.5px;
  line-height: 40px;
  color: var(--ig-tx);
  text-decoration: none;
}
.sharepanel__copy {
  flex: none;
  height: 40px;
  padding: 0 14px;
  border: none;
  border-radius: 999px;
  background: var(--ig-go-bg);
  color: var(--ig-go-tx);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}
.sharepanel__targets { display: flex; flex-wrap: wrap; gap: 6px; }
.sharepanel__target {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 12px;
  border: 1px solid var(--ig-br);
  border-radius: 999px;
  font-size: 13px;
  color: var(--ig-mu);
  text-decoration: none;
}
.sharepanel__target:hover { color: var(--ig-st); background: var(--ig-hov2); }
.sharepanel__err { font-size: 13.5px; color: var(--ig-mu); }
/* in the viewer: floats in the gap under the buttons */
.iv__spacer .sharepanel { position: absolute; top: 0; left: 0; right: 0; z-index: 2; }
.iv__note { font-size: 12px; line-height: 1.45; color: var(--ig-fa); opacity: .7; text-wrap: pretty; }

/* /search start on a phone (PRC-963, MobileSearchStart.dc.html «01 Покой»):
   the phone form of the shared header — search_header_2026(phone=true). The
   web results page keeps its own 52px capsule. 17px field (the phone scale,
   PRC-1006; never under 16 or iOS zooms on focus — css/mobile/base.css
   --m-field-fs); no watermark in the capsule; the row's right edge fades out,
   the pod behind it never does. */
.rheader--phone .rheader__slot { height: 56px; }
.rheader--phone .searchbar--results { height: 56px; gap: 6px; padding: 0 6px; }
.rheader--phone .searchbar--results .cap-circle { width: 44px; height: 44px; }
.rheader--phone .rheader__field .searchbar__input { font-size: var(--m-field-fs, 17px); line-height: 56px; }
.rheader.rheader--phone[data-startbar] .cap-brand { display: none; }
.rheader--phone .rmenu {
  padding: 30px 10px 6px;
  border-radius: 0 0 22px 22px;
}
/* The right-edge fade belongs to the ROW, not to the plate, and shows only
   while there is something to scroll to — owner 02.10.2026 («гаснет только
   когда справа есть что листать; доскроллил — край чистый»); start.js toggles
   `is-fade-r` off the row's scroll position, the geometry is the mockup's own
   86%. The plate (.rmenu) carries no mask and stays whole to its rounded
   corner. Phone-scoped on purpose: the desktop pod has no fade (owner
   «десктоп не трогаем»), so the class is inert there. */
.rheader--phone .rmenu__scroll.is-fade-r {
  -webkit-mask-image: linear-gradient(90deg, #000 86%, transparent);
  mask-image: linear-gradient(90deg, #000 86%, transparent);
}
/* The tabs under the capsule — ONE pill on every vertical (PRC-1007, the
   phone scale of PRC-1006; MobileResults / MobileSearchStart / MobileStates /
   MobileIskra / MobileImages*): 36px high, 14/500, a 14px icon — the Искра
   spark (13) and the plus (26px, 15px glyph, tucked -4px) included; custom
   items are .rmenu__pill too (custom-menu.js). The pod grows 8px with them
   (30 + 36 + 6); start.js tucks it away by its measured height, and the
   Iskra dock counts it in css/mobile/iskra.css --m-iskra-dock. */
.rheader--phone .rmenu__pill { height: 36px; padding: 0 11px; font-size: 14px; }
.rheader--phone .rmenu__pill svg,
.rheader--phone .rmenu__pill--iskra .spark { width: 14px; height: 14px; }
.rheader--phone .rmenu__add { width: 36px; height: 36px; margin-left: 0; }
.rheader--phone .rmenu__add svg { width: 14px; height: 14px; }
/* Those 8px come out of the header's own bottom gap (16 → 8) where the phone
   header keeps one — Картинки, by picture, collections, /i/: their mockups
   already drew the 36px pills and put the first block 8px under the pod
   (MobileImages*: pod 110, block 118), so nothing under the header moves.
   The web pages carry no gap at all (css/mobile/web.css). */
.rheader--phone .rheader__bar { padding-bottom: 8px; }
