
  :root {
    color-scheme: light dark;
    /* Галочки, каретка и ползунки — фирменным цветом, а не системным синим */
    accent-color: var(--brand-1);

    /* Фирменная пара и градиент из неё */
    --brand-1: #7c3aed;
    --brand-2: #f97316;
    --brand: linear-gradient(135deg, var(--brand-1), var(--brand-2));

    --radius: 14px;
    --radius-sm: 10px;
    --gap: 8px;
    --pad: 13px;

    /* Поля страницы одной переменной: от неё же считается вылет
       прилипающего заголовка за край — иначе он перестаёт совпадать с
       краем экрана, стоит поменять отступ в одном месте */
    --gutter: 16px;

    /* Палец попадает не в текст, а в площадь. 44 пикселя — тот размер,
       ниже которого промахиваются все, а не только «неаккуратные» */
    --tap: 44px;
    --ease: cubic-bezier(.2, .7, .3, 1);

    /* Вырез камеры, полоса «домой» и шапка самого Telegram. Сначала
       нули: где max() с env() не поддержан, вся строка отбрасывается
       целиком, и без запасного значения отступы бы схлопнулись. */
    --safe-top: 0px;
    --safe-bottom: 0px;

    /* Две поверхности: блок на фоне страницы и «утопленное» внутри блока */
    --surface: var(--tg-theme-secondary-bg-color, #f4f4f7);
    --sunken: var(--tg-theme-bg-color, #fff);
    /* Граница вместо тени: на телефоне тени превращаются в грязь, а
       волосяная линия держит форму карточки в обеих темах */
    --line: rgba(120, 120, 140, .16);
    --tint: rgba(124, 58, 237, .10);
  }
  :root {
    --safe-top: max(env(safe-area-inset-top, 0px), var(--tg-content-safe-area-inset-top, 0px));
    --safe-bottom: max(env(safe-area-inset-bottom, 0px), var(--tg-safe-area-inset-bottom, 0px));
  }
  /* Панель открывают и с Telegram Desktop, где окно шире телефона втрое.
     Строка в тысячу пикселей не читается: глаз теряет начало следующей.
     Колонку держим той же, а лишнюю ширину отдаём полям — тогда и
     прилипающий заголовок по-прежнему упирается ровно в край колонки. */
  @media (min-width: 680px) {
    :root { --gutter: calc((100vw - 648px) / 2); }
  }
  body.dark {
    --line: rgba(255, 255, 255, .12);
    --tint: rgba(167, 139, 250, .14);
  }
  @media (prefers-color-scheme: dark) {
    body:not(.light) {
      --line: rgba(255, 255, 255, .12);
      --tint: rgba(167, 139, 250, .14);
    }
  }

  * { box-sizing: border-box; }
  /* Свои display побеждают браузерный [hidden], поэтому говорим прямо:
     скрытое — значит скрытое. Иначе строка сводки остаётся на экране
     ровно тогда, когда всё в порядке и показывать нечего. */
  [hidden] { display: none !important; }

  body {
    margin: 0;
    padding:
      calc(16px + var(--safe-top)) var(--gutter)
      calc(28px + var(--safe-bottom));
    font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
      "Helvetica Neue", Arial, sans-serif;
    background: var(--tg-theme-bg-color, #fff);
    color: var(--tg-theme-text-color, #111);
    -webkit-tap-highlight-color: transparent;
    /* Крупный шрифт в системных настройках не должен ломать вёрстку, но
       и не должен молча игнорироваться — 100% значит «как просили» */
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    /* Дотянув список до конца, продолжаешь тянуть — и страница уезжает
       вместе с содержимым позади неё. Внутри Mini App это выглядит как
       поломка, потому что «позади» там сам Telegram. */
    overscroll-behavior-y: contain;
    /* Убирает задержку в треть секунды перед нажатием на старых вебвью:
       браузер больше не ждёт, не будет ли это двойным касанием. Щипок
       для увеличения остаётся. */
    touch-action: manipulation;
  }

  /* ── шапка ──────────────────────────────────────────────────────── */
  header { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 14px; gap: 8px; }
  h1 {
    font-size: 22px; margin: 0; letter-spacing: -.02em;
    /* Цвет объявлен до градиента: если background-clip не поддержан,
       заголовок останется читаемым, а не исчезнет */
    color: var(--brand-1);
    background: var(--brand);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
  }
  /* Эмодзи под background-clip: text превращается в залитый квадрат,
     поэтому знак панели живёт вне градиента */
  h1 .logo { -webkit-text-fill-color: initial; background: none; }
  .who { font-size: 12px; opacity: .55; text-align: right; }

  /* ── вкладки периода ────────────────────────────────────────────── */
  .tabs {
    display: flex; gap: 4px; margin-bottom: 14px; padding: 4px;
    border-radius: var(--radius); background: var(--surface);
  }
  /* Вкладки и «таблетки» — настоящие кнопки, поэтому с них сперва
     снимается всё кнопочное оформление браузера: без этого неактивная
     вкладка забирала бы заливку из общего правила для button ниже и
     выглядела бы выбранной вместе с настоящей выбранной. */
  .tab, .subtab {
    -webkit-appearance: none; appearance: none;
    font: inherit; color: inherit; background: none; border: 0;
    cursor: pointer; user-select: none;
    transition: background .15s ease, color .15s ease;
  }
  .tab {
    flex: 1; text-align: center; padding: 9px 8px; min-height: 38px;
    border-radius: var(--radius-sm); font-size: 14px; font-weight: 500;
  }
  .tab.active { background: var(--brand); color: #fff; }
  @media (prefers-reduced-motion: reduce) { .tab, .subtab { transition: none } }

  /* ── поиск ──────────────────────────────────────────────────────── */
  .search { display: flex; gap: 8px; margin-bottom: 14px; }
  .search input { margin-top: 0; }
  .search button { flex: none; }

  /* ── строка «что встало» ────────────────────────────────────────── */
  /* Единственный элемент, который окрашен целиком: он появляется, только
     когда действительно есть что чинить, и должен ловить взгляд первым */
  .strip {
    display: flex; align-items: center; gap: 10px; cursor: pointer;
    padding: 11px var(--pad); margin-bottom: 14px; font-size: 13px; font-weight: 500;
    border-radius: var(--radius); background: var(--tint);
    border: 1px solid var(--line);
  }
  .strip:active { opacity: .65; }
  .strip .dot { width: 9px; height: 9px; border-radius: 50%; flex: none; background: var(--brand); }
  .strip .chev { margin-left: auto; opacity: .4; }

  /* ── показатели ─────────────────────────────────────────────────── */
  .group {
    font-size: 11px; text-transform: uppercase; letter-spacing: .07em;
    opacity: .45; margin: 20px 2px 7px; font-weight: 600;
  }
  .group:first-child { margin-top: 2px; }

  .card {
    display: flex; justify-content: space-between; align-items: center; gap: 12px;
    padding: var(--pad); margin-bottom: var(--gap); border-radius: var(--radius);
    background: var(--surface); border: 1px solid var(--line);
  }
  .card .label { font-size: 14px; }
  .card .value { font-size: 19px; font-weight: 650; white-space: nowrap; letter-spacing: -.01em; }
  .card.tappable { cursor: pointer; }
  .card.tappable:active { opacity: .65; }
  .card .chev { opacity: .35; font-size: 13px; margin-left: 5px; }

  /* Своя очередь — единственная строка про тебя лично, ей и место героя */
  .card.hero {
    background: var(--brand); border-color: transparent; color: #fff;
    padding: 15px var(--pad); margin-bottom: 12px;
  }
  .card.hero .label { font-size: 15px; font-weight: 600; }
  .card.hero .value { font-size: 24px; font-weight: 700; }
  .card.hero .chev, .card.hero .delta { opacity: .8; }

  .note { font-size: 11px; opacity: .6; margin-left: 6px; }
  .delta { font-size: 11px; font-weight: 600; margin-left: 6px; opacity: .7; white-space: nowrap; }
  .delta.flat { opacity: .35; }

  /* ── голос вместо клавиатуры ────────────────────────────────────── */
  /* Микрофон стоит тише кнопки «Найти»: диктовать можно, а искать —
     нужно, и главным действием остаётся второе */
  .search .mic {
    flex: none; padding: 10px 12px; font-size: 15px; line-height: 1;
    background: var(--surface); border: 1px solid var(--line); color: inherit;
  }
  /* Идёт запись — красным и с пульсом: перепутать это с «не нажалось»
     нельзя, а системный значок записи виден не на всяком телефоне */
  .search .mic.rec {
    background: #d33; border-color: transparent; color: #fff;
    animation: beat 1.1s ease-in-out infinite;
  }
  @keyframes beat { 0%, 100% { opacity: 1 } 50% { opacity: .5 } }
  @media (prefers-reduced-motion: reduce) { .search .mic.rec { animation: none } }
  .heard { font-size: 12px; opacity: .7; margin: -8px 0 12px; }
  .heard.bad { color: #d33; opacity: 1; }

  /* ── сказанное голосом ждёт подтверждения ───────────────────────── */
  /* Стоит первой строкой в карточке и окрашено: это единственное место
     панели, где она предлагает что-то изменить сама, и пройти мимо него
     глазами нельзя */
  .order {
    padding: var(--pad); margin-bottom: 12px; border-radius: var(--radius);
    background: var(--tint); border: 1px solid var(--line);
  }
  .order .what { font-size: 15px; font-weight: 600; }
  .order .acts { margin-top: 10px; padding-top: 0; border-top: 0; }

  /* ── первый экран ───────────────────────────────────────────────── */
  /* Пока панель объясняет про токен, вкладки периода, поиск и строка
     вставших заявок только мешают: под ними ещё ничего нет, а выбирать
     «сегодня или неделю» не из чего. Прячем стилями, а не только
     свойством hidden: строка вставших приходит своим ответом позже и
     иначе вылезла бы поверх объяснения. */
  body.welcome .tabs, body.welcome .search, body.welcome .strip { display: none; }
  .hello { margin-top: 4px; }
  /* Здесь это обычный текст, а не цитата из Jira: рамка и заливка
     .prose делают из него блок, которого никто не читает */
  .hello .prose { background: none; border: 0; padding: 0; }
  .steps { margin: 6px 0 4px; }
  .step { display: flex; align-items: center; gap: 10px; font-size: 14px; padding: 6px 0; }
  .step .num {
    flex: none; width: 22px; height: 22px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--brand); color: #fff; font-size: 12px; font-weight: 700;
  }
  /* Отказаться должно быть так же просто, как согласиться, но не так же
     заметно: панель без токена работает, и настаивать не на чем */
  .hello .skip { background: none; border: 0; opacity: .65; font-weight: 400; }

  /* ── перенос показателя ─────────────────────────────────────────── */
  /* Оторванная строка приподнята тенью: под пальцем должно быть видно,
     что она уже не на месте, а едет. Соседи расходятся с переходом, сама
     строка идёт за пальцем без него — иначе она отстаёт ровно на длину
     анимации, и жест ощущается вязким. */
  .card, .group { transition: transform .16s var(--ease); }
  .card.lifted, .group.lifted {
    position: relative; z-index: 10; transition: none;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .28);
  }
  .card.lifted { border-color: var(--brand-1); }
  .group.lifted { opacity: 1; }
  /* Пока идёт перенос, выделение текста только мешает: палец держат на
     строке, а браузер понимает это как «выделить слово» */
  body.reordering { user-select: none; -webkit-user-select: none; }
  body.reordering .card, body.reordering .group { cursor: grab; }
  body.reordering .lifted { cursor: grabbing; }
  @media (prefers-reduced-motion: reduce) { .card, .group { transition: none } }

  /* ── список заявок ──────────────────────────────────────────────── */
  .issue {
    display: block; padding: 12px var(--pad); margin-bottom: var(--gap);
    border-radius: var(--radius); background: var(--surface);
    border: 1px solid var(--line); color: inherit; text-decoration: none;
  }
  .issue:active { opacity: .65; }
  .issue .key { font-size: 12px; font-weight: 700; letter-spacing: .01em; color: var(--brand-1); }
  body.dark .issue .key { color: #a78bfa; }
  @media (prefers-color-scheme: dark) { body:not(.light) .issue .key { color: #a78bfa; } }
  .issue .summary { font-size: 14px; margin: 4px 0; }
  .issue .meta { font-size: 11px; opacity: .6; }
  .issue .line { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
  .issue .chev { opacity: .35; font-size: 13px; transition: transform .15s ease; }
  .issue.open .chev { transform: rotate(90deg); }
  @media (prefers-reduced-motion: reduce) { .issue .chev { transition: none } }

  /* Заявка, раскрытая прямо в списке: шапка и тело — один блок, поэтому
     у шапки снизу углы выпрямляются, а тело подхватывает рамку */
  .issuebox { margin-bottom: var(--gap); }
  .issuebox > .issue { margin-bottom: 0; }
  .issuebox > .issue.open { border-bottom-left-radius: 0; border-bottom-right-radius: 0; border-bottom: 0; }
  .expand {
    padding: 2px var(--pad) 13px; background: var(--surface);
    border: 1px solid var(--line); border-top: 0;
    border-radius: 0 0 var(--radius) var(--radius);
  }
  .expand .chips { margin-top: 10px; }

  /* Сводка по поисковому запросу — «сколько такого вообще бывает» */
  .digest {
    padding: var(--pad); margin-bottom: 12px; border-radius: var(--radius);
    background: var(--tint); border: 1px solid var(--line);
  }
  .digest .big { font-size: 17px; font-weight: 650; letter-spacing: -.01em; }

  .back { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
  .back h2 { font-size: 15px; margin: 0; font-weight: 600; }

  /* ── разделы ────────────────────────────────────────────────────── */
  details { margin-top: 22px; }
  summary {
    cursor: pointer; font-size: 14px; font-weight: 600; padding: 6px 0;
    opacity: .85; list-style-position: inside;
  }
  summary::marker { color: var(--brand-1); }
  /* Заголовок раскрытого раздела прилипает к верху экрана. Разделы длинные —
     обзор месяца это полгода строк, — и чтобы свернуть, приходилось листать
     обратно до самого начала. Прилипает только верхний уровень: заголовок
     «Похожие» внутри карточки заявки должен уезжать вместе с ней.
     Поля тянутся на отступ страницы, иначе из-под строки выезжают карточки. */
  body > details[open] > summary,
  /* Раздел внутри свёрнутой в один пункт группы («Аналитика потока» и
     подобные) — тот же длинный список, прилипание нужно ему точно так же */
  .navgroup > details[open] > summary {
    position: sticky; top: var(--safe-top); z-index: 5;
    margin: 0 calc(-1 * var(--gutter)); padding: 8px var(--gutter);
    background: var(--tg-theme-bg-color, #fff);
    box-shadow: 0 1px 0 var(--line);
    opacity: 1;
  }
  /* Группа-папка сама не тянет длинный список — прилипать ей незачем,
     а margin-top у вложенных <details> внутри не должен удваивать отступ */
  .navgroup { margin-top: 20px; }
  .navgroup > summary.group {
    cursor: pointer; list-style: none; margin: 0; padding: 0;
    display: flex; align-items: center; gap: 5px;
  }
  .navgroup > summary.group::-webkit-details-marker { display: none; }
  .navgroup > summary.group::after {
    content: "›"; opacity: .45; font-size: 12px; transition: transform .15s ease;
  }
  .navgroup[open] > summary.group::after { transform: rotate(90deg); }
  .navgroup > details:first-of-type { margin-top: 10px; }
  @media (prefers-reduced-motion: reduce) { .navgroup > summary.group::after { transition: none } }
  /* Дата снимка в заголовке раздела. Без своего класса она вставала
     вплотную к названию — «Insidioснимок 02.09»: у верхнего summary нет
     флекса, а .headline живёт только внутри строк сравнения. */
  summary .stamp {
    font-size: 11px; font-weight: 400; opacity: .55;
    margin-left: 8px; white-space: nowrap;
  }

  /* Человек внутри раскрытого кабинета или отдела. Именно строка, а не
     карточка: карточка с фоном и рамкой внутри такой же карточки даёт
     коробку в коробке, и список из сорока человек выглядит рябью. */
  .who-line { padding: 7px 2px; border-top: 1px solid var(--line); }
  .who-line:first-child { border-top: none; }
  .who-line .name { font-size: 14px; font-weight: 500; }
  .who-line .caption { margin-top: 2px; }
  .who-line.tappable { cursor: pointer; }
  .who-line.tappable:active { opacity: .55; }
  /* Этаж внутри кабинета: заголовок группы, а не такая же строка */
  .who-floor {
    font-size: 11px; opacity: .5; letter-spacing: .04em; text-transform: uppercase;
    margin: 12px 0 2px; font-weight: 600;
  }

  /* Фото сотрудника. Кружком и мелко: оно помогает узнать человека, а не
     разглядывать его, — а страницу списком портретов забивать нечем. */
  .face {
    width: 34px; height: 34px; border-radius: 50%; flex: none;
    object-fit: cover; background: var(--tint); display: block;
  }
  .face-none {
    display: flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 600; opacity: .55; letter-spacing: .02em;
  }
  /* Имя и фото в одной строке: без флекса портрет уводит текст вниз */
  .sum .who-face { display: flex; align-items: center; gap: 9px; min-width: 0; }
  .sum .who-face .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Отдел — строкой под именем, не рядом с ним: «Кузнецова Александра
     Кирилловна» и «Отдел по качеству контента» вдвоём в один ряд не
     влезали и резались многоточием оба разом */
  .sum .who-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
  .sum .who-text .dept {
    font-size: 12px; opacity: .6; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }

  /* С переносом: подвкладок Insidio четыре, а групп техники бывает пять
     — в одну строку узкого экрана они не встают и уезжали за край */
  .subtabs { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 12px; }
  .subtab {
    padding: 8px 14px; min-height: 34px; border-radius: 999px;
    font-size: 12px; font-weight: 500;
    background: var(--surface); border: 1px solid var(--line);
  }
  .subtab.active { background: var(--brand); border-color: transparent; color: #fff; }

  /* ── повестка на дейли ──────────────────────────────────────────── */
  .agenda {
    padding: 12px var(--pad); margin-bottom: var(--gap); border-radius: var(--radius);
    background: var(--surface); border: 1px solid var(--line);
  }
  .agenda.tappable { cursor: pointer; }
  .agenda.tappable:active { opacity: .65; }
  .agenda .top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
  .agenda .name { font-size: 15px; font-weight: 600; }
  /* Действие — то, ради чего пункт написан, поэтому оно набрано цветом
     акцента, а не серым вместе с остальными подробностями */
  .agenda .todo {
    font-size: 13px; margin-top: 7px; padding-top: 7px;
    border-top: 1px solid var(--line); color: var(--brand-1); font-weight: 500;
  }
  body.dark .agenda .todo { color: #c4b5fd; }
  @media (prefers-color-scheme: dark) { body:not(.light) .agenda .todo { color: #c4b5fd; } }
  body.classic .agenda .todo { color: var(--tg-theme-link-color, #2481cc); }

  /* ── разбор долга ───────────────────────────────────────────────── */
  /* Тема заявки здесь не подпись, а то, ради чего в карточку смотрят:
     решают-то по существу, а не по номеру */
  .agenda .dsum { font-size: 13px; line-height: 1.4; margin-top: 5px; }
  .agenda .value { font-size: 13px; font-weight: 650; white-space: nowrap; opacity: .75; }
  /* Кнопки решений в строку с переносом: на узком экране «Переносим»
     уезжает вниз само, а не вылезает за край */
  .acts {
    display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px;
    padding-top: 9px; border-top: 1px solid var(--line);
  }
  .acts button { flex: 1 1 auto; padding: 8px 12px; font-size: 13px; }

  /* ── офисы ──────────────────────────────────────────────────────── */
  .office {
    padding: 11px var(--pad); border-radius: var(--radius); margin-bottom: var(--gap);
    background: var(--surface); border: 1px solid var(--line); cursor: pointer;
  }
  .office:active { opacity: .65; }
  .office .top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
  .office .name { font-size: 15px; font-weight: 600; }
  .office .value { font-size: 17px; font-weight: 650; white-space: nowrap; }
  /* Шеврон не должен липнуть к стрелке динамики: «14 ▼ −13›» читается
     как одно число */
  .office .chev, .topic .chev, .wline .chev { margin-left: 5px; opacity: .35; font-size: 13px; }
  .office .caption { margin-top: 3px; }
  /* Этажи и темы — теги: их читают взглядом, а не строкой */
  .office .tags, .wline .tags { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
  .office .tag, .wline .tag {
    font-size: 11px; padding: 3px 8px; border-radius: 999px;
    background: var(--tint); color: var(--brand-1);
  }
  body.dark .office .tag, body.dark .wline .tag { color: #c4b5fd; }
  @media (prefers-color-scheme: dark) {
    body:not(.light) .office .tag, body:not(.light) .wline .tag { color: #c4b5fd; }
  }
  body.classic .office .tag, body.classic .wline .tag {
    background: var(--sunken); color: var(--tg-theme-link-color, #2481cc);
  }

  /* ── недельный обзор ────────────────────────────────────────────── */
  .wblock { margin-bottom: var(--gap); }
  .wblock > .name {
    font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
    opacity: .5; margin: 0 2px 6px;
  }
  .wline {
    padding: 9px var(--pad); border-radius: var(--radius); margin-bottom: 4px;
    background: var(--surface); border: 1px solid var(--line);
  }
  .wline.tappable { cursor: pointer; }
  .wline.tappable:active { opacity: .65; }
  .wline .top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
  .wline .label { font-size: 14px; }
  .wline .value { font-size: 16px; font-weight: 650; white-space: nowrap; }
  .wline .caption { margin-top: 3px; }
  .period { margin-bottom: 12px; }

  /* ── зрелость процессов ─────────────────────────────────────────── */
  /* Состояние признака несёт эмодзи, а не только цвет: цветом одним
     это не читается ни в чёрно-белом скриншоте, ни при дальтонизме.
     Полоса слева — вторая подсказка, а не единственная. */
  .sig { border-left-width: 3px; }
  .sig.ok { border-left-color: #2fa36b; }
  .sig.watch { border-left-color: #d99a2b; }
  .sig.risk { border-left-color: #d3533a; }
  .sig .target { opacity: .55; }
  /* Что делать — набрано как вывод обзора: это единственная строка
     признака, по которой можно действовать */
  .fix {
    font-size: 13px; line-height: 1.45; margin-top: 6px;
    padding-left: 9px; border-left: 2px solid var(--brand-1); color: var(--brand-1);
  }
  body.dark .fix { color: #c4b5fd; border-left-color: #c4b5fd; }
  @media (prefers-color-scheme: dark) {
    body:not(.light) .fix { color: #c4b5fd; border-left-color: #c4b5fd; }
  }
  body.classic .fix {
    color: var(--tg-theme-link-color, #2481cc);
    border-left-color: var(--tg-theme-link-color, #2481cc);
  }
  /* Вывод блока — то, ради чего блок читают: он набран цветом акцента,
     а цифры над ним остаются служебными подробностями */
  .verdict {
    font-size: 13px; line-height: 1.45; margin: 7px 2px 0;
    padding-left: 9px; border-left: 2px solid var(--brand-1); color: var(--brand-1);
  }
  body.dark .verdict { color: #c4b5fd; border-left-color: #c4b5fd; }
  @media (prefers-color-scheme: dark) {
    body:not(.light) .verdict { color: #c4b5fd; border-left-color: #c4b5fd; }
  }
  body.classic .verdict {
    color: var(--tg-theme-link-color, #2481cc);
    border-left-color: var(--tg-theme-link-color, #2481cc);
  }

  /* Готовый текст: моноширинный, с сохранением переносов — его копируют
     целиком, поэтому он и выглядит как текст письма, а не как карточка */
  .report {
    white-space: pre-wrap; word-break: break-word; font-size: 12px; line-height: 1.5;
    padding: 12px var(--pad); border-radius: var(--radius); margin: 0 0 8px;
    background: var(--sunken); border: 1px solid var(--line);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  }
  .copy { width: 100%; }

  /* ── темы потока ────────────────────────────────────────────────── */
  .topic {
    padding: 11px var(--pad); margin-bottom: var(--gap); border-radius: var(--radius);
    cursor: pointer; background: var(--surface); border: 1px solid var(--line);
  }
  .topic:active { opacity: .65; }
  .topic .top { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; }
  .topic .name { font-size: 15px; font-weight: 600; }
  .topic .value { font-size: 17px; font-weight: 650; white-space: nowrap; }
  .topic .caption { margin-top: 3px; }
  /* Доля темы полоской: глазами она читается быстрее процента */
  .bar { height: 3px; margin-top: 9px; border-radius: 999px; background: var(--line); overflow: hidden; }
  .bar .fill { height: 100%; border-radius: 999px; background: var(--brand); }

  /* ── сравнение сотрудников ──────────────────────────────────────── */
  .teamrow {
    margin-bottom: var(--gap); border-radius: var(--radius); padding: 11px var(--pad);
    background: var(--surface); border: 1px solid var(--line);
  }
  .teamrow > .sum {
    display: flex; justify-content: space-between; align-items: baseline;
    gap: 10px; cursor: pointer; opacity: 1; padding: 0; list-style: none;
  }
  /* Стрелку рисует ::marker, в вебвью Safari — ::-webkit-details-marker */
  .teamrow > .sum::-webkit-details-marker { display: none; }
  .teamrow > .sum::after { content: "›"; opacity: .35; transition: transform .15s ease; }
  .teamrow[open] > .sum::after { transform: rotate(90deg); }
  .teamrow .name { font-size: 15px; font-weight: 600; }
  .teamrow .headline { font-size: 13px; opacity: .75; white-space: nowrap; margin-left: auto; }
  .teamrow > .stats { margin-top: 11px; }
  .teamrow .kind { font-size: 11px; opacity: .6; margin: 11px 0 5px; }
  @media (prefers-reduced-motion: reduce) { .teamrow > .sum::after { transition: none } }

  /* Тело раскрытой строки. Именно блок, а не флекс-ряд: сюда кладут
     обычное содержимое — поля карточки человека, список людей по этажам,
     заявки группы. Когда здесь стоял flex с переносом,
     каждая строка становилась флекс-элементом по ширине своего текста, и
     карточка рассыпалась: заголовок «MAC-адреса · 2» вставал в один ряд
     с первым адресом, а значение уезжало под подпись. Ряд из плиток —
     это .cells ниже, и он свой ряд объявляет сам. */
  .stats { display: block; }
  /* Плитки показателей сотрудника. Сетка, а не флекс с переносом:
     у флекса каждая плитка по ширине своего текста, и «в работе» у
     одного человека оказывается не там, где у другого, — а раздел ровно
     про то, чтобы сравнивать их глазами по столбцу. */
  .cells {
    display: grid; gap: 6px;
    grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  }
  .teamrow > .cells { margin-top: 11px; }
  .stat {
    display: flex; align-items: baseline; gap: 6px; padding: 6px 10px;
    border-radius: var(--radius-sm); background: var(--sunken);
    border: 1px solid var(--line); font-size: 14px;
  }
  .stat.tappable { cursor: pointer; }
  .stat.tappable:active { opacity: .65; }
  .stat .cap { opacity: .6; font-size: 11px; }

  .person {
    padding: 11px var(--pad); margin-bottom: var(--gap); border-radius: var(--radius);
    background: var(--surface); border: 1px solid var(--line);
  }
  .person .top { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
  .person .name { font-size: 14px; font-weight: 600; }
  .person .meta { font-size: 11px; opacity: .6; margin-top: 2px; }
  .person .actions { display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap; }

  /* ── карточка заявки ────────────────────────────────────────────── */
  .issuecard { padding: var(--pad); border-radius: var(--radius); background: var(--surface); border: 1px solid var(--line); }
  .issuecard .subject { font-size: 17px; font-weight: 650; margin: 0 0 11px; letter-spacing: -.01em; }
  .chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
  .chipmark {
    font-size: 11px; padding: 4px 9px; border-radius: 999px;
    background: var(--sunken); border: 1px solid var(--line); opacity: .9;
  }
  /* Без min-width:0 длинное значение («оборудование диджеев», MAC-адрес)
     не сжимается и не переносится — флекс-элемент по умолчанию не
     сокращается меньше своего контента, и строка уезжает вбок вместо
     переноса. С min-width:0 браузер обязан искать место для переноса. */
  .field { display: flex; flex-wrap: wrap; gap: 4px 8px; font-size: 13px; padding: 3px 0; }
  .field .cap { opacity: .55; min-width: 96px; flex: none; }
  .field > :last-child { flex: 1 1 140px; min-width: 0; overflow-wrap: break-word; }
  .kind { font-size: 11px; opacity: .6; margin: 14px 0 6px; text-transform: uppercase; letter-spacing: .05em; }
  /* Описание и комментарии — обычный текст: Jira Server отдаёт их в своей
     вики-разметке, переносы в ней значимы, а длинные ссылки не должны
     распирать экран вбок */
  .prose {
    font-size: 13px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere;
    padding: 11px; border-radius: var(--radius-sm); background: var(--sunken);
    border: 1px solid var(--line);
  }
  .comment { margin-bottom: 9px; }
  .comment .meta { font-size: 11px; opacity: .6; margin-bottom: 4px; }
  .issuecard button { margin-top: 14px; width: 100%; }
  /* Действия в заявке. Отделены линией и стоят перед «Открыть в Jira»:
     сперва то, что делается здесь, потом выход наружу. Кнопки в ряд с
     переносом — на узком экране четвёртая уезжает вниз сама */
  .doing {
    display: flex; flex-wrap: wrap; gap: 6px;
    margin-top: 16px; padding-top: 13px; border-top: 1px solid var(--line);
  }
  .doing button { flex: 1 1 40%; margin-top: 0; width: auto; padding: 9px 10px; font-size: 13px; }
  .doform { margin-top: 10px; }
  .doform textarea {
    width: 100%; min-height: 84px; padding: 10px 12px; border-radius: var(--radius-sm);
    font: inherit; resize: vertical; border: 1px solid var(--line);
    background: var(--surface); color: var(--tg-theme-text-color, #111);
  }
  .doform textarea:focus { outline: 2px solid var(--brand-1); outline-offset: -1px; }
  .doform button { margin-top: 8px; }
  /* Варианты — статусы и исполнители — плитками, а не выпадающим списком:
     нативный select во вебвью Telegram открывается системным колесом,
     из которого не видно, что было на экране */
  .picks { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
  .picks button { flex: 0 1 auto; width: auto; margin-top: 0; padding: 8px 12px; font-size: 13px; }
  .picks button.closing { background: var(--brand); color: #fff; border-color: transparent; }
  /* Тот, на ком заявка сейчас. Нажать нельзя, но и выглядеть сломанной
     кнопкой не должна: это ответ «уже на нём», а не «недоступно» */
  .picks button.now:disabled { opacity: 1; background: var(--tint); border-color: var(--brand-1); }
  .done { color: #2f855a; font-size: 13px; margin-top: 10px; font-weight: 550; }

  /* Выходы из карточки — «в чат» и «в Jira» — рядом, а не столбиком: оба
     короткие, оба про «унести отсюда». Без верхней черты: она уже нарисована
     у ряда действий прямо над ними */
  .exits { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
  .exits button { flex: 1 1 40%; width: auto; margin-top: 0; padding: 9px 10px; font-size: 13px; }

  .similar { margin-top: 16px; }
  .similar summary { font-size: 13px; }
  .similar .comment { margin: 6px 0 12px; }

  /* ── кнопки и поля ──────────────────────────────────────────────── */
  button {
    padding: 9px 14px; min-height: 38px; border: 0; border-radius: var(--radius-sm);
    font: inherit; font-weight: 500; cursor: pointer;
    background: var(--brand); color: #fff;
    transition: opacity .15s ease;
  }
  button:active { opacity: .75; }
  button.ghost {
    background: var(--surface); border: 1px solid var(--line);
    color: var(--tg-theme-text-color, #111);
  }
  button.danger { background: #e0603a; color: #fff; }
  button:disabled { opacity: .5; cursor: default; }
  @media (prefers-reduced-motion: reduce) { button { transition: none } }

  input[type=text], input[type=search] {
    width: 100%; padding: 10px 12px; border-radius: var(--radius-sm); font: inherit; margin-top: 6px;
    border: 1px solid var(--line);
    background: var(--surface); color: var(--tg-theme-text-color, #111);
    /* Без сброса вида webkit рисует поле поиска по-своему: скруглений
       нет, высота своя, фон белый в тёмной теме */
    -webkit-appearance: none; appearance: none;
  }
  /* Свой крестик очистки: системный в тёмной теме почти не виден, потому
     что нарисован серым по серому и цвет темы не знает. Этот берёт цвет
     текста, значит виден в любой из трёх. */
  input[type=search]::-webkit-search-cancel-button {
    -webkit-appearance: none; appearance: none;
    width: 18px; height: 18px; cursor: pointer;
    background: currentColor; opacity: .45;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 4l8 8M12 4l-8 8' stroke='%23000' stroke-width='2' stroke-linecap='round' fill='none'/%3E%3C/svg%3E") center / 12px 12px no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 4l8 8M12 4l-8 8' stroke='%23000' stroke-width='2' stroke-linecap='round' fill='none'/%3E%3C/svg%3E") center / 12px 12px no-repeat;
  }
  input[type=text]:focus, input[type=search]:focus { outline: 2px solid var(--brand-1); outline-offset: -1px; }
  /* Галочки показателей: 13 пикселей системного квадратика — это
     попадание пальцем через раз */
  .row input[type=checkbox] { width: 19px; height: 19px; flex: none; }

  /* ── видно, куда нажимаешь клавиатурой ──────────────────────────── */
  /* Только клавиатуре: :focus-visible не срабатывает от пальца и мыши,
     поэтому обводка не появляется там, где она читалась бы как ошибка */
  :focus-visible {
    outline: 2px solid var(--brand-1);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
  }
  :focus:not(:focus-visible) { outline: none; }

  /* ── цифры в столбик ────────────────────────────────────────────── */
  /* Пропорциональные цифры разной ширины: «11» уже «88», и колонка
     значений в сравнении сотрудников гуляет строка от строки. Панель
     ровно про то, чтобы сравнивать их глазами сверху вниз. Заодно
     значение перестаёт дёргаться при каждом обновлении. */
  .value, .delta, .big, .headline, .badge, .stat, .caption, .meta,
  .axis, .ts, .report, .who-line .caption {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
  }

  /* ── длинные списки ─────────────────────────────────────────────── */
  /* Отдел на сорок человек и месяц заявок — это сотни строк, и браузер
     раскладывает их все, хотя на экране помещается восемь. Пропускать
     то, что за экраном, он умеет сам, если разрешить и подсказать
     примерную высоту; auto в размере значит «а дальше запомни настоящую». */
  .issuebox, .who-line { content-visibility: auto; }
  .issuebox { contain-intrinsic-size: auto 84px; }
  .who-line { contain-intrinsic-size: auto 46px; }

  /* Переносы по смыслу, а не по краю: заголовок не оставляет одно слово
     на второй строке, абзац — висячую строку из одного слова */
  h1, h2, .subject, .name, .label { text-wrap: balance; }
  .prose, .caption, .verdict, .fix, .todo { text-wrap: pretty; }

  /* Кому системного контраста мало — линии перестают быть волосяными */
  @media (prefers-contrast: more) {
    :root { --line: rgba(90, 90, 110, .5); }
    body.dark, body.lineage { --line: rgba(255, 255, 255, .38); }
    .caption, .meta, .note, .who, .updated { opacity: .8; }
  }

  /* ── служебное ──────────────────────────────────────────────────── */
  .row { display: flex; align-items: center; gap: 8px; padding: 6px 0; font-size: 14px; }
  .empty { opacity: .6; font-size: 14px; padding: 22px 0; text-align: center; }
  .error { color: #d33; font-size: 13px; margin-top: 12px; }
  /* Кнопка «Повторить» стоит под текстом ошибки, а не липнет к нему */
  .error button { margin-top: 9px; }
  .warn {
    font-size: 12px; padding: 10px 11px; border-radius: var(--radius-sm); margin-bottom: 9px;
    background: var(--tint); border: 1px solid var(--line);
  }
  .caption { font-size: 11px; opacity: .55; margin-top: 3px; line-height: 1.45; }
  .readout { font-size: 12px; min-height: 18px; margin-top: 4px; }
  /* Строка «обновлено» — она же кнопка обновления, поэтому не просто
     подпись по центру, а ряд: время слева, действие справа */
  .updated {
    display: flex; flex-wrap: wrap; gap: 10px;
    align-items: center; justify-content: center;
    margin-top: 18px; font-size: 11px; opacity: .55; text-align: center;
  }
  .restamp {
    padding: 6px 12px; min-height: 32px; border-radius: 999px;
    font-size: 11px; font-weight: 500;
    background: none; border: 1px solid var(--line); color: inherit;
  }
  .restamp:active { opacity: .6; }

  /* ── потянуть вниз, чтобы обновить ──────────────────────────────── */
  /* Метка висит над содержимым и выезжает вместе с жестом. Пока жест
     идёт, переход по transform выключен: иначе метка отстаёт от пальца
     на длину анимации и жест ощущается вязким. Возвращается — уже с
     переходом, потому что палец её больше не ведёт. */
  .pull {
    position: fixed; top: calc(var(--safe-top) + 6px); left: 50%;
    margin-left: -18px; width: 36px; height: 36px; z-index: 20;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%; pointer-events: none;
    background: var(--surface); border: 1px solid var(--line);
    color: var(--brand-1); opacity: 0;
    transition: opacity .15s ease;
  }
  .pull:not(.live) { transform: none; transition: opacity .25s ease, transform .25s var(--ease); }
  .pull.live { opacity: 1; }
  .pull-mark { font-size: 17px; line-height: 1; transition: transform .2s var(--ease); }
  /* Порог пройден — метка развернулась: отпускай */
  .pull.ready { color: #fff; background: var(--brand); border-color: transparent; }
  .pull.ready .pull-mark { transform: rotate(180deg); }
  @media (prefers-reduced-motion: reduce) {
    .pull, .pull-mark { transition: none }
  }

  /* ── переход между экранами ─────────────────────────────────────── */
  /* Список, карточка и главный экран сменяют друг друга в одном
     контейнере. Браузер, который умеет переход, закрывает подмену
     собой — быстро, чтобы это читалось как смена экрана, а не как
     анимация ради анимации. Кто не умеет — просто рисует сразу. */
  @media (prefers-reduced-motion: no-preference) {
    ::view-transition-old(root), ::view-transition-new(root) { animation-duration: .16s; }
  }
  .badge {
    font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 999px;
    background: var(--brand); color: #fff; margin-left: 7px;
  }
  /* Заглушка на время загрузки. Блик, бегущий слева направо, а не
     мигание целиком: мигание читается как «сломалось и моргает», а
     движение в одну сторону — как «идёт, подожди». */
  .skeleton {
    height: 46px; margin-bottom: var(--gap); border-radius: var(--radius);
    background-color: var(--surface);
    background-image: linear-gradient(90deg, transparent, var(--tint), transparent);
    background-size: 220% 100%; background-repeat: no-repeat;
    animation: sweep 1.3s ease-in-out infinite;
  }
  @keyframes sweep { from { background-position: -110% 0 } to { background-position: 210% 0 } }
  @media (prefers-reduced-motion: reduce) { .skeleton { animation: none; opacity: .5 } }

  /* ── классическое оформление ────────────────────────────────────── */
  /* Прежний плоский вид, без градиента: акцент — цвет кнопок Telegram,
     углы мягче, поверхности ровные. Кому-то спокойнее, и отбирать это
     ради красоты неправильно — панель открывают по десять раз в день. */
  body.classic {
    --brand-1: var(--tg-theme-button-color, #2481cc);
    --brand: var(--tg-theme-button-color, #2481cc);
    --radius: 10px;
    --radius-sm: 8px;
    --line: transparent;
    --tint: var(--surface);
  }
  body.classic h1 {
    background: none;
    -webkit-text-fill-color: initial;
    color: var(--tg-theme-text-color, #111);
  }
  body.classic .tabs { background: none; padding: 0; gap: 8px; }
  /* :not(.active) обязателен: правило с body.classic специфичнее, чем
     .tab.active, и без исключения гасило подсветку выбранной вкладки */
  body.classic .tab:not(.active) { background: var(--surface); }
  body.classic .tab.active { color: var(--tg-theme-button-text-color, #fff); }
  body.classic .card.hero { background: var(--surface); color: inherit; }
  body.classic .card.hero .label { font-size: 14px; font-weight: 400; }
  body.classic .card.hero .value { font-size: 19px; font-weight: 600; }
  body.classic .badge { background: #d33; }
  /* В «Классике» --line прозрачная, и обводка чипа исчезает вместе с ней
     — поверхность вместо неё */
  body.classic .restamp { background: var(--surface); }
  body.classic .pull { background: var(--surface); }
  body.classic .strip .dot { background: #d33; }
  body.classic .issue .key { color: var(--tg-theme-link-color, #2481cc); }
  body.classic button.danger { background: #d33; }
  body.classic .s1 { fill: #2a78d6; }
  body.classic .s2 { fill: #eb6834; }
  body.classic .legend .k1 { background: #2a78d6; }
  body.classic .legend .k2 { background: #eb6834; }
  body.classic.dark .s1 { fill: #3987e5; }
  body.classic.dark .s2 { fill: #d95926; }
  body.classic.dark .legend .k1 { background: #3987e5; }
  body.classic.dark .legend .k2 { background: #d95926; }

  /* ── график ─────────────────────────────────────────────────────── */
  /* Ряды взяты из фирменной пары, но проверены как данные, а не как
     украшение: фиолетовый и оранжевый различимы при дальтонизме (они
     расходятся и по светлоте) и держат контраст с фоном. Для тёмной темы
     значения свои, а не осветлённые те же. */
  .s1 { fill: #7c3aed; }
  .s2 { fill: #ea6a17; }
  body.dark .s1 { fill: #a78bfa; }
  body.dark .s2 { fill: #fb923c; }
  @media (prefers-color-scheme: dark) {
    body:not(.light) .s1 { fill: #a78bfa; }
    body:not(.light) .s2 { fill: #fb923c; }
  }
  /* Текущий день ещё не кончился — приглушаем, чтобы неполный столбик
     не читался как спад */
  .partial { opacity: .5; }
  .chart { display: block; width: 100%; height: auto; }
  .chart .axis { font-size: 9px; }
  .baseline { stroke: currentColor; opacity: .18; stroke-width: 1; }
  .legend { display: flex; flex-wrap: wrap; gap: 14px; font-size: 12px; margin-bottom: 8px; }
  .legend span { display: flex; align-items: center; gap: 6px; }
  .legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }
  .legend .k1 { background: #7c3aed; }
  .legend .k2 { background: #ea6a17; }
  body.dark .legend .k1 { background: #a78bfa; }
  body.dark .legend .k2 { background: #fb923c; }
  @media (prefers-color-scheme: dark) {
    body:not(.light) .legend .k1 { background: #a78bfa; }
    body:not(.light) .legend .k2 { background: #fb923c; }
  }

  /* ══ ТЕМА «ЛИНЕЙКА» ═══════════════════════════════════════════════════
     Третье оформление рядом с «Градиентом» и «Классикой». В отличие от
     них, эта тема НЕ идёт за цветами Telegram: интерфейс из тёмного камня
     и золота работает только целиком, а наполовину светлый выглядит
     поломанным. Поэтому все цвета переопределены жёстко.

     Чужих картинок здесь нет ни одной. Иконки и рамки из клиента игры —
     собственность правообладателя, и то, что их много раз перерисовали,
     общими их не делает. Стиль не защищён, конкретные файлы защищены,
     поэтому то же ощущение собрано на градиентах, тенях и
     псевдоэлементах. Заодно это ничего не весит: картинок нет вовсе, ни
     своих, ни чужих. (С чужого адреса их бы и не пустил CSP — там
     default-src 'none' и img-src только 'self' и data:.)

     Читаемость проверяется теми же требованиями, что у остальных тем:
     основной текст на фоне даёт контраст выше 7:1, ряды графика
     расходятся и по тону, и по светлоте. */
  body.lineage {
    /* Золото и старая бронза. Второй цвет темнее первого больше чем
       вдвое — на этом держится и градиент, и различимость рядов графика */
    --brand-1: #d9b45a;
    --brand-2: #8a5a1e;
    --brand: linear-gradient(135deg, #e8cd85, #a8791f 55%, #7a4f18);

    /* Камень: фон страницы, плита блока, утопленная ниша */
    --stone-0: #12100c;
    --stone-1: #1d1913;
    --stone-2: #262019;
    --surface: var(--stone-1);
    --sunken: var(--stone-0);

    /* Волосяная линия — потускневшая позолота, а не серый */
    --line: rgba(217, 180, 90, .22);
    --tint: rgba(217, 180, 90, .10);

    /* Пергамент для текста: чистый белый на тёмном тёплом фоне режет
       глаза и выглядит чужим */
    --ink: #ece0c4;
    --ink-dim: #b8a888;
    --blood: #a33025;

    --radius: 6px;
    --radius-sm: 4px;

    background:
      radial-gradient(120% 80% at 50% 0%, #241d15 0%, var(--stone-0) 70%),
      var(--stone-0);
    color: var(--ink);
    /* Засечки — только там, где они уместны: в теле заявки готика
       читается плохо, а в заголовке и в цифрах держит характер */
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  }

  /* Тёмная и светлая темы Telegram на эту тему не влияют: она сама тёмная */
  body.lineage.light, body.lineage.dark { color: var(--ink); }

  body.lineage h1 {
    font-family: Georgia, "Times New Roman", serif;
    font-weight: 700; letter-spacing: .01em;
    background: linear-gradient(180deg, #f3e0a8, #c79b3c 60%, #8a5a1e);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent;
    color: #d9b45a;
    text-shadow: 0 1px 0 rgba(0, 0, 0, .5);
  }
  body.lineage .who { color: var(--ink-dim); opacity: 1; }

  /* ── плита ──────────────────────────────────────────────────────────
     Двойная обводка: тёмная снаружи, золотая изнутри — так выглядит
     металлическая накладка на камне. Одной линией этого не собрать. */
  body.lineage .card,
  body.lineage .issue,
  body.lineage .wline,
  body.lineage .teamrow,
  body.lineage .office,
  body.lineage .topic,
  body.lineage .person,
  body.lineage .wblock,
  body.lineage .digest,
  body.lineage .stat {
    background: linear-gradient(180deg, var(--stone-2), var(--stone-1));
    border: 1px solid rgba(0, 0, 0, .55);
    box-shadow:
      inset 0 0 0 1px var(--line),
      inset 0 1px 0 rgba(255, 255, 255, .05),
      0 1px 2px rgba(0, 0, 0, .5);
  }

  body.lineage .card .label,
  body.lineage .wline .name,
  body.lineage .teamrow .name { color: var(--ink); }
  body.lineage .card .value,
  body.lineage .wline .value,
  body.lineage .stat .value,
  body.lineage .big {
    font-family: Georgia, "Times New Roman", serif;
    color: #e9cf90;
    text-shadow: 0 1px 0 rgba(0, 0, 0, .6);
  }

  /* Своя очередь — единственная строка про тебя лично. Здесь она
     выглядит как подсвеченный пункт меню: золотая рамка и тёплое
     свечение изнутри, а не заливка целиком. */
  body.lineage .card.hero {
    background:
      linear-gradient(180deg, rgba(217, 180, 90, .16), rgba(217, 180, 90, .05)),
      linear-gradient(180deg, var(--stone-2), var(--stone-1));
    border-color: rgba(0, 0, 0, .6);
    box-shadow:
      inset 0 0 0 1px rgba(217, 180, 90, .55),
      inset 0 0 18px rgba(217, 180, 90, .12),
      0 1px 3px rgba(0, 0, 0, .6);
    color: var(--ink);
  }
  body.lineage .card.hero .label { color: #f0dcae; }
  body.lineage .card.hero .value { color: #f7e6b8; }

  /* Уголки-накладки. Только на строке-герое и на раскрытом разделе:
     если посадить их на каждую плиту, экран превратится в ковёр. */
  body.lineage .card.hero { position: relative; }
  body.lineage .card.hero::before,
  body.lineage .card.hero::after {
    content: ""; position: absolute; width: 9px; height: 9px;
    border: 1px solid rgba(217, 180, 90, .8); pointer-events: none;
  }
  body.lineage .card.hero::before {
    top: 3px; left: 3px; border-right: none; border-bottom: none;
  }
  body.lineage .card.hero::after {
    bottom: 3px; right: 3px; border-left: none; border-top: none;
  }

  /* ── вкладки как каменное меню ──────────────────────────────────── */
  body.lineage .tabs {
    background: linear-gradient(180deg, #0d0b08, #171410);
    border: 1px solid rgba(0, 0, 0, .6);
    box-shadow: inset 0 0 0 1px var(--line);
  }
  body.lineage .tab { color: var(--ink-dim); }
  body.lineage .tab.active {
    background: linear-gradient(180deg, #b98f30, #7d5417);
    color: #1a1409; font-weight: 700;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), 0 1px 2px rgba(0, 0, 0, .6);
  }
  body.lineage .subtab {
    background: linear-gradient(180deg, var(--stone-2), var(--stone-1));
    border: 1px solid rgba(0, 0, 0, .5);
    box-shadow: inset 0 0 0 1px var(--line);
    color: var(--ink-dim);
  }
  body.lineage .subtab.active {
    background: linear-gradient(180deg, #b98f30, #7d5417);
    color: #1a1409; font-weight: 700;
  }

  /* ── заголовки разделов ─────────────────────────────────────────── */
  body.lineage summary {
    font-family: Georgia, "Times New Roman", serif;
    color: #e2c47c; opacity: 1; letter-spacing: .01em;
  }
  body.lineage summary::marker { color: #b98f30; }
  body.lineage body > details[open] > summary,
  body.lineage > details[open] > summary,
  body.lineage .navgroup > details[open] > summary {
    background: linear-gradient(180deg, #1b1710, #12100c);
    box-shadow: 0 1px 0 rgba(217, 180, 90, .35);
  }
  body.lineage .navgroup > summary.group::after { color: #c9a24f; }
  body.lineage .group {
    color: #c9a24f; opacity: 1; font-family: Georgia, "Times New Roman", serif;
    letter-spacing: .12em;
  }
  body.lineage .kind { color: #c9a24f; opacity: 1; letter-spacing: .1em; }
  body.lineage .caption, body.lineage .meta, body.lineage .note {
    color: var(--ink-dim); opacity: 1;
  }
  body.lineage .empty { color: var(--ink-dim); opacity: 1; }
  body.lineage .prose, body.lineage .summary { color: var(--ink); }

  /* ── тревога: красный камень, а не яркая точка ──────────────────── */
  body.lineage .strip {
    background: linear-gradient(180deg, rgba(163, 48, 37, .22), rgba(163, 48, 37, .08));
    border-color: rgba(0, 0, 0, .6);
    box-shadow: inset 0 0 0 1px rgba(196, 74, 60, .45);
    color: #f0c9c2;
  }
  body.lineage .strip .dot {
    background: radial-gradient(circle at 35% 30%, #ff8a72, var(--blood));
    box-shadow: 0 0 6px rgba(196, 74, 60, .7);
  }
  body.lineage .badge {
    background: linear-gradient(180deg, #c4413a, #7d1f18);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25);
  }
  body.lineage .error {
    background: rgba(163, 48, 37, .14);
    border: 1px solid rgba(196, 74, 60, .45);
    color: #f0c9c2;
  }

  /* ── кнопки: металлическая пластина ─────────────────────────────── */
  body.lineage button {
    background: linear-gradient(180deg, #b98f30, #7d5417);
    color: #1a1409; font-weight: 700;
    border: 1px solid rgba(0, 0, 0, .6);
    border-radius: var(--radius-sm);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), 0 1px 2px rgba(0, 0, 0, .6);
  }
  body.lineage button:active { box-shadow: inset 0 1px 3px rgba(0, 0, 0, .5); }
  body.lineage button.ghost {
    background: linear-gradient(180deg, var(--stone-2), var(--stone-1));
    color: #e2c47c; font-weight: 600;
    box-shadow: inset 0 0 0 1px var(--line);
  }
  body.lineage button.danger {
    background: linear-gradient(180deg, #c4413a, #7d1f18); color: #ffe8e4;
  }
  body.lineage button:disabled { opacity: .45; }

  body.lineage input, body.lineage textarea {
    background: var(--stone-0); color: var(--ink);
    border: 1px solid rgba(0, 0, 0, .6);
    box-shadow: inset 0 0 0 1px var(--line), inset 0 2px 4px rgba(0, 0, 0, .45);
    border-radius: var(--radius-sm);
  }
  body.lineage input::placeholder { color: #7d7159; }

  /* ── мелочи ─────────────────────────────────────────────────────── */
  body.lineage .chipmark, body.lineage .tag {
    background: rgba(217, 180, 90, .12);
    border: 1px solid rgba(217, 180, 90, .3);
    color: #dcc287;
  }
  body.lineage .issue .key { color: #e2c47c; }
  body.lineage .chev { color: #b98f30; opacity: .8; }
  body.lineage .face { border: 1px solid rgba(217, 180, 90, .45); background: var(--stone-2); }
  body.lineage .face-none { color: #c9a24f; }
  body.lineage .who-line { border-top-color: rgba(217, 180, 90, .16); }
  body.lineage .who-floor { color: #c9a24f; opacity: 1; }
  body.lineage .stamp { color: var(--ink-dim); opacity: 1; }
  body.lineage .delta { color: var(--ink-dim); opacity: 1; }
  body.lineage .updated { color: #7d7159; }
  /* Раздельно фон и блик: коротким background блик затирался бы вместе
     с цветом, и заглушка стояла бы неподвижной плитой */
  body.lineage .skeleton {
    background-color: var(--stone-1);
    background-image: linear-gradient(90deg, transparent, rgba(217, 180, 90, .12), transparent);
  }
  body.lineage .restamp {
    background: linear-gradient(180deg, var(--stone-2), var(--stone-1));
    color: #e2c47c; box-shadow: inset 0 0 0 1px var(--line);
  }
  body.lineage .pull {
    background: linear-gradient(180deg, var(--stone-2), var(--stone-1));
    border-color: rgba(0, 0, 0, .6); color: #e2c47c;
    box-shadow: inset 0 0 0 1px var(--line);
  }
  body.lineage .pull.ready {
    background: linear-gradient(180deg, #b98f30, #7d5417); color: #1a1409;
  }
  body.lineage .expand, body.lineage .stats { border-top-color: var(--line); }
  /* Оторванная плита не должна терять свою золотую обводку: короткий
     box-shadow затирает и её тоже, поэтому здесь оба слоя разом */
  body.lineage .card.lifted {
    box-shadow:
      inset 0 0 0 1px rgba(217, 180, 90, .55),
      0 8px 22px rgba(0, 0, 0, .65);
    border-color: rgba(0, 0, 0, .7);
  }

  /* Признаки зрелости и выводы обзоров: смысл несёт эмодзи, цвет —
     только подпорка, поэтому тут достаточно попасть в палитру */
  body.lineage .ok { color: #8fbf6a; }
  body.lineage .warn { color: #d9b45a; }
  body.lineage .risk, body.lineage .danger { color: #d9705f; }
  body.lineage .fix, body.lineage .todo { color: #e2c47c; }
  body.lineage .agenda .todo { color: #e2c47c; }
  body.lineage .verdict {
    background: rgba(217, 180, 90, .08);
    border-left: 2px solid #b98f30;
  }
  body.lineage .report { background: var(--stone-0); color: var(--ink); }

  /* ── график ─────────────────────────────────────────────────────
     Золото и бирюза: расходятся и по тону, и по светлоте, поэтому
     различимы при дальтонизме — то же требование, что к другим темам */
  body.lineage .s1 { fill: #d9b45a; }
  body.lineage .s2 { fill: #4e9a94; }
  body.lineage .legend .k1 { background: #d9b45a; }
  body.lineage .legend .k2 { background: #4e9a94; }
  body.lineage .axis, body.lineage .baseline { stroke: rgba(217, 180, 90, .25); }
  body.lineage .ts { fill: var(--ink-dim); }
