/* gamelog — дизайн-система.
   Первый блок — токены и компоненты один в один из макета
   «gamelog — дизайн-система.html»: цвета, типографика, отступы, все
   компоненты. Менять оформление только здесь; в шаблонах — только классы.
   Второй блок, GAMELOG, добавляет то, чего в статичном макете не было. */

  /* ============ TOKENS ============ */
  :root{
    color-scheme: dark;

    /* — surfaces — */
    --bg:            #14161b;
    --bg-elevated:   #191c22;
    --surface:       #1e2128;
    --surface-hover: #262a32;
    --surface-sunken:#101216;

    /* — borders — */
    --border:        #2b2f38;
    --border-subtle: #21242b;
    --border-strong: #3a3f4b;

    /* — text — */
    --text-primary:   #e7e9ed;
    --text-secondary: #9aa0ab;  /* level 2 */
    --text-tertiary:  #6a7080;

    /* — accent (UI / interactive, not a status) — */
    --accent:      #4f9b93;
    --accent-fg:   #8fd0c8;
    --accent-soft: rgba(79,155,147,.14);
    --accent-border: rgba(79,155,147,.4);

    /* — status colors (5) — */
    --status-completed:      #5f9e6a;
    --status-completed-fg:   #93c99c;
    --status-completed-bg:   rgba(95,158,106,.14);
    --status-completed-bd:   rgba(95,158,106,.38);

    --status-playing:        #4f8fd0;
    --status-playing-fg:     #8fbcec;
    --status-playing-bg:     rgba(79,143,208,.14);
    --status-playing-bd:     rgba(79,143,208,.38);

    --status-paused:        #c9974f;
    --status-paused-fg:     #e6bb7d;
    --status-paused-bg:     rgba(201,151,79,.14);
    --status-paused-bd:     rgba(201,151,79,.38);

    --status-planned:        #8b7fc7;
    --status-planned-fg:     #b3aae0;
    --status-planned-bg:     rgba(139,127,199,.14);
    --status-planned-bd:     rgba(139,127,199,.38);

    --status-dropped:        #c0645a;
    --status-dropped-fg:     #e2988f;
    --status-dropped-bg:     rgba(192,100,90,.14);
    --status-dropped-bd:     rgba(192,100,90,.38);

    --status-100:            #b9c0cb;
    --status-100-fg:         #e6e9ee;
    --status-100-bg:         rgba(185,192,203,.14);
    --status-100-bd:         rgba(185,192,203,.4);

    /* — трофейные тиры личной оценки (кубки: бронза/серебро/золото/платина) — */
    --tier-bronze:   #b3773f;
    --tier-silver:   #b8c0ca;
    --tier-gold:     #d9ac3f;
    --tier-platinum: #d7ecf2;

    /* — cover placeholder family (art, not semantic) — */
    --cover-1: #384a5c; --cover-2: #4a3f57; --cover-3: #4f4636;
    --cover-4: #2f4a48; --cover-5: #55403f; --cover-6: #3d4a3a;
    --cover-7: #443a5c; --cover-8: #57492f;

    /* — type — */
    --font-ui:   "Golos Text", "Segoe UI", system-ui, sans-serif;
    --font-mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", Consolas, monospace;

    --text-2xs: 0.6875rem;  /* 11 */
    --text-xs:  0.75rem;    /* 12 */
    --text-sm:  0.8125rem;  /* 13 */
    --text-base:0.875rem;   /* 14 */
    --text-md:  1rem;       /* 16 */
    --text-lg:  1.25rem;    /* 20 */
    --text-xl:  1.625rem;   /* 26 */
    --text-2xl: 2.125rem;   /* 34 */

    /* — spacing — */
    --space-1: 0.25rem; --space-2: 0.5rem;  --space-3: 0.75rem;
    --space-4: 1rem;    --space-5: 1.25rem; --space-6: 1.5rem;
    --space-8: 2rem;    --space-10: 2.5rem;

    /* — radii — */
    --radius-xs: 0.1875rem;
    --radius-sm: 0.375rem;
    --radius-md: 0.5rem;
    --radius-lg: 0.75rem;
    --radius-full: 999px;

    /* — shadow — */
    --shadow-sm: 0 1px 2px rgba(0,0,0,.35);
    --shadow-md: 0 6px 16px -4px rgba(0,0,0,.5);
    --shadow-lg: 0 16px 36px -10px rgba(0,0,0,.55);

    --topbar-h: 56px;
    --tabbar-h: 46px;
  }

  *,*::before,*::after{ box-sizing:border-box; }
  html{ -webkit-text-size-adjust:100%; }
  body{
    background: var(--bg);
    color: var(--text-primary);
    font-family: var(--font-ui);
    font-size: var(--text-base);
    line-height: 1.45;
    overflow-x: hidden;
  }
  h1,h2,h3,h4{ margin:0; font-weight:700; text-wrap:balance; }
  p{ margin:0; }
  ul{ margin:0; padding:0; list-style:none; }
  button{ font-family:inherit; }
  a{ color:inherit; }
  img,svg{ display:block; }
  ::selection{ background: var(--accent-soft); color:var(--text-primary); }

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

  .tabular{ font-variant-numeric: tabular-nums; font-feature-settings:"tnum" 1; }
  .mono{ font-family: var(--font-mono); }

  /* ============ SHELL LAYOUT ============ */
  .shell{ display:flex; flex-direction:column; min-height:100vh; }
  .main{ display:flex; flex-direction:column; min-width:0; }

  /* — Brand — */
  .brand{
    display:flex;
    align-items:center;
    gap: 5px;
    font-family: var(--font-mono);
    font-weight:600;
    font-size: var(--text-md);
    letter-spacing:-0.02em;
    flex:none;
  }
  .brand-mark{ color: var(--accent); }
  .brand-name{ color: var(--text-primary); }
  .brand small{
    font-family: var(--font-ui);
    font-weight:500;
    font-size: var(--text-2xs);
    color: var(--text-tertiary);
    margin-left:2px;
  }
  /* Слово у названия вместо «beta»: достижения → платина → игры. Все три
     лежат в одной ячейке сетки — ширина по самому длинному, шапка не
     дёргается при смене. Без анимаций (motion.css, п. 7) видно первое. */
  .brand-words{ display:inline-grid; }
  .brand-words > span{ grid-area:1 / 1; }
  .brand-words > span + span{ visibility:hidden; }

  /* — Top bar (profile row) — */
  .topbar{
    height: var(--topbar-h);
    position: sticky; top:0; z-index:6;
    background: rgba(20,22,27,.9);
    backdrop-filter: blur(6px);
    border-bottom:1px solid var(--border-subtle);
    display:flex;
    align-items:center;
    gap: var(--space-5);
    padding: 0 var(--space-6);
  }

  /* — Tab bar (top navigation, replaces the old sidebar) — */
  .tabbar{
    position: sticky; top: var(--topbar-h); z-index:5;
    background: var(--bg-elevated);
    border-bottom:1px solid var(--border-subtle);
    display:flex;
    align-items:stretch;
    gap: var(--space-1);
    padding: 0 var(--space-6);
    overflow-x:auto;
    scrollbar-width:none;
  }
  .tabbar::-webkit-scrollbar{ display:none; }
  .nav-item{
    display:flex;
    align-items:center;
    gap: var(--space-2);
    padding: 0 var(--space-3);
    height: var(--tabbar-h);
    color: var(--text-secondary);
    font-size: var(--text-sm);
    font-weight:500;
    border:none;
    border-bottom:2px solid transparent;
    background:none;
    white-space:nowrap;
    cursor:pointer;
    transition: background-color .12s ease, color .12s ease, border-color .12s ease;
  }
  .nav-item svg{ width:16px; height:16px; flex:none; stroke: currentColor; }
  .nav-item:hover{ background: var(--surface-hover); color: var(--text-primary); }
  .nav-item[aria-current="page"]{
    color: var(--accent-fg);
    border-bottom-color: var(--accent);
  }
  .nav-item[aria-current="page"] svg{ stroke: var(--accent-fg); }

  .search{
    position:relative;
    flex:1;
    max-width:420px;
  }
  .search input{
    width:100%;
    background: var(--surface);
    border:1px solid var(--border);
    color: var(--text-primary);
    font-family:inherit;
    font-size: var(--text-sm);
    padding: var(--space-2) var(--space-8) var(--space-2) var(--space-8);
    border-radius: var(--radius-sm);
    transition: border-color .12s ease, background-color .12s ease;
  }
  .search input::placeholder{ color: var(--text-tertiary); }
  .search input:focus{ outline:none; border-color: var(--accent-border); background: var(--surface-sunken); }
  .search svg{
    position:absolute; left:10px; top:50%; transform:translateY(-50%);
    width:15px; height:15px; stroke: var(--text-tertiary); pointer-events:none;
  }
  .search kbd{
    position:absolute; right:8px; top:50%; transform:translateY(-50%);
    font-family: var(--font-mono);
    font-size: var(--text-2xs);
    color: var(--text-tertiary);
    background: var(--bg-elevated);
    border:1px solid var(--border);
    border-radius: var(--radius-xs);
    padding: 1px 5px;
  }

  .topbar-spacer{ flex:1; }

  /* Поиск — по центру шапки. Авто-поля слева и справа забирают всё
     свободное место поровну, поэтому на экранах с поиском правый
     spacer больше не нужен и схлопывается. На «Входе»/«Регистрации»
     поиска нет — spacer работает как раньше и прижимает кнопки вправо. */
  .topbar .search{ flex: 0 1 420px; margin-inline: auto; }
  .topbar:has(.search) .topbar-spacer{ display:none; }

  .account{
    display:flex; align-items:center; gap: var(--space-2);
    padding: var(--space-1) var(--space-2) var(--space-1) var(--space-1);
    border-radius: var(--radius-full);
    border:1px solid transparent;
  }
  .account:hover{ background: var(--surface); border-color: var(--border); }
  .avatar{
    width:30px; height:30px; border-radius: var(--radius-sm);
    background: linear-gradient(155deg, var(--cover-7), var(--cover-1));
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size:11px;
    color: var(--text-primary);
    flex:none;
  }
  .account-name{ display:flex; flex-direction:column; line-height:1.2; }
  .account-name b{ font-size: var(--text-xs); font-weight:600; }
  .account-name span{ font-size: var(--text-2xs); color: var(--text-tertiary); }

  /* ============ CONTENT ============ */
  .content{ padding: var(--space-6) var(--space-6) var(--space-10); display:flex; flex-direction:column; gap: var(--space-8); max-width:1280px; width:100%; margin-inline:auto; }

  .page-head{ display:flex; align-items:baseline; gap: var(--space-3); flex-wrap:wrap; }
  .page-head h1{ font-size: var(--text-xl); }
  .page-head .count{ color: var(--text-tertiary); font-size: var(--text-sm); }

  /* — Profile header — */
  .profile-header{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-5);
    display:flex;
    align-items:center;
    flex-wrap:wrap;
    gap: var(--space-5);
  }
  .profile-id-group{ display:flex; align-items:flex-start; flex-wrap:wrap; gap: var(--space-4); flex:1; min-width:220px; }
  .profile-avatar-col{ display:flex; flex-direction:column; align-items:center; gap:9px; flex:none; }
  .profile-avatar{
    width:88px; height:88px; flex:none;
    border-radius: var(--radius-lg);
    background: linear-gradient(155deg, var(--cover-7), var(--cover-1));
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size: var(--text-xl);
    color: var(--text-primary);
  }
  /* Полоса статов: своя строка под аватаром и именем, прижата влево. */
  .avatar-stats{ flex-basis:100%; display:flex; flex-direction:row; flex-wrap:wrap; justify-content:flex-start; gap:10px 16px; }
  .avatar-stats li{ display:flex; align-items:baseline; gap:5px; font-size: var(--text-xs); color: var(--text-tertiary); white-space:nowrap; }
  .avatar-stats .emoji{ font-size: var(--text-sm); line-height:1; }
  .avatar-stats b{ font-family: var(--font-mono); color: var(--text-primary); font-weight:600; font-size: var(--text-sm); }
  .profile-id{ display:flex; flex-direction:column; gap:4px; min-width:0; padding-top:4px; }
  .profile-name{ font-size: var(--text-lg); }
  .profile-meta{ font-size: var(--text-xs); color: var(--text-tertiary); }
  .profile-meta .sep{ margin:0 6px; opacity:.5; }
  .sync-link{
    background:none; border:none; padding:0; cursor:pointer;
    font-family:inherit; font-size:inherit; color: var(--text-tertiary);
    text-decoration: underline dotted; text-underline-offset:2px;
  }
  .sync-link:hover{ color: var(--accent-fg); }

  .profile-level{ display:flex; align-items:center; gap: var(--space-3); flex:none; }
  .level-ring{ position:relative; width:60px; height:60px; flex:none; }
  .level-ring svg{ width:100%; height:100%; transform:rotate(-90deg); }
  .level-ring .ring-track{ fill:none; stroke: var(--border); stroke-width:5; }
  .level-ring .ring-fill{ fill:none; stroke: var(--accent); stroke-width:5; stroke-linecap:round; }
  .level-ring .level-num{
    position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size: var(--text-md);
    /* Внутри кольца помещается уровень до четырёх знаков — поджимаем трекинг. */
    letter-spacing:-0.04em;
    color: var(--text-primary);
  }
  .level-text{ display:flex; flex-direction:column; gap:2px; }
  .level-text .level-label{ font-size: var(--text-sm); font-weight:600; color: var(--accent-fg); }
  .level-text .level-sub{ font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--text-tertiary); }

  /* — Page layout: main column + right rail — */
  .page-layout{ display:grid; grid-template-columns: 1fr 300px; align-items:start; gap: var(--space-6); }
  .page-main{ display:flex; flex-direction:column; gap: var(--space-8); min-width:0; }
  /* Пустой маунт-поинт синка не должен есть gap колонки — иначе
     первый блок съезжает вниз относительно правого сайдбара. */
  #sync-progress:not(:has(*)){ display:none; }
  .page-aside{
    display:flex; flex-direction:column; gap: var(--space-5);
  }

  /* — Recently played rail — */
  .recent-card{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display:flex; flex-direction:column; gap: var(--space-3);
  }
  .recent-rows{ display:flex; flex-direction:column; gap:2px; }
  .recent-row{
    display:flex; align-items:center; gap: var(--space-3);
    padding: 5px; border-radius: var(--radius-sm);
  }
  .recent-row:hover{ background: var(--surface-hover); }
  .recent-cover{
    width:30px; aspect-ratio:3/4; flex:none; border-radius:3px;
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size:8.5px;
    color: rgba(255,255,255,.4);
  }
  .recent-info{ display:flex; flex-direction:column; gap:1px; min-width:0; }
  .recent-info b{
    font-size: var(--text-xs); font-weight:600; color: var(--text-primary);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .recent-info span{ font-size:10.5px; color: var(--text-tertiary); font-family: var(--font-mono); }

  /* — Friends rail — */
  .friends-card{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display:flex; flex-direction:column; gap: var(--space-3);
  }
  .friend-rows{ display:flex; flex-direction:column; gap:2px; }
  .friend-row{
    display:flex; align-items:center; gap: var(--space-3);
    padding: 5px; border-radius: var(--radius-sm);
  }
  .friend-row:hover{ background: var(--surface-hover); }
  .friend-row .friend-avatar{
    width:36px; height:36px; flex:none; border-radius: var(--radius-sm);
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size:10.5px;
    color: var(--text-primary);
  }
  .friend-row .friend-name{
    font-size: var(--text-xs); color: var(--text-secondary);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }

  section.block{ display:flex; flex-direction:column; gap: var(--space-4); }
  .block-head{ display:flex; align-items:center; justify-content:space-between; gap: var(--space-3); flex-wrap:wrap; }
  .block-head h2{ font-size: var(--text-md); }
  .block-head .hint{ font-size: var(--text-xs); color: var(--text-tertiary); }

  /* — Stat strip — */
  .stat-grid{
    display:grid;
    grid-template-columns: repeat(3, minmax(0,1fr));
    gap: var(--space-3);
  }
  .stat-card{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display:flex; flex-direction:column; gap: var(--space-1);
  }
  .stat-card .label{
    font-size: var(--text-2xs); text-transform:uppercase; letter-spacing:.07em;
    color: var(--text-tertiary);
  }
  .stat-card .value{
    font-family: var(--font-mono); font-weight:600; font-size: var(--text-xl);
    color: var(--text-primary);
  }
  .stat-card .sub{ font-size: var(--text-xs); color: var(--text-secondary); }
  .stat-card .sub em{ color: var(--status-completed-fg); font-style:normal; font-weight:600; }
  .stat-card .sub.warn em{ color: var(--status-dropped-fg); }

  /* — Status distribution chart — */
  .status-chart{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display:flex; flex-direction:column; gap: var(--space-3);
  }
  .status-chart-bar{
    display:flex;
    height:14px;
    border-radius: var(--radius-full);
    overflow:hidden;
    background: var(--surface-sunken);
    border:1px solid var(--border-subtle);
  }
  .status-chart-bar .seg{ height:100%; }
  .status-chart-bar .seg:not(:last-child){ border-right:1px solid var(--bg); }
  .status-chart-legend{ display:flex; flex-wrap:wrap; column-gap: var(--space-5); row-gap: var(--space-2); }
  .status-chart-legend li{ display:flex; align-items:center; gap:7px; font-size: var(--text-xs); color: var(--text-secondary); }
  .status-chart-legend .dot{ width:8px; height:8px; border-radius:50%; flex:none; }
  .status-chart-legend b{ font-family: var(--font-mono); color: var(--text-primary); font-weight:600; }

  /* — Status distribution pie/donut — тот же датасет, что и status-chart-bar,
       но по кругу: удобнее, когда статусов пять и в узкой колонке-сайдбаре. — */
  .status-donut-wrap{ display:flex; justify-content:center; padding: var(--space-1) 0 var(--space-2); }
  .status-donut{ position:relative; width:112px; height:112px; border-radius:50%; flex:none; }
  .status-donut::after{
    content:""; position:absolute; inset:24%; border-radius:50%;
    background: var(--surface);
    box-shadow: inset 0 0 0 1px var(--border-subtle);
  }

  /* — Оценки критиков (Metacritic / OpenCritic / IGN и т.п.) — */
  .critic-card{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display:flex; flex-direction:column; gap: var(--space-2);
  }
  .critic-list{ display:flex; flex-direction:column; }
  .critic-row{
    display:flex; align-items:center; justify-content:space-between; gap: var(--space-3);
    padding: var(--space-2) 3px;
  }
  .critic-row:not(:last-child){ border-bottom:1px solid var(--border-subtle); }
  .critic-source{ display:flex; align-items:center; gap: var(--space-3); min-width:0; }
  .critic-badge{
    width:30px; height:30px; flex:none; border-radius: var(--radius-sm);
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size:10px;
    color: var(--text-primary);
  }
  .critic-name{ font-size: var(--text-sm); color: var(--text-secondary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .critic-score{ font-family: var(--font-mono); font-weight:700; font-size: var(--text-md); flex:none; }
  .critic-score.is-high{ color: var(--status-completed-fg); }
  .critic-score.is-mid{ color: var(--status-paused-fg); }
  .critic-score.is-low{ color: var(--status-dropped-fg); }

  /* — Оценка сайта: средняя по оценкам пользователей Gamelog — */
  .site-score-label{ font-size: var(--text-sm); color: var(--text-secondary); }
  .site-score-sub{ font-size: var(--text-2xs); color: var(--text-tertiary); }
  .site-score-value{ font-family: var(--font-mono); font-weight:700; font-size: var(--text-lg); color: var(--accent-fg); flex:none; }
  .site-score-value .site-score-max{ font-size: var(--text-xs); font-weight:600; color: var(--text-tertiary); margin-left:2px; }

  /* — Сколько проходят игру (HowLongToBeat) — */
  .hltb-card{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display:flex; flex-direction:column; gap: var(--space-2);
  }
  .hltb-list{ display:flex; flex-direction:column; }
  .hltb-row{
    display:flex; align-items:center; justify-content:space-between; gap: var(--space-3);
    padding: var(--space-2) 3px;
  }
  .hltb-row:not(:last-child){ border-bottom:1px solid var(--border-subtle); }
  .hltb-label{ font-size: var(--text-sm); color: var(--text-secondary); }
  .hltb-value{ font-family: var(--font-mono); font-weight:600; font-size: var(--text-sm); color: var(--text-primary); flex:none; }

  /* — Status legend / filters — */
  .status-filters{ display:flex; flex-wrap:wrap; gap: var(--space-2); }

  /* — StatusBadge — */
  .status-badge{
    display:inline-flex; align-items:center; gap:6px;
    font-size: var(--text-2xs); font-weight:600;
    padding: 3px 9px 3px 7px;
    border-radius: var(--radius-full);
    border:1px solid transparent;
    white-space:nowrap;
    cursor:default;
    line-height:1.6;
  }
  .status-badge .dot{ width:6px; height:6px; border-radius:50%; flex:none; }
  button.status-badge{ cursor:pointer; background:none; font-family:inherit; transition:filter .12s ease, opacity .12s ease; }
  button.status-badge:hover{ filter:brightness(1.15); }
  button.status-badge:not(.is-active){ opacity:.55; }

  .status-badge.st-completed{ color:var(--status-completed-fg); background:var(--status-completed-bg); border-color:var(--status-completed-bd); }
  .status-badge.st-completed .dot{ background:var(--status-completed); }
  .status-badge.st-playing{ color:var(--status-playing-fg); background:var(--status-playing-bg); border-color:var(--status-playing-bd); }
  .status-badge.st-playing .dot{ background:var(--status-playing); }
  .status-badge.st-paused{ color:var(--status-paused-fg); background:var(--status-paused-bg); border-color:var(--status-paused-bd); }
  .status-badge.st-paused .dot{ background:var(--status-paused); }
  .status-badge.st-planned{ color:var(--status-planned-fg); background:var(--status-planned-bg); border-color:var(--status-planned-bd); }
  .status-badge.st-planned .dot{ background:var(--status-planned); }
  .status-badge.st-dropped{ color:var(--status-dropped-fg); background:var(--status-dropped-bg); border-color:var(--status-dropped-bd); }
  .status-badge.st-dropped .dot{ background:var(--status-dropped); }
  .status-badge.st-100{ color:var(--status-100-fg); background:var(--status-100-bg); border-color:var(--status-100-bd); }
  .status-badge.st-100 .dot{ background:var(--status-100); }

  /* — GameCard grid — */
  .card-grid{
    display:grid;
    grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
    gap: var(--space-4);
  }
  .game-card{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    overflow:hidden;
    display:flex; flex-direction:column;
    transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease;
  }
  .game-card:hover{ border-color: var(--border-strong); box-shadow: var(--shadow-md); transform: translateY(-2px); }
  .game-card[data-status="100"]{ border-color: var(--status-100-bd); box-shadow: 0 0 0 1px var(--status-100-bd) inset; }
  .game-card[data-status="100"]:hover{ border-color: var(--status-100); box-shadow: 0 0 0 1px var(--status-100) inset, var(--shadow-md); }
  .js-open-game{ cursor:pointer; }
  .game-card[hidden]{ display:none; }

  .cover{
    aspect-ratio: 3/4;
    position:relative;
    display:flex; align-items:center; justify-content:center;
    overflow:hidden;
    background-image:
      repeating-linear-gradient(135deg, rgba(255,255,255,.05) 0 2px, transparent 2px 14px);
  }
  .cover .mono-letters{
    font-family: var(--font-mono); font-weight:700;
    font-size: 2.4rem; letter-spacing:-0.03em;
    color: rgba(255,255,255,.16);
  }
  .cover .cover-badge{
    position:absolute; top:6px; left:6px;
    display:flex; align-items:center; gap:4px;
    background: rgba(10,11,14,.55);
    border:1px solid rgba(255,255,255,.08);
    border-radius: var(--radius-xs);
    padding: 2px 6px;
    font-size:10px; color: rgba(233,235,239,.85);
  }
  .cover .cover-badge svg{ width:10px; height:10px; stroke:currentColor; }

  .game-body{ padding: var(--space-3); display:flex; flex-direction:column; gap: var(--space-2); flex:1; }
  .game-title{
    font-size: var(--text-sm); font-weight:600; color: var(--text-primary);
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
    line-height:1.3; min-height:2.6em;
  }
  .game-meta-row{ display:flex; align-items:center; justify-content:space-between; gap: var(--space-2); }
  .playtime{ font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-secondary); }

  .progress{ display:flex; flex-direction:column; gap:4px; margin-top:auto; }
  .progress-track{ height:5px; background: var(--surface-sunken); border:1px solid var(--border-subtle); border-radius: var(--radius-full); overflow:hidden; }
  .progress-fill{ height:100%; background: var(--accent); border-radius: var(--radius-full); }
  .progress-label{ font-family: var(--font-mono); font-size:10.5px; color: var(--text-tertiary); display:flex; justify-content:space-between; }
  .progress-label .pct{ color: var(--text-secondary); }

  /* — GameRow list — */
  .row-list{ display:flex; flex-direction:column; border-top:1px solid var(--border-subtle); }
  .game-row{
    display:grid;
    grid-template-columns: 34px 1fr 96px 88px 150px;
    align-items:center;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-2);
    border-bottom:1px solid var(--border-subtle);
    transition: background-color .1s ease;
  }
  .game-row:hover{ background: var(--surface-hover); }
  .game-row[data-status="100"]{ background: var(--status-100-bg); box-shadow: inset 2px 0 0 var(--status-100); }
  .game-row[data-status="100"]:hover{ background: var(--status-100-bg); filter:brightness(1.15); }
  .game-row[hidden]{ display:none; }
  .row-cover{
    width:34px; aspect-ratio:3/4; border-radius:3px; overflow:hidden;
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size:10px; color: rgba(255,255,255,.35);
    flex:none;
  }
  .row-title{ display:flex; flex-direction:column; gap:1px; min-width:0; }
  .row-title b{ font-size: var(--text-sm); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .row-platform{ display:flex; align-items:center; gap:4px; font-size:10.5px; color: var(--text-tertiary); }
  .row-platform svg{ width:10px; height:10px; stroke:currentColor; }
  .row-playtime{ font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-secondary); text-align:right; }
  .row-progress{ display:flex; flex-direction:column; gap:3px; }
  .row-progress .progress-track{ height:4px; }
  .row-progress .progress-label{ font-size:10px; }

  /* — Achievements panel — */
  .ach-panel{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    overflow:hidden;
  }
  .ach-panel-head{
    display:flex; align-items:center; gap: var(--space-3);
    padding: var(--space-4);
    border-bottom:1px solid var(--border-subtle);
    background: var(--bg-elevated);
  }
  .ach-panel-head .cover-mini{
    width:44px; aspect-ratio:3/4; border-radius: var(--radius-xs); flex:none;
    background: var(--cover-4);
  }
  .ach-panel-head-text{ display:flex; flex-direction:column; gap:2px; flex:1; min-width:0; }
  .ach-panel-head-text b{ font-size: var(--text-md); }
  .ach-panel-head-text .note{ font-size: var(--text-xs); color: var(--status-playing-fg); }
  .ach-panel-head .progress{ width:160px; margin-top:0; }

  .ach-list{ display:flex; flex-direction:column; }
  .ach-row{
    display:flex; align-items:center; gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-bottom:1px solid var(--border-subtle);
  }
  .ach-row:last-child{ border-bottom:none; }
  .ach-row[hidden]{ display:none; }
  .ach-icon{
    width:64px; height:64px; flex:none; border-radius: var(--radius-sm);
    display:flex; align-items:center; justify-content:center;
    background: var(--surface-sunken); border:1px solid var(--border);
  }
  .ach-icon svg{ width:30px; height:30px; stroke: var(--accent-fg); fill:none; }
  .ach-row.is-locked .ach-icon{ filter:grayscale(1); opacity:.4; }
  .ach-row.is-locked .ach-icon svg{ stroke: var(--text-tertiary); }
  .ach-text{ flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
  .ach-text b{ font-size: var(--text-sm); font-weight:600; }
  .ach-row.is-locked .ach-text b{ color: var(--text-secondary); font-weight:500; }
  .ach-text p{ font-size: var(--text-xs); color: var(--text-secondary); }
  .ach-row.is-locked .ach-text p{ color: var(--text-tertiary); }
  .ach-meta{ flex:none; text-align:right; display:flex; flex-direction:column; gap:3px; min-width:118px; }
  .ach-meta .date{ font-size: var(--text-xs); color: var(--text-secondary); }
  .ach-row.is-locked .ach-meta .date{ color: var(--text-tertiary); font-style:normal; }
  .ach-meta .rarity{ font-family: var(--font-mono); font-size:10.5px; color: var(--text-tertiary); }

  /* — EmptyState — */
  .empty-state{
    display:flex; flex-direction:column; align-items:center; text-align:center;
    gap: var(--space-3);
    padding: var(--space-10) var(--space-6);
    border:1px dashed var(--border);
    border-radius: var(--radius-lg);
    color: var(--text-secondary);
  }
  .empty-state .icon-wrap{
    width:44px; height:44px; border-radius:50%;
    background: var(--surface); border:1px solid var(--border);
    display:flex; align-items:center; justify-content:center;
  }
  .empty-state .icon-wrap svg{ width:19px; height:19px; stroke: var(--text-tertiary); }
  .empty-state h3{ font-size: var(--text-sm); color: var(--text-primary); font-weight:600; }
  .empty-state p{ font-size: var(--text-xs); max-width:34ch; }

  /* — SkeletonCard — */
  @keyframes shimmer{ 0%{ opacity:.55 } 50%{ opacity:1 } 100%{ opacity:.55 } }
  .skel-cover, .skel-line{ background: var(--surface-hover); border-radius: var(--radius-xs); animation: shimmer 1.6s ease-in-out infinite; }
  .skeleton-card{ background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md); overflow:hidden; display:flex; flex-direction:column; }
  .skel-cover{ aspect-ratio:3/4; border-radius:0; }
  .skel-body{ padding: var(--space-3); display:flex; flex-direction:column; gap: var(--space-2); }
  .skel-line{ height:9px; }
  .skel-line.w-80{ width:80%; }
  .skel-line.w-50{ width:50%; }
  .skel-line.w-100{ width:100%; height:5px; margin-top:6px; }
  @media (prefers-reduced-motion: reduce){
    .skel-cover, .skel-line{ animation:none; opacity:.7; }
  }

  /* ============ TOKEN REFERENCE (appendix) ============ */
  .tokens-appendix{
    border-top:1px solid var(--border);
    padding-top: var(--space-8);
    display:flex; flex-direction:column; gap: var(--space-8);
  }
  .tokens-appendix > .appendix-head{ display:flex; flex-direction:column; gap:4px; }
  .appendix-head h2{ font-size: var(--text-lg); }
  .appendix-head p{ font-size: var(--text-sm); color: var(--text-secondary); max-width:70ch; }

  .swatch-grid{ display:grid; grid-template-columns: repeat(auto-fill, minmax(150px,1fr)); gap: var(--space-3); }
  .swatch{ border:1px solid var(--border); border-radius: var(--radius-md); overflow:hidden; background: var(--surface); }
  .swatch-fill{ height:52px; }
  .swatch-meta{ padding: var(--space-2) var(--space-3); display:flex; flex-direction:column; gap:1px; }
  .swatch-meta b{ font-size: var(--text-xs); }
  .swatch-meta span{ font-family: var(--font-mono); font-size:10.5px; color: var(--text-tertiary); }

  .type-specimen{ display:flex; flex-direction:column; gap: var(--space-3); }
  .type-row{ display:flex; align-items:baseline; gap: var(--space-4); padding: var(--space-2) 0; border-bottom:1px solid var(--border-subtle); }
  .type-row .tag{ width:150px; flex:none; font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-tertiary); }
  .type-row .sample{ color: var(--text-primary); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

  .misc-specimen-grid{ display:grid; grid-template-columns: repeat(auto-fit, minmax(220px,1fr)); gap: var(--space-6); }
  .radius-row, .shadow-row{ display:flex; align-items:center; gap: var(--space-3); padding: var(--space-2) 0; }
  .radius-box{ width:44px; height:44px; background: var(--surface); border:1px solid var(--border-strong); flex:none; }
  .shadow-box{ width:60px; height:44px; background: var(--surface); border:1px solid var(--border); flex:none; border-radius: var(--radius-sm); }
  .spec-label{ font-size: var(--text-xs); color: var(--text-secondary); }
  .spec-label .mono{ display:block; color: var(--text-tertiary); font-size:10.5px; }

  /* ============ GAME PAGE ============ */
  #view-library{ display:flex; flex-direction:column; gap: var(--space-8); }
  #view-game{ display:flex; flex-direction:column; gap: var(--space-6); }

  .back-link{
    display:inline-flex; align-items:center; gap:6px; align-self:flex-start;
    background:none; border:none; cursor:pointer;
    font-family: inherit; font-size: var(--text-sm); font-weight:600;
    color: var(--text-secondary); padding: var(--space-1) 0;
  }
  .back-link:hover{ color: var(--accent-fg); }
  .back-link svg{ width:15px; height:15px; stroke:currentColor; }

  /* — Game header — */
  .game-header{
    position:relative;
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: var(--space-6);
    display:flex;
    align-items:center;
    flex-wrap:wrap;
    gap: var(--space-6);
  }
  /* — Оценка сайта: приколота к верхнему правому углу шапки — */
  .game-header-score{
    position:absolute; top: var(--space-5); right: var(--space-6);
    display:flex; flex-direction:column; align-items:flex-end; gap:1px;
  }
  .game-header-cover{
    width:144px; aspect-ratio:3/4; flex:none;
    border-radius: var(--radius-md);
    position:relative; overflow:hidden;
    display:flex; align-items:center; justify-content:center;
    background-image: repeating-linear-gradient(135deg, rgba(255,255,255,.05) 0 2px, transparent 2px 14px);
  }
  .game-header-cover .mono-letters{
    font-family: var(--font-mono); font-weight:700; font-size:3.2rem; letter-spacing:-0.03em;
    color: rgba(255,255,255,.16);
  }

  /* — Обложка + личная оценка кубками под ней — */
  .game-header-cover-col{ display:flex; flex-direction:column; align-items:center; gap:10px; width:144px; flex:none; }
  .game-header-cover-col .game-header-cover{ width:100%; }

  /* Личная оценка 1–10: 5 кубков по 2 балла каждый (половина = нечётное
     значение). Цвет заливки — по тиру итоговой оценки: 1-3 бронза, 4-6
     серебро, 7-9 золото, 10 — платина, у неё поверх ряда бежит блик. */
  .cup-rating{ display:flex; flex-direction:column; align-items:center; gap:6px; }
  .cup-rating-icons{ position:relative; display:flex; gap:5px; }
  .cup-slot{ --cup-size:26px; position:relative; width:var(--cup-size); height:var(--cup-size); flex:none; }
  .cup-slot .cup-bg{ position:absolute; inset:0; width:100%; height:100%; stroke: var(--border-strong); fill:none; }
  .cup-slot .cup-fill-wrap{
    position:absolute; top:0; left:0; height:100%; width:0%;
    overflow:hidden; color: var(--text-tertiary);
    transition: width .15s ease;
  }
  .cup-slot .cup-fill-wrap svg{ position:absolute; top:0; left:0; width:var(--cup-size); height:var(--cup-size); fill:none; stroke: currentColor; }
  .cup-rating.tier-bronze .cup-fill-wrap{ color: var(--tier-bronze); }
  .cup-rating.tier-silver .cup-fill-wrap{ color: var(--tier-silver); }
  .cup-rating.tier-gold .cup-fill-wrap{ color: var(--tier-gold); }
  .cup-rating.tier-platinum .cup-fill-wrap{ color: var(--tier-platinum); }
  .cup-hit{ position:absolute; top:0; bottom:0; width:50%; background:none; border:none; padding:0; margin:0; cursor:pointer; }
  .cup-hit--left{ left:0; }
  .cup-hit--right{ right:0; }
  .cup-rating-label{ font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-secondary); }
  .cup-rating-label .tier-name{ color: var(--text-tertiary); }
  /* блик на платине — заведён на каждый кубок отдельно и обрезан маской
     по силуэту i-trophy, поэтому светится именно кубок, а не весь ряд. */
  .cup-rating.tier-platinum .cup-slot::after{
    content:"";
    position:absolute; inset:0;
    mask: url(#cup-trophy-mask); -webkit-mask: url(#cup-trophy-mask);
    mask-repeat:no-repeat; -webkit-mask-repeat:no-repeat;
    background: linear-gradient(100deg, transparent 42%, rgba(255,255,255,.85) 50%, transparent 58%);
    background-size:260% 100%;
    animation: cup-shine 2.4s ease-in-out infinite;
    pointer-events:none;
    mix-blend-mode: screen;
  }
  @keyframes cup-shine{
    0%{ background-position: 140% 0; }
    65%{ background-position: -40% 0; }
    100%{ background-position: -40% 0; }
  }
  @media (prefers-reduced-motion: reduce){
    .cup-rating.tier-platinum .cup-slot::after{ animation:none; }
  }

  /* — Статус игры под обложкой: та же пилюля-<select>, растянута по
       ширине обложки, без заливки — и со стрелкой раскрытия справа. — */
  .game-status-picker{ position:relative; width:100%; }
  .game-status-picker select.status-badge{
    width:100%; justify-content:center; text-align:center;
    background:none; border-color: var(--border);
    border-radius: var(--radius-sm);
    padding: 5px 24px;
  }
  .game-status-picker select.status-badge:hover{ background: var(--surface-hover); }
  .game-status-caret{
    position:absolute; right:9px; top:50%; transform:translateY(-50%);
    width:12px; height:12px; stroke: var(--text-tertiary);
    pointer-events:none;
  }
  /* Полупрозрачные строки в раскрытом списке — только у этого пикера. */
  .game-status-picker select.status-badge option{
    background: rgba(30,33,40,.72);
    color: var(--text-primary);
  }

  .game-header-info{ display:flex; flex-direction:column; gap:8px; flex:1; min-width:220px; align-self:flex-start; }
  .game-header-title-row{ display:flex; align-items:center; gap: var(--space-3); flex-wrap:wrap; }
  .game-header-info h1{ font-size: var(--text-xl); }
  .xp-pill{
    display:inline-flex; align-items:center;
    font-family: var(--font-mono); font-weight:700; font-size: var(--text-xs);
    color: var(--accent-fg); background: var(--accent-soft);
    border:1px solid var(--accent-border); border-radius: var(--radius-full);
    padding: 3px 10px; white-space:nowrap;
  }
  .game-header-meta{ display:flex; align-items:center; gap:6px; font-size: var(--text-xs); color: var(--text-tertiary); }
  .game-header-meta .sep{ opacity:.5; }
  .platform-tag{ display:inline-flex; align-items:center; gap:4px; }
  .platform-tag svg{ width:11px; height:11px; stroke:currentColor; }
  .game-header-row{ display:flex; align-items:center; gap: var(--space-4); flex-wrap:wrap; font-size: var(--text-xs); color: var(--text-secondary); }
  .game-header-row .stat-inline b{ font-family: var(--font-mono); color: var(--text-primary); font-weight:600; }

  .ach-ring-wrap{ display:flex; align-items:center; gap: var(--space-3); flex:none; }
  .ach-ring{ position:relative; width:72px; height:72px; flex:none; }
  .ach-ring svg{ width:100%; height:100%; transform:rotate(-90deg); }
  .ach-ring .ring-track{ fill:none; stroke: var(--border); stroke-width:6; }
  .ach-ring .ring-fill{ fill:none; stroke: var(--accent); stroke-width:6; stroke-linecap:round; }
  .ach-ring .ach-ring-pct{
    position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size: var(--text-sm);
    color: var(--text-primary);
  }
  .ach-ring-text{ font-size: var(--text-xs); color: var(--text-secondary); }
  .ach-ring-text b{ font-family: var(--font-mono); color: var(--text-primary); }

  /* — Personal note (inline edit) — */
  .note-card{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display:flex; flex-direction:column; gap: var(--space-2);
  }
  .note-head{ display:flex; align-items:center; gap:6px; font-size: var(--text-xs); font-weight:600; color: var(--text-tertiary); text-transform:uppercase; letter-spacing:.06em; }
  .note-head svg{ width:13px; height:13px; stroke:currentColor; }
  .note-body{
    font-size: var(--text-sm); color: var(--text-primary); line-height:1.55;
    border:1px solid transparent; border-radius: var(--radius-sm);
    padding: var(--space-2); margin: calc(var(--space-2) * -1);
    outline:none; cursor:text;
    transition: border-color .12s ease, background-color .12s ease;
  }
  .note-body:hover{ background: var(--surface-hover); }
  .note-body:focus{ border-color: var(--accent-border); background: var(--surface-sunken); }
  .note-body:empty::before{ content: attr(data-placeholder); color: var(--text-tertiary); }

  /* — Game tabs — */
  .game-tabs{ display:flex; gap: var(--space-1); border-bottom:1px solid var(--border-subtle); }
  .game-tab{
    background:none; border:none; border-bottom:2px solid transparent;
    padding: var(--space-2) var(--space-1); margin-right: var(--space-4);
    font-family:inherit; font-size: var(--text-sm); font-weight:600;
    color: var(--text-secondary); cursor:pointer;
  }
  .game-tab:hover{ color: var(--text-primary); }
  .game-tab[aria-selected="true"]{ color: var(--accent-fg); border-bottom-color: var(--accent); }
  .tab-panel{ display:flex; flex-direction:column; gap: var(--space-5); }

  /* — Achievements toolbar — */
  .ach-toolbar{ display:flex; align-items:center; justify-content:space-between; gap: var(--space-3); flex-wrap:wrap; }
  .filter-toggle{
    display:inline-flex; align-items:center; gap:7px;
    padding: 6px 12px 6px 9px;
    border-radius: var(--radius-full);
    border:1px solid var(--border);
    background: var(--surface);
    color: var(--text-secondary);
    font-family:inherit; font-size: var(--text-xs); font-weight:600;
    cursor:pointer;
  }
  .filter-toggle .box{ width:13px; height:13px; border-radius:3px; border:1px solid var(--border-strong); flex:none; display:flex; align-items:center; justify-content:center; }
  .filter-toggle .box svg{ width:9px; height:9px; stroke: var(--bg); opacity:0; }
  .filter-toggle[aria-pressed="true"]{ background: var(--accent-soft); border-color: var(--accent-border); color: var(--accent-fg); }
  .filter-toggle[aria-pressed="true"] .box{ background: var(--accent); border-color: var(--accent); }
  .filter-toggle[aria-pressed="true"] .box svg{ opacity:1; stroke: var(--bg-elevated); }
  .sort-select{
    background: var(--surface); border:1px solid var(--border); color: var(--text-primary);
    font-family:inherit; font-size: var(--text-xs); padding: 6px 10px;
    border-radius: var(--radius-sm);
  }

  .ach-hidden-block{ display:flex; flex-direction:column; gap: var(--space-3); padding-top: var(--space-2); border-top:1px solid var(--border-subtle); }
  .ach-hidden-block h3{ font-size: var(--text-sm); font-weight:600; }
  .ach-row.is-hidden-ach .ach-text b{ font-style:italic; }
  .ach-row .reveal-tag{ font-size:10px; color: var(--text-tertiary); font-weight:500; }

  /* — «Показать ещё» под усечённым списком достижений — */
  .ach-show-more{
    display:flex; align-items:center; justify-content:center; gap:6px;
    width:100%; background:none; border:none; cursor:pointer;
    padding: var(--space-3) var(--space-4);
    font-family:inherit; font-size: var(--text-sm); font-weight:600;
    color: var(--text-secondary);
  }
  .ach-show-more:hover{ background: var(--surface-hover); color: var(--text-primary); }
  .ach-show-more svg{ width:14px; height:14px; stroke:currentColor; transition: transform .15s ease; }
  .ach-show-more[aria-expanded="true"] svg{ transform: rotate(180deg); }

  /* — Friends-on-this-game list — */
  .friend-game-list{ display:flex; flex-direction:column; border-top:1px solid var(--border-subtle); }
  .friend-game-row{
    display:grid;
    grid-template-columns: 38px 130px 108px 72px 60px 1fr;
    align-items:center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-2);
    border-bottom:1px solid var(--border-subtle);
  }
  .friend-game-row:hover{ background: var(--surface-hover); }
  .friend-game-row .friend-avatar{ width:38px; height:38px; font-size:11px; border-radius: var(--radius-sm); display:flex; align-items:center; justify-content:center; font-family:var(--font-mono); font-weight:700; color:var(--text-primary); flex:none; }
  .friend-game-row .fg-name{ font-size: var(--text-sm); font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .friend-game-row .fg-playtime{ font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-secondary); }
  .friend-game-row .fg-pct{ font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-secondary); }
  .friend-game-row .fg-note{ font-size: var(--text-xs); color: var(--text-tertiary); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-style:italic; }

  /* ============ COLLECTIONS PAGE ============ */
  #view-collections{ display:flex; flex-direction:column; gap: var(--space-8); }
  .stat-grid-5{ grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }

  .shelf{ display:flex; flex-direction:column; gap: var(--space-4); }
  .shelf-row{ display:flex; gap: var(--space-4); overflow-x:auto; padding-bottom:4px; }
  .shelf-row .game-card{ width:172px; flex:none; }

  .card-note{
    display:flex; align-items:center; gap:5px;
    font-size:10.5px; color: var(--text-tertiary); margin-top:2px;
  }
  .card-missing{ display:flex; flex-direction:column; gap:3px; margin-top:2px; }
  .card-missing .missing-label{ font-size:10px; text-transform:uppercase; letter-spacing:.05em; color: var(--text-tertiary); }
  .card-missing ul{ display:flex; flex-direction:column; gap:2px; }
  .card-missing li{
    font-size:10.5px; color: var(--text-secondary);
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
    padding-left:11px; position:relative;
  }
  .card-missing li::before{ content:"·"; position:absolute; left:2px; color: var(--text-tertiary); }

  /* — Roulette — */
  .roulette-card{
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md);
    padding: var(--space-5); display:flex; flex-direction:column; gap: var(--space-4);
  }
  .roulette-head{ display:flex; align-items:center; justify-content:space-between; gap: var(--space-3); flex-wrap:wrap; }
  .roulette-tabs{ display:flex; gap: var(--space-2); flex-wrap:wrap; }
  .roulette-tab{
    display:inline-flex; align-items:center; padding:6px 12px;
    border-radius: var(--radius-full); border:1px solid var(--border);
    background: var(--surface); color: var(--text-secondary);
    font-family:inherit; font-size: var(--text-xs); font-weight:600; cursor:pointer;
  }
  .roulette-tab[aria-checked="true"]{ background: var(--accent-soft); border-color: var(--accent-border); color: var(--accent-fg); }
  #rouletteSpin[disabled]{ opacity:.55; cursor:default; }

  .reel-wrap{
    position:relative; overflow:hidden;
    border:1px solid var(--border-subtle); border-radius: var(--radius-sm);
    background: var(--surface-sunken); padding: 12px 0;
  }
  .reel-pointer{ position:absolute; left:50%; top:0; bottom:0; width:2px; background: var(--accent); transform:translateX(-50%); z-index:2; }
  .reel-pointer::before, .reel-pointer::after{ content:""; position:absolute; left:50%; width:0; height:0; border-left:5px solid transparent; border-right:5px solid transparent; transform:translateX(-50%); }
  .reel-pointer::before{ top:-1px; border-top:6px solid var(--accent); }
  .reel-pointer::after{ bottom:-1px; border-bottom:6px solid var(--accent); }
  .reel-track{ display:flex; gap:10px; padding-left: calc(50% - 28px); will-change:transform; }
  .reel-tile{ flex:none; width:56px; aspect-ratio:3/4; border-radius: var(--radius-xs); position:relative; overflow:hidden;
    display:flex; align-items:center; justify-content:center;
    background-image: repeating-linear-gradient(135deg, rgba(255,255,255,.05) 0 2px, transparent 2px 14px);
    opacity:.5; transition: opacity .2s ease, box-shadow .2s ease, transform .2s ease;
  }
  .reel-tile span{ font-family: var(--font-mono); font-weight:700; font-size:13px; color: rgba(255,255,255,.7); }
  .reel-tile.is-winner{ opacity:1; box-shadow: 0 0 0 2px var(--accent); transform:scale(1.06); }

  .roulette-result{ display:flex; align-items:baseline; gap: var(--space-2); }
  .roulette-result .result-label{ font-size: var(--text-xs); color: var(--text-tertiary); }
  .roulette-result .result-title{ font-size: var(--text-md); font-weight:700; color: var(--text-primary); }

  /* ============ IMPORT PAGE ============ */
  #view-import{ display:flex; flex-direction:column; gap: var(--space-6); }
  .import-card{
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md);
    padding: var(--space-5); display:flex; flex-direction:column; gap: var(--space-4);
  }
  .import-card h2{ font-size: var(--text-md); }
  .import-card .subtitle{ font-size: var(--text-xs); color: var(--text-tertiary); margin-top:-8px; }

  .sync-progress-label{ display:flex; justify-content:space-between; align-items:baseline; font-size: var(--text-xs); color: var(--text-secondary); }
  .sync-progress-label b{ font-family: var(--font-mono); color: var(--text-primary); }
  .sync-progress-track{ height:9px; background: var(--surface-sunken); border:1px solid var(--border-subtle); border-radius: var(--radius-full); overflow:hidden; }
  .sync-progress-fill{ height:100%; background: var(--accent); border-radius: var(--radius-full); }

  .sync-current{ display:flex; align-items:center; gap:9px; font-size: var(--text-sm); color: var(--text-secondary); }
  .sync-current b{ color: var(--text-primary); }
  .pulse-dot{ width:8px; height:8px; border-radius:50%; background: var(--accent); flex:none; animation: pulse-dot 1.4s ease-in-out infinite; }
  @keyframes pulse-dot{ 0%,100%{ opacity:1; transform:scale(1); } 50%{ opacity:.4; transform:scale(.7); } }
  @media (prefers-reduced-motion: reduce){ .pulse-dot{ animation:none; } }

  .import-log{ display:flex; flex-direction:column; gap:2px; font-family: var(--font-mono); font-size:11.5px; max-height:220px; overflow-y:auto; }
  .import-log-row{ display:flex; gap: var(--space-3); padding:4px 2px; border-radius: var(--radius-xs); }
  .import-log-row:hover{ background: var(--surface-hover); }
  .import-log-row .ts{ color: var(--text-tertiary); flex:none; }
  .import-log-row .msg{ color: var(--text-secondary); }
  .import-log-row.is-warn .msg{ color: var(--status-dropped-fg); }
  .import-log-row .msg b{ color: var(--text-primary); font-weight:600; }

  .import-errors-note{ font-size: var(--text-xs); color: var(--text-secondary); }
  .import-error-row{ display:flex; align-items:flex-start; gap: var(--space-3); padding: var(--space-2) 2px; border-bottom:1px solid var(--border-subtle); }
  .import-error-row:last-child{ border-bottom:none; }
  .import-error-row svg{ width:15px; height:15px; flex:none; margin-top:2px; stroke: var(--status-dropped-fg); }
  .import-error-row .err-text{ display:flex; flex-direction:column; gap:1px; }
  .import-error-row .err-text b{ font-size: var(--text-xs); font-weight:600; }
  .import-error-row .err-text span{ font-size: var(--text-2xs); color: var(--text-tertiary); }

  .import-divider{ display:flex; align-items:center; gap: var(--space-3); color: var(--text-tertiary); font-size: var(--text-2xs); text-transform:uppercase; letter-spacing:.06em; }
  .import-divider::before, .import-divider::after{ content:""; flex:1; height:1px; background: var(--border); }

  .import-private{
    background: var(--surface); border:1px solid var(--status-dropped-bd); border-radius: var(--radius-md);
    padding: var(--space-5); display:flex; gap: var(--space-4);
  }
  .import-private .icon-wrap{
    width:40px; height:40px; border-radius:50%; flex:none;
    background: var(--status-dropped-bg); border:1px solid var(--status-dropped-bd);
    display:flex; align-items:center; justify-content:center;
  }
  .import-private .icon-wrap svg{ width:18px; height:18px; stroke: var(--status-dropped-fg); }
  .import-private-body{ display:flex; flex-direction:column; gap: var(--space-3); flex:1; }
  .import-private-body h3{ font-size: var(--text-md); }
  .import-private-body > p{ font-size: var(--text-sm); color: var(--text-secondary); }
  .import-private-steps{ display:flex; flex-direction:column; gap:6px; counter-reset: step; }
  .import-private-steps li{ display:flex; gap: var(--space-2); font-size: var(--text-xs); color: var(--text-secondary); counter-increment: step; }
  .import-private-steps li::before{
    content: counter(step); flex:none; width:18px; height:18px; border-radius:50%;
    background: var(--surface-hover); color: var(--text-primary); font-family: var(--font-mono); font-size:10px; font-weight:700;
    display:flex; align-items:center; justify-content:center;
  }

  .btn-primary{
    align-self:flex-start;
    background: var(--accent); color: var(--bg-elevated); border:none;
    border-radius: var(--radius-sm); padding: 8px 14px;
    font-family:inherit; font-size: var(--text-sm); font-weight:600; cursor:pointer;
  }
  .btn-primary:hover{ filter:brightness(1.08); }

  /* ============ RESPONSIVE ============ */
  @media (max-width: 980px){
    .brand small{ display:none; }
    .page-layout{ grid-template-columns: 1fr; }
    .friend-rows{ flex-direction:row; flex-wrap:wrap; }
    .friend-row{ flex-direction:column; gap: var(--space-1); width:64px; text-align:center; }
    .friend-row .friend-name{ max-width:64px; }
    .game-row{ grid-template-columns: 30px 1fr 76px; }
    .row-progress, .row-platform, .game-row > .status-badge{ display:none; }
    .friend-game-row{ grid-template-columns: 38px 1fr 96px; }
    .friend-game-row .fg-pct, .friend-game-row .fg-note{ display:none; }
  }
  @media (max-width: 620px){
    .content{ padding: var(--space-4); }
    .topbar, .tabbar{ padding: 0 var(--space-3); }
    .topbar{ gap: var(--space-2); }
    .account-name{ display:none; }
    .nav-item span{ display:none; }
    .nav-item{ padding: 0 var(--space-2); }
    .stat-grid{ grid-template-columns: 1fr; }
    .card-grid{ grid-template-columns: repeat(auto-fill, minmax(130px,1fr)); }
    .profile-header{ padding: var(--space-4); }
    .profile-avatar{ width:68px; height:68px; font-size: var(--text-lg); }
    .level-ring{ width:48px; height:48px; }
    .game-header{ padding: var(--space-4); }
    .game-header-cover{ width:84px; }
    .game-header-cover-col{ width:84px; }
    .cup-slot{ --cup-size:15px; }
    .cup-rating-icons{ gap:2px; }
    .friend-game-row{ grid-template-columns: 38px 1fr; }
    .friend-game-row .fg-playtime{ display:none; }
  }

  /* ============================================================
     GAMELOG — дополнения к макету
     Всё, чего в статичном макете не было: обложки-картинки,
     формы входа и регистрации, служебные состояния Django.
     Значения берутся только из токенов выше.
     ============================================================ */

  /* — Шестой хранимый статус: «Играл». В макете его не было, поэтому
       токены и пилюля живут здесь, а не в блоке выше. Оттенок взят
       холоднее акцента и зеленее «Играю», чтобы на полосе распределения
       и в кольце эти три не слипались. — */
  :root{
    --status-played:        #4aa3b5;
    --status-played-fg:     #8ecbd8;
    --status-played-bg:     rgba(74,163,181,.14);
    --status-played-bd:     rgba(74,163,181,.38);
  }
  .status-badge.st-played{ color:var(--status-played-fg); background:var(--status-played-bg); border-color:var(--status-played-bd); }
  .status-badge.st-played .dot{ background:var(--status-played); }

  /* — Сотня отмечается атрибутом, а не статусом —
       Раньше «100%» был вычисляемым седьмым статусом: он подменял собой
       хранимый, из-за чего в списке библиотеки статус такой игры нельзя
       было сменить вовсе. Теперь пилюля всегда показывает хранимый статус,
       а сотня висит отдельным `data-perfect` — рамка и подсветка те же.

       Правила макета по [data-status="100"] остаются на месте мёртвыми:
       первый блок держим равным присланному макету. Медиазапрос тут не
       нужен — подсветку узкая раскладка не переопределяет, она правит
       только сетку колонок. */
  .game-card[data-perfect]{ border-color: var(--status-100-bd); box-shadow: 0 0 0 1px var(--status-100-bd) inset; }
  .game-card[data-perfect]:hover{ border-color: var(--status-100); box-shadow: 0 0 0 1px var(--status-100) inset, var(--shadow-md); }
  .game-row[data-perfect]{ background: var(--status-100-bg); box-shadow: inset 2px 0 0 var(--status-100); }
  .game-row[data-perfect]:hover{ background: var(--status-100-bg); filter:brightness(1.15); }

  /* — Текст статусной пилюли по центру —
       Пилюля и пилюля-<select> живут в колонках сетки и растягиваются на
       всю ширину колонки, а `<select>` вдобавок шире своего значения: он
       меряется по самому длинному варианту списка («Не в библиотеке»), и
       короткое «Играю» прилипало к левому краю. `text-align-last` нужен
       рядом с `text-align`: у select'а одна строка, и часть браузеров
       слушает только его. */
  .status-badge{ justify-content:center; }
  select.status-select{ text-align:center; text-align-last:center; }

  /* — Обложки: картинка ложится поверх плашки с инициалами.
       Если Steam CDN не отдал файл, onerror убирает <img>, и видно плашку. — */
  .row-cover, .recent-cover, .profile-avatar, .friend-avatar,
  .avatar, .cover-mini, .game-header-cover{ position:relative; overflow:hidden; }
  .cover img, .row-cover img, .recent-cover img, .game-header-cover img,
  .profile-avatar img, .friend-avatar img, .avatar img, .cover-mini img{
    position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  }
  .cover .cover-badge{ z-index:2; }

  /* — Ссылки вместо кнопок: разметка макета, семантика сайта — */
  a{ text-decoration:none; }
  a.game-card, a.game-row, a.recent-row, a.friend-row,
  a.nav-item, a.brand, a.account, a.status-badge, a.friend-game-row{ color:inherit; }
  a.game-row:hover, a.recent-row:hover, a.friend-row:hover{ background: var(--surface-hover); }
  a.status-badge{ cursor:pointer; transition:filter .12s ease, opacity .12s ease; }
  a.status-badge:hover{ filter:brightness(1.15); }
  a.status-badge:not(.is-active){ opacity:.55; }
  .link-inline{ color: var(--accent-fg); text-decoration: underline dotted; text-underline-offset:2px; }
  .link-inline:hover{ color: var(--accent); }
  /* Та же ссылка кнопкой — у действий, которые что-то меняют (POST). */
  button.link-inline{ background:none; border:0; padding:0; font:inherit; cursor:pointer; }

  /* — Лого в шапке: кольцо прогресса (#i-logo) вместо знака «>» макета.
       Правило .brand-mark макета (цвет) осталось — у svg цвета свои. — */
  .brand{ gap: var(--space-2); }
  svg.brand-mark{ width:24px; height:24px; flex:none; }

  /* — Окно подтверждения (static/js/confirm.js) —
       Нативный <dialog>: фокус, Esc и затемнение даёт браузер, от нас —
       только вид карточки сайта. Отступ от края экрана задаёт ширина, а
       не margin: у dialog margin:auto центрирует окно. — */
  .confirm-dialog{
    width: min(420px, calc(100vw - 2 * var(--space-4)));
    padding: var(--space-5);
    background: var(--surface); color: var(--text-primary);
    border:1px solid var(--border); border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
  }
  .confirm-dialog::backdrop{ background: var(--bg); opacity:.75; }
  .confirm-title{ font-size: var(--text-md); font-weight:600; margin:0 0 var(--space-2); line-height:1.35; }
  .confirm-text{ font-size: var(--text-sm); color: var(--text-secondary); margin:0 0 var(--space-5); line-height:1.5; }
  .confirm-actions{ display:flex; justify-content:flex-end; gap: var(--space-2); }

  /* — Кнопки — */
  .btn-ghost{
    display:inline-flex; align-items:center; gap: var(--space-2);
    background: var(--surface); color: var(--text-secondary);
    border:1px solid var(--border); border-radius: var(--radius-sm);
    padding: 7px 13px; font-family:inherit; font-size: var(--text-sm); font-weight:500; cursor:pointer;
  }
  .btn-ghost:hover{ background: var(--surface-hover); color: var(--text-primary); border-color: var(--border-strong); }

  /* Профиль: иконки из спрайта вместо эмодзи в полосе статов (у svg нет
     базовой линии — поэтому строка по центру) и строка устройств над ней. */
  .avatar-stats li{ align-items:center; }
  .avatar-stats svg{ width:18px; height:18px; flex:none; stroke:currentColor; color: var(--text-secondary); }
  /* Цвета — из токенов статусов: игры синим («Играю»), 100% зелёным
     («Пройдено»), ачивки золотом (уровень достижения). Часы — нейтральные. */
  .avatar-stats .stat-games{ color: var(--status-playing); }
  .avatar-stats .stat-perfect{ color: var(--status-completed); }
  .avatar-stats .stat-trophy{ color: var(--tier-gold); }
  .avatar-devices{ flex-basis:100%; display:flex; flex-wrap:wrap; gap: var(--space-2); }
  .avatar-devices button{
    display:inline-flex; align-items:center; justify-content:center; width:30px; height:30px;
    padding:0; cursor:pointer; font:inherit;
    background: var(--surface); color: var(--text-secondary);
    border:1px solid var(--border); border-radius: var(--radius-sm);
  }
  .avatar-devices button:hover{ background: var(--surface-hover); color: var(--text-primary); border-color: var(--border-strong); }
  .avatar-devices svg{ width:17px; height:17px; stroke:currentColor; }

  /* Подсказка и перетаскиваемое окно устройства в шапке профиля
     (static/js/device_window.js). Подсказка — .device-float, а не
     .device-tip: тот занят карточкой в строке библиотеки, и его правила
     (display:none, absolute) легли бы и сюда. Внутри — копия .device-card из
     блока «Устройства»; у копии рамка и фон сняты, их даёт обёртка. Вид —
     как у .help-tip-body и окна подтверждения. z-index выше липкой шапки
     (5–6) и выпадающих списков (20–30). */
  .device-float, .device-window{ position:fixed; left:0; top:0; }
  .device-float{
    z-index:60; pointer-events:none;
    width: min(320px, calc(100vw - 2 * var(--space-4)));
    background: var(--bg-elevated); border:1px solid var(--border-strong);
    border-radius: var(--radius-md); box-shadow: var(--shadow-md); overflow:hidden;
  }
  .device-window{
    z-index:40;
    width: min(360px, calc(100vw - 2 * var(--space-4)));
    max-height: calc(100vh - 2 * var(--space-4)); overflow:auto;
    background: var(--surface); color: var(--text-primary);
    border:1px solid var(--border); border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
  }
  .device-float .device-card, .device-window .device-card{ background:none; border:0; border-radius:0; }
  .device-window-bar{
    display:flex; align-items:center; justify-content:space-between; gap: var(--space-2);
    padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
    border-bottom:1px solid var(--border-subtle);
    cursor:grab; touch-action:none; user-select:none;
  }
  .device-window.is-dragging{ box-shadow: var(--shadow-lg), 0 0 0 1px var(--border-strong); }
  .device-window.is-dragging .device-window-bar{ cursor:grabbing; }
  .device-window-bar b{ font-size: var(--text-sm); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .device-window-close{
    display:inline-flex; align-items:center; justify-content:center; flex:none;
    width:28px; height:28px; padding:0; cursor:pointer;
    background:none; border:1px solid transparent; border-radius: var(--radius-sm); color: var(--text-tertiary);
  }
  .device-window-close:hover, .device-window-close:focus-visible{ background: var(--surface-hover); color: var(--text-primary); border-color: var(--border); }
  .device-window-close svg{ width:15px; height:15px; stroke:currentColor; }
  /* Заблокированная кнопка (отсчёт «Отправить ещё раз»): без hover, цифры одной ширины. */
  .btn-ghost:disabled,
  .btn-ghost:disabled:hover{ background: var(--surface); color: var(--text-tertiary); border-color: var(--border); cursor:default; font-variant-numeric: tabular-nums; }
  .btn-ghost svg{ width:14px; height:14px; stroke:currentColor; }
  .btn-danger{ color: var(--status-dropped-fg); border-color: var(--status-dropped-bd); }
  .btn-danger:hover{ background: var(--status-dropped-bg); color: var(--status-dropped-fg); }
  a.btn-primary{ display:inline-flex; align-items:center; }
  .btn-row{ display:flex; flex-wrap:wrap; gap: var(--space-2); align-items:center; }
  .link-btn{
    background:none; border:none; padding:0; cursor:pointer;
    font-family:inherit; font-size: var(--text-2xs); color: var(--text-tertiary);
    text-decoration: underline dotted; text-underline-offset:2px;
  }
  .link-btn:hover{ color: var(--accent-fg); }

  /* — Формы: вход, регистрация, добавление друга — */
  .form-shell{ max-width:400px; width:100%; margin-inline:auto; display:flex; flex-direction:column; gap: var(--space-5); }
  .form-card{
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md);
    padding: var(--space-6); display:flex; flex-direction:column; gap: var(--space-4);
  }
  .form-card h1{ font-size: var(--text-lg); }
  .form-card .subtitle{ font-size: var(--text-xs); color: var(--text-tertiary); margin-top:-8px; }
  /* Поля и кнопка — с тем же шагом, что блоки самой карточки. Без этого
     форма была обычным блоком: кнопка «Создать аккаунт» липла к подсказке
     под последним полем, а подпись следующего поля — к подсказке
     предыдущего. Ловушка .hp вынесена абсолютно и в шаге не участвует. */
  .form-card form{ display:flex; flex-direction:column; gap: var(--space-4); }
  .field{ display:flex; flex-direction:column; gap:5px; }
  .field > label{ font-size: var(--text-2xs); font-weight:600; text-transform:uppercase; letter-spacing:.07em; color: var(--text-tertiary); }
  .field .helptext{ font-size: var(--text-2xs); color: var(--text-tertiary); }
  /* Селекторы намеренно узкие: у поиска в шапке своё оформление,
     и общее правило по типу поля перебивало бы его отступы. */
  .field input, .field textarea, .field select{
    width:100%; background: var(--surface-sunken); color: var(--text-primary);
    border:1px solid var(--border); border-radius: var(--radius-sm);
    padding: 9px 11px; font-family:inherit; font-size: var(--text-sm);
  }
  .field input:focus, .field textarea:focus, .field select:focus{ outline:none; border-color: var(--accent-border); background: var(--bg-elevated); }
  .field textarea{ min-height:110px; resize:vertical; line-height:1.5; }
  .errorlist{ display:flex; flex-direction:column; gap:2px; }
  .errorlist li{ font-size: var(--text-2xs); color: var(--status-dropped-fg); }
  .field.has-error input{ border-color: var(--status-dropped-bd); }
  .form-foot{ font-size: var(--text-xs); color: var(--text-tertiary); text-align:center; }

  /* — Сообщения Django — */
  .messages{ display:flex; flex-direction:column; gap: var(--space-2); }
  .messages li{
    font-size: var(--text-xs); padding: 9px 13px;
    border-radius: var(--radius-sm); border:1px solid var(--border);
    background: var(--surface); color: var(--text-secondary);
  }
  .messages li.success{ border-color: var(--status-completed-bd); background: var(--status-completed-bg); color: var(--status-completed-fg); }
  .messages li.error{ border-color: var(--status-dropped-bd); background: var(--status-dropped-bg); color: var(--status-dropped-fg); }
  .messages li.warning{ border-color: var(--status-planned-bd); background: var(--status-planned-bg); color: var(--status-planned-fg); }

  /* — Гостевая главная — */
  .hero{
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-lg);
    padding: var(--space-10) var(--space-8); display:flex; flex-direction:column; gap: var(--space-4);
    align-items:flex-start; max-width:720px; margin-inline:auto;
  }
  .hero h1{ font-size: var(--text-2xl); }
  .hero p{ font-size: var(--text-base); color: var(--text-secondary); max-width:52ch; }
  .hero ul{ display:flex; flex-direction:column; gap: var(--space-2); }
  .hero ul li{ font-size: var(--text-sm); color: var(--text-secondary); display:flex; gap: var(--space-2); }
  .hero ul li::before{ content:"—"; color: var(--text-tertiary); }

  /* — Плашка «Steam не подключён» и прочие подсказки — */
  .callout{
    display:flex; align-items:center; gap: var(--space-4); flex-wrap:wrap;
    background: var(--surface); border:1px solid var(--accent-border); border-radius: var(--radius-md);
    padding: var(--space-4) var(--space-5);
  }
  .callout .callout-text{ display:flex; flex-direction:column; gap:2px; flex:1; min-width:220px; }
  .callout b{ font-size: var(--text-sm); }
  .callout span{ font-size: var(--text-xs); color: var(--text-secondary); }

  /* — Комментарии на странице игры (partials/comments.html, apps/comments).
       Аватар слева, ответы — со сдвигом под текстом родителя, один уровень. — */
  .comment-form{ display:flex; flex-direction:column; gap: var(--space-2); margin-bottom: var(--space-4); }
  .comment-form textarea{
    width:100%; min-height:72px; resize:vertical; line-height:1.5;
    background: var(--surface-sunken); color: var(--text-primary);
    border:1px solid var(--border); border-radius: var(--radius-sm);
    padding: 9px 11px; font-family:inherit; font-size: var(--text-sm);
  }
  .comment-form textarea:focus{ outline:none; border-color: var(--accent-border); background: var(--bg-elevated); }
  .comment-form-foot{ display:flex; align-items:center; justify-content:space-between; gap: var(--space-3); flex-wrap:wrap; }
  .comment-form-foot .btn-primary{ align-self:auto; margin-left:auto; }
  .comment-form-foot .helptext{ font-size: var(--text-2xs); color: var(--text-tertiary); font-family: var(--font-mono); }
  .comment-list{ display:flex; flex-direction:column; gap: var(--space-4); }
  .comment{ display:flex; gap: var(--space-3); align-items:flex-start; scroll-margin-top: calc(var(--topbar-h) + var(--tabbar-h) + var(--space-6)); }
  #h-comments{ scroll-margin-top: calc(var(--topbar-h) + var(--tabbar-h) + var(--space-6)); }
  /* У .friend-avatar своего размера и display нет — только внутри списков
     макета; здесь он внутри ссылки, поэтому всё задано целиком. */
  .comment-avatar{ display:block; flex:none; }
  .comment .friend-avatar{
    width:36px; height:36px; border-radius: var(--radius-sm);
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size: var(--text-2xs); color: var(--text-primary);
  }
  .comment.is-reply .friend-avatar{ width:28px; height:28px; }
  .comment-main{ flex:1; min-width:0; display:flex; flex-direction:column; gap:4px; }
  .comment-head{ display:flex; align-items:baseline; gap: var(--space-2); flex-wrap:wrap; font-size: var(--text-xs); color: var(--text-tertiary); }
  .comment-author{ color: var(--text-primary); font-weight:600; font-size: var(--text-sm); }
  .comment-author:hover{ color: var(--accent-fg); }
  .comment-time{ color: var(--text-tertiary); }
  .comment-time:hover{ color: var(--text-secondary); }
  .comment-body{ font-size: var(--text-sm); color: var(--text-secondary); line-height:1.55; overflow-wrap:anywhere; }
  .comment-body > * + *{ margin-top: var(--space-2); }
  .comment-body a{ color: var(--accent-fg); text-decoration: underline; text-underline-offset:2px; }
  .comment-body blockquote{ border-left:2px solid var(--border-strong); padding-left: var(--space-3); color: var(--text-tertiary); }
  .comment-body ul, .comment-body ol{ padding-left: 1.4em; }
  .comment-body ul{ list-style: disc; }
  .comment-body ol{ list-style: decimal; }
  .comment-body code{ font-family: var(--font-mono); font-size: .92em; background: var(--surface-sunken); padding: 1px 4px; border-radius: var(--radius-xs); }
  .comment-body pre{ background: var(--surface-sunken); padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); overflow-x:auto; }
  .comment-body pre code{ padding:0; background:none; }
  /* Спойлер: плашка без текста, пока не кликнули (static/js/comments.js);
     с клавиатуры — пока на нём фокус. Ссылки внутри скрыты и не нажимаются. */
  .comment-body .spoiler{ background: var(--text-tertiary); color:transparent; border-radius: var(--radius-xs); padding: 0 2px; cursor:pointer; transition: background .15s ease, color .15s ease; }
  .comment-body .spoiler:not(.is-shown) *{ color:transparent; pointer-events:none; }
  .comment-body .spoiler.is-shown, .comment-body .spoiler:focus-visible{ background: var(--surface-sunken); color: inherit; cursor:auto; outline:none; }
  .comment-body .spoiler:focus-visible *{ color: inherit; }
  .comment-actions{ display:flex; align-items:center; gap: var(--space-4); flex-wrap:wrap; margin-top:2px; }
  .comment-actions .link-btn{ font-size: var(--text-xs); }
  .comment-actions .comment-delete:hover{ color: var(--status-dropped-fg); }
  /* «Ответить» и «Изменить» — <details>: раскрытый уходит в конец ряда
     отдельной строкой во всю ширину, форма под своей ссылкой. */
  .comment-box summary{ list-style:none; cursor:pointer; }
  .comment-box summary::-webkit-details-marker{ display:none; }
  .comment-box[open]{ order:10; flex-basis:100%; }
  .comment-box > .comment-form{ margin: var(--space-2) 0 0; }
  .comment-like{
    display:inline-flex; align-items:center; gap:5px; padding:0; background:none; border:0;
    font-family:inherit; font-size: var(--text-xs); color: var(--text-tertiary); cursor:pointer;
  }
  .comment-like svg{ width:15px; height:15px; stroke:currentColor; fill:none; }
  .comment-like:hover{ color: var(--status-dropped-fg); }
  .comment-like.is-liked{ color: var(--status-dropped-fg); }
  .comment-like.is-liked svg{ fill:currentColor; }
  .comment-like.is-static{ cursor:default; }
  .comment-like.is-static:hover{ color: var(--text-tertiary); }
  .comment-replies{ display:flex; flex-direction:column; gap: var(--space-3); margin-top: var(--space-3); padding-left: var(--space-3); border-left:1px solid var(--border-subtle); }

  /* — Мелочи — */
  .search form{ display:contents; }
  .inline-form{ display:inline-flex; align-items:center; gap: var(--space-2); }
  .friend-row-actions{ display:flex; align-items:center; gap: var(--space-2); }
  .friend-rows .friend-row{ justify-content:space-between; }
  .friend-row .friend-body{ display:flex; align-items:center; gap: var(--space-3); min-width:0; }
  .friend-text{ display:flex; flex-direction:column; gap:1px; min-width:0; }
  .friend-text .friend-sub{ font-size:10.5px; color: var(--text-tertiary); font-family: var(--font-mono); }

  /* — Друзья в профиле на узкой ширине —
       Макет ниже 980px делает .friend-row колонкой 64px (аватар над
       ником), но наша обёртка .friend-body осталась строкой: аватар и
       подпись вставали рядом и наезжали на соседа. Ставим её колонкой
       тоже; «N пройдено» переносится по центру, ник — с многоточием. — */
  @media (max-width: 980px){
    .friend-row .friend-body{ flex-direction:column; gap: var(--space-1); }
    .friend-row .friend-text{ align-items:center; max-width:64px; }
    .friend-text .friend-sub{ text-align:center; }
  }

  /* — Правая колонка не шире экрана —
       На узкой ширине сетка .page-layout — одна колонка 1fr, а её минимум
       берётся из содержимого. У .page-main min-width:0 стоит, у
       .page-aside — нет, и длинное название в «Недавних играх» (nowrap)
       раздвигало колонку шире экрана: карточки обрезались справа. — */
  .page-aside{ min-width:0; }
  .stat-card.is-link:hover{ border-color: var(--border-strong); }
  .empty-state.is-compact{ padding: var(--space-6) var(--space-4); }

  /* — Градиенты аватаров-заглушек: у человека номер постоянный — */
  .tint-1{ background: linear-gradient(155deg, var(--cover-1), var(--cover-4)); }
  .tint-2{ background: linear-gradient(155deg, var(--cover-2), var(--cover-5)); }
  .tint-3{ background: linear-gradient(155deg, var(--cover-3), var(--cover-6)); }
  .tint-4{ background: linear-gradient(155deg, var(--cover-4), var(--cover-7)); }
  .tint-5{ background: linear-gradient(155deg, var(--cover-5), var(--cover-8)); }
  .tint-6{ background: linear-gradient(155deg, var(--cover-6), var(--cover-1)); }
  .tint-7{ background: linear-gradient(155deg, var(--cover-7), var(--cover-2)); }
  .tint-8{ background: linear-gradient(155deg, var(--cover-8), var(--cover-3)); }

  /* — Статус-пилюля, которая одновременно редактор: тот же вид, но <select> — */
  select.status-select{
    appearance:none; -webkit-appearance:none;
    cursor:pointer; font-family:inherit; width:auto;
    padding: 3px 9px; line-height:1.6;
  }
  select.status-select:hover{ filter:brightness(1.15); }
  select.status-select option{ background: var(--surface); color: var(--text-primary); }

  /* Раскрытый список статуса — свой, а не системный (customizable select,
     Chromium 135+). Системный список браузер рисует сам: на странице игры в
     Chrome он выходил уже пилюли и прижатым к её левому краю. Свой — шириной
     не меньше пилюли, по центру под ней (над ней, если внизу нет места),
     строки по центру, текущий статус акцентом. Firefox и Safari base-select
     пока не умеют — у них системный список, как раньше. */
  @supports (appearance: base-select){
    select.status-select, select.status-select::picker(select){ appearance: base-select; }
    select.status-select::picker-icon{ display:none; }
    select.status-select::picker(select){
      min-inline-size: anchor-size(self-inline);
      position-area: block-end; position-try-fallbacks: flip-block;
      margin-block: 4px; padding: 4px;
      background: var(--surface); color: var(--text-primary);
      border:1px solid var(--border-strong); border-radius: var(--radius-sm);
      box-shadow: var(--shadow-md);
    }
    /* Второй селектор — чтобы перебить полупрозрачные строки пикера игры. */
    select.status-select option,
    .game-status-picker select.status-select option{
      justify-content:center; padding: 6px 12px; border-radius: var(--radius-xs);
      font-size: var(--text-xs); font-weight:600; background:none; color: var(--text-primary);
    }
    select.status-select option::checkmark{ display:none; }
    select.status-select option:hover,
    select.status-select option:focus-visible{ background: var(--surface-hover); outline:none; }
    select.status-select option:checked{ color: var(--accent-fg); }
  }

  /* — Иконка достижения: картинка Steam поверх запасного кубка — */
  .ach-icon{ position:relative; overflow:hidden; }
  .ach-icon img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }

  /* Невыбитое достижение приезжает со Steam уже серой картинкой
     (icon_gray_url), а правило макета гасит её второй раз: прозрачность
     .4 поверх серого на тёмном фоне съедала иконку до пятна. Гасим
     заметно слабее. grayscale из макета остаётся — он нужен тем играм,
     у которых серой версии нет и в дело идёт цветная. */
  .ach-row.is-locked .ach-icon{ opacity:.72; }

  /* Игра на сотню: шапка получает ту же платиновую рамку, что карточка в
     сетке и строка в списке, только заметнее — это главный блок страницы.
     Цвет из семейства --status-100: «сотня» на всех экранах читается одним
     и тем же цветом. Признак — свой атрибут data-perfect, а не статус:
     статус теперь всегда хранимый и сотню собой не подменяет. */
  .game-header[data-perfect]{
    border-color: var(--status-100-bd);
    box-shadow: 0 0 0 1px var(--status-100-bd) inset, 0 0 26px -10px var(--status-100);
  }

  /* Платиновая оценка: над шапкой тихо сыплются кубки.
     Слой уходит под содержимое отрицательным z-index, а не подъёмом всех
     соседей: подъём делался через `position:relative` для всех детей и
     ломал «Оценку сайта» — она прибита к углу через `position:absolute`,
     и правило сбрасывало её в обычный поток, к левому краю.
     Отрицательный слой не проваливается за фон шапки, потому что
     `isolation` делает её собственным контекстом наложения; фон и рамка
     рисуются раньше отрицательных детей, а содержимое — позже. */
  .game-header{ isolation:isolate; }
  .platinum-snow{
    /* Один множитель на все кубки: на узком экране шапка ниже, и крупные
       кубки в ней смотрятся не снежком, а помехой. */
    --flake: 1;
    position:absolute; inset:0; z-index:-1;
    overflow:hidden; border-radius:inherit; pointer-events:none;
  }
  /* `backwards` обязателен: с положительной задержкой элемент до старта
     стоит в собственном виде — вверху и непрозрачный, — и кубки висели
     под рамкой, пока их очередь не подойдёт. С ним ещё до старта
     применяется нулевой кадр, где кубок поднят и прозрачен. */
  .platinum-snow span{
    position:absolute; top:0; display:block; opacity:0;
    animation: platinum-fall linear infinite backwards;
  }
  .platinum-snow svg{
    width:100%; height:100%; fill:none;
    stroke: var(--tier-platinum); stroke-width:1.4;
  }
  @keyframes platinum-fall{
    0%   { transform: translate3d(0, -48px, 0) rotate(-14deg); opacity:0; }
    12%  { opacity:.5; }
    85%  { opacity:.5; }
    100% { transform: translate3d(18px, 420px, 0) rotate(18deg); opacity:0; }
  }
  .platinum-snow span:nth-child(1){ left:3%; width:calc(22px * var(--flake)); height:calc(22px * var(--flake)); animation-duration:8s; animation-delay:0s; }
  .platinum-snow span:nth-child(2){ left:12%; width:calc(15px * var(--flake)); height:calc(15px * var(--flake)); animation-duration:11s; animation-delay:2.4s; }
  .platinum-snow span:nth-child(3){ left:21%; width:calc(26px * var(--flake)); height:calc(26px * var(--flake)); animation-duration:9.5s; animation-delay:5.1s; }
  .platinum-snow span:nth-child(4){ left:33%; width:calc(13px * var(--flake)); height:calc(13px * var(--flake)); animation-duration:12.5s; animation-delay:1.2s; }
  .platinum-snow span:nth-child(5){ left:44%; width:calc(30px * var(--flake)); height:calc(30px * var(--flake)); animation-duration:8.5s; animation-delay:6.3s; }
  .platinum-snow span:nth-child(6){ left:55%; width:calc(17px * var(--flake)); height:calc(17px * var(--flake)); animation-duration:10.5s; animation-delay:3.7s; }
  .platinum-snow span:nth-child(7){ left:66%; width:calc(28px * var(--flake)); height:calc(28px * var(--flake)); animation-duration:9s; animation-delay:7.8s; }
  .platinum-snow span:nth-child(8){ left:76%; width:calc(14px * var(--flake)); height:calc(14px * var(--flake)); animation-duration:12s; animation-delay:0.8s; }
  .platinum-snow span:nth-child(9){ left:86%; width:calc(24px * var(--flake)); height:calc(24px * var(--flake)); animation-duration:9.8s; animation-delay:4.5s; }
  .platinum-snow span:nth-child(10){ left:94%; width:calc(12px * var(--flake)); height:calc(12px * var(--flake)); animation-duration:11.5s; animation-delay:6.9s; }
  @media (max-width: 620px){
    .platinum-snow{ --flake: .6; }
  }
  @media (prefers-reduced-motion: reduce){
    /* Замереть на месте здесь некрасиво: десять кубков посреди шапки
       выглядят мусором. Убираем слой целиком — он декоративный. */
    .platinum-snow{ display:none; }
  }

  /* — Живой поиск в шапке. Список висит под полем; `.search` уже
       position:relative, так что достаточно прижать его к низу. — */
  .search-results{ position:absolute; top:calc(100% + 6px); left:0; right:0; z-index:20; }
  .search-panel{
    background: var(--bg-elevated);
    border:1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    overflow:hidden auto;
    max-height:min(60vh, 420px);
  }
  .search-result{
    display:flex; align-items:center; gap: var(--space-3);
    padding: var(--space-2) var(--space-3); color:inherit;
  }
  .search-result:not(:last-child){ border-bottom:1px solid var(--border-subtle); }
  .search-result:hover, .search-result:focus-visible{ background: var(--surface-hover); }
  .search-result-text{ display:flex; flex-direction:column; gap:1px; min-width:0; flex:1; }
  .search-result-text b{
    font-size: var(--text-sm); font-weight:600;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .search-result-text span{
    font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--text-tertiary);
  }
  .search-result-all{ justify-content:center; font-size: var(--text-xs); color: var(--text-secondary); }
  .search-empty{
    padding: var(--space-4); text-align:center;
    font-size: var(--text-xs); color: var(--text-tertiary);
  }

  /* — Руководства по достижениям. Карточки в макете не было: сделана по
       образцу hltb-card, но строки здесь ссылки — длинное название в две
       строки слева, число плюсов справа. — */
  .guides-card{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display:flex; flex-direction:column; gap: var(--space-2);
  }
  .guide-list{ display:flex; flex-direction:column; }
  .guide-row:not(:last-child){ border-bottom:1px solid var(--border-subtle); }
  .guide-row a{
    display:flex; align-items:flex-start; justify-content:space-between;
    gap: var(--space-3); padding: var(--space-2) 3px; color:inherit;
  }
  .guide-row a:hover .guide-title{ color: var(--accent-fg); }
  .guide-title{
    font-size: var(--text-sm); color: var(--text-secondary); min-width:0;
    display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
  }
  .guide-votes{
    font-family: var(--font-mono); font-size: var(--text-xs);
    color: var(--text-tertiary); flex:none; padding-top:1px;
  }

  /* Строка критика — ссылка на источник; в макете это был просто span.
     В бейдже своя звезда вместо инициалов: логотипы источников — чужие
     знаки, а название и так написано рядом. */
  .critic-badge svg{ width:15px; height:15px; stroke:currentColor; fill:none; }
  a.critic-source{ color:inherit; }
  a.critic-source:hover .critic-name{ color: var(--accent-fg); }

  /* — «Друзья» —
       Блок переехал в правую колонку, а там 300 px: шестиколоночная строка
       макета (.friend-game-row) туда не влезает и больше не используется.
       Вместо неё карточка в две строки: имя со статусом, под ними цифры.
       Аватар занимает обе строки. — */
  .friend-card{
    background: var(--surface);
    border:1px solid var(--border);
    border-radius: var(--radius-md);
    padding: var(--space-4);
    display:flex; flex-direction:column; gap: var(--space-2);
  }
  .friend-game-card{
    display:grid;
    grid-template-columns: 34px minmax(0,1fr) auto;
    align-items:center;
    column-gap: var(--space-3); row-gap:1px;
    padding: var(--space-2) 0;
    border-bottom:1px solid var(--border-subtle);
  }
  .friend-game-card:last-child{ border-bottom:0; padding-bottom:0; }
  .friend-game-card:hover .fgc-name{ color: var(--accent-fg); }
  .friend-game-card .friend-avatar{
    grid-row: 1 / span 2; width:34px; height:34px; font-size:11px;
    border-radius: var(--radius-sm);
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; color: var(--text-primary); flex:none;
  }
  .fgc-name{
    grid-column:2; font-size: var(--text-sm); font-weight:600;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .friend-game-card > .status-badge{ grid-column:3; grid-row:1; }
  .fgc-meta{
    grid-column: 2 / span 2;
    font-size: var(--text-2xs); color: var(--text-tertiary);
  }

  /* — Фильтры списка достижений —
       Ряд ссылок в шапке блока. Свой нейтральный вид, а не .status-badge:
       у той пилюли цвет всегда означает статус игры, и красить ею
       сортировку значило бы врать глазом. — */
  .ach-filters{ display:flex; flex-wrap:wrap; gap: var(--space-2); }
  .ach-filter{
    font-size: var(--text-2xs); font-weight:600; line-height:1.6;
    padding: 3px 10px; border-radius: var(--radius-full);
    border:1px solid var(--border); color: var(--text-tertiary);
    white-space:nowrap; transition: color .12s ease, border-color .12s ease, background-color .12s ease;
  }
  .ach-filter:hover{ color: var(--text-primary); border-color: var(--border-strong); }
  .ach-filter.is-active{
    color: var(--accent-fg); border-color: var(--accent-border); background: var(--accent-soft);
  }
  /* Переключатель Steam ↔ PlayStation — тот же вид, но отделён от
     сортировок пунктиром: это другой список, а не другой порядок. */
  /* Платформа достижений — выпадающий список того же вида, что статус в
     шапке, но по ширине содержимого и в высоту пилюль рядом. */
  .ach-platform-picker{ width:auto; }
  .ach-platform-picker select.status-badge{
    width:auto; padding: 3px 26px 3px 10px; line-height:1.6;
    font-size: var(--text-2xs); font-weight:600;
    color: var(--text-secondary); border-radius: var(--radius-full);
  }

  /* Ранг трофея PSN над датой — цветом кубков из логотипа. */
  .ach-grade{ font-size: var(--text-2xs); font-weight:600; }
  .ach-grade.grade-bronze{ color: var(--tier-bronze); }
  .ach-grade.grade-silver{ color: var(--tier-silver); }
  .ach-grade.grade-gold{ color: var(--tier-gold); }
  .ach-grade.grade-platinum{ color: var(--tier-platinum); }

  /* — Действия над аккаунтом в шапке: Steam и выход — */
  .topbar-actions{ display:flex; align-items:center; gap: var(--space-2); flex:none; }
  .topbar-actions .btn-ghost{ padding: 5px 10px; font-size: var(--text-xs); }
  .topbar-actions svg{ width:13px; height:13px; stroke:currentColor; }

  /* — Блок «Любимые игры»: панель на игру, под ней её достижения — */
  .favourites{ display:flex; flex-direction:column; gap: var(--space-4); }
  .favourites .ach-panel-head .status-badge{ flex:none; }
  .favourites .ach-panel-head-text a{ color:inherit; }
  .favourites .ach-panel-head-text a:hover{ color: var(--accent-fg); }
  .favourites .ach-icon{ width:44px; height:44px; }
  .favourites .ach-icon svg{ width:22px; height:22px; }

  /* Достижения в панели — только иконки в ряд. Название с описанием
     и рядность прячутся и всплывают подсказкой при наведении на иконку. */
  .favourites .ach-panel{ overflow:visible; }
  /* Шапка панели — широкий фон игры вместо иконки: картинка лежит под
     контентом, поверх неё градиент, иначе текст по ней не читается. */
  .favourites .ach-panel-head{
    position:relative;
    overflow:hidden;
    min-height:110px;
    padding: var(--space-4) var(--space-5);
    border-radius: var(--radius-md) var(--radius-md) 0 0;
  }
  .favourites .ach-panel-bg{
    position:absolute; inset:0; width:100%; height:100%;
    object-fit:cover; object-position:center;
  }
  .favourites .ach-panel-head::after{
    content:""; position:absolute; inset:0;
    background: linear-gradient(90deg,
      rgba(20,22,27,.95) 0%, rgba(20,22,27,.88) 42%, rgba(20,22,27,.5) 100%);
  }
  .favourites .ach-panel-head > *:not(.ach-panel-bg){ position:relative; z-index:1; }

  /* Текст в панели крупнее: блок читается с расстояния, а не только вблизи. */
  .favourites .ach-panel-head-text b{ font-size: var(--text-lg); }
  .favourites .ach-panel-head-text .note{ font-size: var(--text-sm); }

  /* Нижний блок панели — одна строка: иконки слева, статус и полоса
     справа, на том же уровне. На узком экране строка переносится, и
     margin-left:auto по-прежнему держит их у правого края. */
  .favourites .ach-panel-body{
    display:flex; align-items:center; flex-wrap:wrap;
    gap: var(--space-4);
    padding-right: var(--space-5);
  }
  .favourites .ach-panel-body > .ach-list,
  .favourites .ach-panel-body > .ach-empty{ flex:1; min-width:0; }
  .favourites .ach-panel-meta{
    display:flex; align-items:center; flex-wrap:wrap;
    gap: var(--space-4);
    margin-left:auto;
    padding: var(--space-4) 0;
  }
  .favourites .ach-panel-meta .progress{
    flex:none; width:300px; max-width:100%; margin-top:0;
  }
  .favourites .ach-panel-meta .progress-label{ font-size: var(--text-xs); }
  .favourites .ach-panel-meta .status-badge{ font-size: var(--text-xs); padding: 4px 11px 4px 9px; }

  /* Строка легенды в «Сводке» сама стала ссылкой в библиотеку с фильтром.
     На чужом профиле href нет — оформление не должно обещать переход. */
  .status-chart-legend a{ display:flex; align-items:center; gap:7px; color:inherit; }
  .status-chart-legend a[href]:hover{ color: var(--text-primary); }
  .status-chart-legend a[href]:hover .dot{ box-shadow: 0 0 0 3px var(--surface-hover); }
  .favourites .ach-list{
    display:flex;
    flex-direction:row;
    flex-wrap:wrap;
    align-items:flex-start;
    gap: var(--space-3);
    padding: var(--space-4);
  }
  .favourites .ach-list .ach-row{
    position:relative;
    flex:none;
    gap:0;
    padding:0;
    border-bottom:none;
  }
  .favourites .ach-list .ach-icon{ cursor:help; }

  /* Подсказка: название + описание над иконкой, редкость под ней. */
  .favourites .ach-list .ach-text,
  .favourites .ach-list .ach-meta{
    position:absolute;
    left:50%;
    width:220px;
    padding: var(--space-2) var(--space-3);
    background: var(--bg-elevated);
    border:1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
    opacity:0;
    visibility:hidden;
    pointer-events:none;
    transition: opacity .12s ease, transform .12s ease, visibility 0s linear .12s;
    z-index:6;
  }
  .favourites .ach-list .ach-text{
    bottom: calc(100% + 8px);
    transform: translateX(-50%) translateY(4px);
  }
  .favourites .ach-list .ach-meta{
    top: calc(100% + 8px);
    min-width:0;
    text-align:left;
    align-items:flex-start;
    transform: translateX(-50%) translateY(-4px);
  }
  .favourites .ach-list .ach-row:hover .ach-text,
  .favourites .ach-list .ach-row:hover .ach-meta{
    opacity:1;
    visibility:visible;
    transform: translateX(-50%);
    transition: opacity .12s ease, transform .12s ease;
  }
  .ach-empty{
    padding: var(--space-4); font-size: var(--text-xs); color: var(--text-tertiary);
  }

  /* Правая колонка стала шире — обложки и аватары в ней тоже. */
  .page-aside .recent-cover{ width:36px; }
  .page-aside .recent-info b{ font-size: var(--text-sm); }
  .page-aside .recent-info span{ font-size: var(--text-xs); }
  .page-aside .friend-row .friend-avatar{ width:40px; height:40px; }
  .page-aside .friend-name{ font-size: var(--text-sm); color: var(--text-primary); }

  /* — Шестерёнка в шапке — */
  .icon-btn{
    display:inline-flex; align-items:center; justify-content:center;
    width:30px; height:30px; flex:none;
    border:1px solid transparent; border-radius: var(--radius-sm);
    color: var(--text-secondary);
  }
  .icon-btn svg{ width:17px; height:17px; stroke: currentColor; }
  .icon-btn:hover{ background: var(--surface); border-color: var(--border); color: var(--text-primary); }
  .icon-btn[aria-current="page"]{ color: var(--accent-fg); border-color: var(--accent-border); }
  /* Тумблер языка: глобус плюс код языка, на который переключаемся. */
  .icon-btn.lang-btn{ width:auto; gap:5px; padding:0 8px; font:inherit; font-size: var(--text-2xs); font-weight:600; letter-spacing:.04em; }
  .lang-form{ display:inline-flex; }

  /* — Колокольчик в шапке: <details>, панель висит под ним у правого края. — */
  .bell{ position:relative; display:inline-flex; }
  .bell > summary{ list-style:none; cursor:pointer; position:relative; }
  .bell > summary::-webkit-details-marker{ display:none; }
  .bell[open] > summary{ background: var(--surface); border-color: var(--border); color: var(--text-primary); }
  .bell-count{
    position:absolute; top:-4px; right:-4px;
    min-width:16px; height:16px; padding:0 4px;
    border-radius: var(--radius-full); background: var(--accent); color: var(--bg);
    font-family: var(--font-mono); font-size: var(--text-2xs); font-weight:700;
    line-height:16px; text-align:center;
  }
  .bell-panel{
    position:absolute; top:calc(100% + 8px); right:0; z-index:20;
    width:320px;
    background: var(--bg-elevated);
    border:1px solid var(--border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    overflow:hidden;
  }
  .bell-item{ display:flex; align-items:flex-start; gap: var(--space-3); padding: var(--space-3); }
  .bell-item:not(:last-child){ border-bottom:1px solid var(--border-subtle); }
  .bell-item-text{ display:flex; flex-direction:column; gap: var(--space-2); min-width:0; font-size: var(--text-sm); line-height:1.4; }
  .bell-item .btn-primary, .bell-item .btn-ghost{ padding: 5px 10px; font-size: var(--text-xs); }
  .bell-empty{ padding: var(--space-4); text-align:center; font-size: var(--text-xs); color: var(--text-tertiary); }
  /* Уведомление-ссылка (запросы администратору): вся строка кликабельна,
     вместо аватара — значок вида в кружке того же размера. */
  a.bell-link{ color:inherit; }
  a.bell-link:hover, a.bell-link:focus-visible{ background: var(--surface-hover); outline:none; }
  /* Объявление — кнопка формы (POST отмечает прочитанным), а выглядит как
     пункт-ссылка: без рамки и фона кнопки, во всю ширину, текст слева. */
  .bell-form:not(:last-child){ border-bottom:1px solid var(--border-subtle); }
  button.bell-link{
    width:100%; border:0; border-radius:0; background:none; color:inherit;
    font:inherit; text-align:left; cursor:pointer;
  }
  button.bell-link:hover, button.bell-link:focus-visible{ background: var(--surface-hover); outline:none; }
  .bell-icon{
    width:32px; height:32px; flex:none; border-radius:50%;
    display:flex; align-items:center; justify-content:center;
    background: var(--surface); border:1px solid var(--border); color: var(--text-secondary);
  }
  .bell-icon svg{ width:16px; height:16px; stroke: currentColor; }
  .bell-hint{ font-size: var(--text-xs); color: var(--text-tertiary); }
  @media (max-width: 620px){
    /* На телефоне колокольчик почти у правого края, и панель в 320px
       уехала бы за левый край экрана. Растягиваем её на ширину шапки. */
    .bell-panel{ position:fixed; top: calc(var(--topbar-h) + 4px); left: var(--space-3); right: var(--space-3); width:auto; }
  }

  /* — Регистрация по приглашению: кто позвал — */
  .invite-from{ display:flex; align-items:center; gap: var(--space-2); font-size: var(--text-sm); color: var(--text-secondary); }
  .invite-from b{ color: var(--text-primary); }

  /* — Страница настроек — */
  .settings{ display:flex; flex-direction:column; gap: var(--space-8); max-width:760px; }
  .settings-card{
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md);
    padding: var(--space-5); display:flex; flex-direction:column; gap: var(--space-4);
  }
  .settings-row{
    display:flex; align-items:center; gap: var(--space-3); flex-wrap:wrap;
    padding-bottom: var(--space-4); border-bottom:1px solid var(--border-subtle);
  }
  .settings-row-text{ display:flex; flex-direction:column; gap:2px; flex:1; min-width:200px; }
  .settings-row-text b{ font-size: var(--text-md); }
  .settings-row-text span{ font-size: var(--text-xs); color: var(--text-tertiary); }
  /* Аватар в строке настроек (карточки «Аватар» и «Профиль Steam»). У
     .friend-avatar в макете нет своего размера — только внутри списков, —
     и без него плашка в строке сжималась до размера инициалов. */
  .settings-row .friend-avatar{
    width:56px; height:56px; flex:none; border-radius: var(--radius-md);
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size: var(--text-md);
    color: var(--text-primary);
  }
  .settings-form{ display:flex; flex-direction:column; gap: var(--space-3); align-items:flex-start; }
  .settings-form .field{ width:100%; }
  .field-row{ display:flex; gap: var(--space-2); align-items:stretch; }
  .field-row input{ flex:1; }
  .settings-note{
    font-size: var(--text-xs); color: var(--text-tertiary); max-width:70ch; line-height:1.5;
  }
  .checkbox-row{ display:flex; align-items:flex-start; gap: var(--space-3); cursor:pointer; }
  /* flex:none — иначе у строки с длинной подписью flex сжимал галочку, и
     в одном списке они выходили разного размера. */
  .checkbox-row input{ flex:none; margin:3px 0 0; width:16px; height:16px; accent-color: var(--accent); }
  .checkbox-row > span{ display:flex; flex-direction:column; gap:2px; }
  .checkbox-row b{ font-size: var(--text-sm); }
  .checkbox-row .helptext{ font-size: var(--text-2xs); color: var(--text-tertiary); }

  /* — Настройки: навигация справа —
       Две страницы («Аккаунт» и «Внешний вид профиля»), под текущей —
       якоря на её разделы. Колонка навигации липкая, поэтому сетке нужен
       align-items:start: растянутая на всю высоту колонка не прилипает.
       Якоря разделов отступают на высоту шапки и полосы вкладок, иначе
       заголовок уезжал бы под липкую шапку. */
  .settings-layout{
    display:grid; grid-template-columns: minmax(0,760px) 220px;
    gap: var(--space-8); align-items:start;
  }
  .settings-nav{
    grid-column:2; grid-row:1;
    position:sticky; top: calc(var(--topbar-h) + var(--tabbar-h) + var(--space-6));
    display:flex; flex-direction:column; gap: var(--space-1);
  }
  .settings-nav-item{
    display:block; padding: 7px var(--space-3); border-radius: var(--radius-sm);
    color: var(--text-secondary); font-size: var(--text-sm); font-weight:500;
  }
  .settings-nav-item:hover{ background: var(--surface-hover); color: var(--text-primary); }
  .settings-nav-item[aria-current="page"]{ background: var(--accent-soft); color: var(--accent-fg); }
  .settings-nav-sub{
    display:flex; flex-direction:column; gap:2px;
    margin: 0 0 var(--space-2) var(--space-3); padding-left: var(--space-3);
    border-left:1px solid var(--border-subtle);
  }
  .settings-nav-sub a{ font-size: var(--text-xs); color: var(--text-tertiary); padding: 3px 0; }
  .settings-nav-sub a:hover{ color: var(--text-primary); }
  .settings-nav-sub a.is-danger{ color: var(--status-dropped-fg); }
  .settings [id^="h-"]{ scroll-margin-top: calc(var(--topbar-h) + var(--tabbar-h) + var(--space-6)); }
  @media (max-width: 980px){
    /* Узко — навигация строкой над разделами, без якорей. */
    .settings-layout{ grid-template-columns: minmax(0,1fr); gap: var(--space-5); }
    .settings-nav{ grid-column:1; position:static; flex-direction:row; flex-wrap:wrap; }
    .settings-nav-sub{ display:none; }
  }

  /* — Красная зона: удаление аккаунта — */
  .danger-zone .block-head h2{ color: var(--status-dropped-fg); }
  .danger-zone .settings-card{
    border-color: var(--status-dropped-bd);
    background: linear-gradient(var(--status-dropped-bg), var(--status-dropped-bg)), var(--surface);
  }
  .danger-zone .settings-row{ border-bottom-color: var(--status-dropped-bd); }

  /* — Убрать игру из библиотеки —
       Последняя колонка строки: место под крестик резервируется всегда, иначе
       названия дёргались бы при наведении. Сам крестик виден только на строке
       под курсором и при фокусе с клавиатуры.

       Колонку добавляем только на широком экране: с 980px макет схлопывает
       строку до трёх колонок, и правка вне медиазапроса переехала бы поверх
       неё. Там крестика просто нет — удалять удобнее со страницы игры. */
  @media (min-width: 981px){
    /* 26px после названия — квадратик устройства (.row-device). */
    .game-row{ grid-template-columns: 34px 1fr 26px 96px 60px 88px 150px 22px; }
  }
  @media (max-width: 980px){
    .row-remove{ display:none; }
    .row-device{ display:none; }
    /* На узком экране макет схлопывает строку до трёх колонок — оценка
       уезжает вместе с полосой достижений, иначе она встала бы во вторую
       строку сетки под обложкой. */
    .row-rating{ display:none; }
  }
  .row-remove button{
    width:22px; height:22px; display:flex; align-items:center; justify-content:center;
    background:none; border:0; padding:0; cursor:pointer; border-radius: var(--radius-sm);
    color: var(--text-tertiary); opacity:0;
    transition: opacity .1s ease, color .1s ease, background-color .1s ease;
  }
  .row-remove button svg{ width:13px; height:13px; stroke:currentColor; fill:none; }
  .game-row:hover .row-remove button,
  .row-remove button:focus-visible{ opacity:1; }
  .row-remove button:hover{ color: var(--status-dropped-fg); background: var(--surface-hover); }

  /* — Своя оценка в строке библиотеки —
       Числом, а не кубками: пять кубков рядом с часами и полосой достижений
       превратили бы строку в кашу, а цвет тира тот же, что у кубков на
       странице игры, — оценка узнаётся по нему и в списке.
       «/10» остаётся приглушённой: красить надо само число. */
  .row-rating{
    display:flex; align-items:center; justify-content:flex-end; gap:3px;
    font-family: var(--font-mono); font-size: var(--text-xs);
    color: var(--text-secondary); white-space:nowrap;
  }
  .row-rating svg{ width:12px; height:12px; stroke:currentColor; fill:none; flex:none; }
  .row-rating .row-rating-max{ color: var(--text-tertiary); }
  .row-rating.tier-bronze{ color: var(--tier-bronze); }
  .row-rating.tier-silver{ color: var(--tier-silver); }
  .row-rating.tier-gold{ color: var(--tier-gold); }
  .row-rating.tier-platinum{ color: var(--tier-platinum); }

  /* Выбор файла аватара. Нативную кнопку внутри input[type=file] красит
     только ::file-selector-button — без этого правила посреди тёмной
     карточки стоит светлая системная плашка. */
  .field input[type="file"]{ padding: 7px 10px; cursor:pointer; }
  .field input[type="file"]::file-selector-button{
    margin-right: var(--space-3); padding: 5px 10px; cursor:pointer;
    font:inherit; color: var(--text-secondary); background: var(--surface-hover);
    border:1px solid var(--border-subtle); border-radius: var(--radius-sm);
  }
  .field input[type="file"]::file-selector-button:hover{ color: var(--text-primary); }

  /* Описание игры из IGDB. Ширина строки ограничена: блок занимает всю
     основную колонку, а сплошной текст на 900 px читается плохо. */
  /* — Подвал шапки игры —
       Строка цифр про тебя уехала в самый низ карточки. Блок полной
       ширины: .game-header — flex с переносом, и flex-basis:100%
       отправляет подвал на свою строку, не трогая раскладку обложки,
       названия и кольца. — */
  .game-header-foot{
    position:relative;
    flex-basis:100%; min-width:0;
    display:flex; flex-direction:column; gap: var(--space-4);
    padding-top: var(--space-4);
  }
  /* Разделитель — псевдоэлементом, а не border-top: рамка идёт на всю
     ширину, не глядя на padding-right, и перечёркивала четверть круга
     прогресса в углу. Линия обрывается там же, где отступ под угол. */
  .game-header-foot::before{
    content:""; position:absolute; top:0; left:0; right:0;
    border-top:1px solid var(--border-subtle);
  }

  /* — «Об игре» под годом и жанрами —
       Отступ сверху больше собственного gap колонки: описание — это уже
       не подпись к названию, а свой блок. Обложку при этом прижимаем к
       верху: с длинным описанием колонка становится высокой, и обложка,
       которую .game-header центрирует, повисала бы посреди карточки.
       Кольцо достижений оставляем по центру — сверху его место занято
       приколотой к углу «Оценкой сайта». — */
  .game-about-block{
    display:flex; flex-direction:column; gap: var(--space-2);
    margin-top: var(--space-2);
  }
  .game-about-block h2{ font-size: var(--text-md); }
  .game-header-cover-col{ align-self: flex-start; }

  /* — Прогресс достижений: четверть круга в углу карточки —
       Кольцо стояло в потоке справа и отъедало ширину у описания. В углу
       оно ничего не занимает: absolute, мышь не ловит (кроме подсказки со
       счётчиком), и не спорит с «Оценкой сайта» в противоположном углу.

       Дуга нарисована в координатах 120×120 с углом в точке (120,120), так
       что поворачивать SVG, как круглое кольцо, не нужно. Заливка идёт от
       нижнего края к правому: штрих начинается с начала пути. — */
  .ach-corner{
    /* Отступ от края: концы дуги лежат ровно на краях своей коробки, а
       круглый колпачок штриха выходит за них ещё на полтолщины. Без
       отступа он торчал бы за карточку. */
    position:absolute; right:10px; bottom:10px;
    width:116px; height:116px; pointer-events:none;
  }
  .ach-corner svg{ width:100%; height:100%; overflow:visible; }
  .quarter-track{ fill:none; stroke: var(--border); stroke-width:8; }
  .quarter-fill{
    fill:none; stroke: var(--accent); stroke-width:8; stroke-linecap:round;
  }
  .quarter-pct{
    fill: var(--text-primary);
    font-family: var(--font-mono); font-weight:700; font-size:25px;
  }
  .quarter-count{
    fill: var(--text-tertiary);
    font-family: var(--font-mono); font-weight:600; font-size:13px;
  }
  /* Сотня — платиновая: тот же цвет, что у рамки карточки и пилюли «100%». */
  .game-header[data-perfect] .quarter-fill{ stroke: var(--status-100); }

  /* — Знак Steam шире, чем выше —
       В квадратной коробке он вписывается по ширине, и на 10px от него
       остаётся 7,6px по высоте — рядом с текстом это уже пыль. Мелким
       местам добавлено по паре пикселей; ширина строки от этого не едет,
       коробка и так была в потоке. — */
  .cover .cover-badge svg, .row-platform svg{ width:13px; height:13px; }

  /* — Плашка платформы стала ссылкой на витрину —
       Значок подрос с 11 до 13px: на 11 он читался кляксой рядом со
       словом, а не значком. Цвет меняется только на наведении, чтобы в
       строке с годом и жанрами ссылка не кричала. — */
  .platform-tag svg{ width:13px; height:13px; }
  a.platform-tag:hover{ color: var(--accent-fg); }

  /* — Платформы в шапке профиля — своей строкой над датой регистрации:
       сейчас там только Steam, потом встанут и другие. — */
  .profile-platforms{ display:flex; flex-wrap:wrap; align-items:center; gap: var(--space-3); }

  /* — Соцсети в шапке профиля — строкой под платформами. Плашка Discord —
       кнопка (копирует ник), а выглядеть должна как соседние плашки-ссылки:
       без фона и рамки кнопки, шрифт и цвет строки. — */
  button.platform-tag{ font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
  button.platform-tag:hover{ color: var(--accent-fg); }

  /* — «Скопировано» справа от ника Discord (static/js/copy.js, data-toast) —
       Плашка всплывает из-за кнопки, держится и гаснет; ник не меняется.
       Без движения — если в системе просили меньше анимации. — */
  button.platform-tag[data-toast]{ position:relative; }
  /* «Скопировано» у ника в правом углу шапки всплывает влево — справа
     край карточки. */
  .profile-socials .copy-toast{ left:auto; right:calc(100% + 8px); }
  .copy-toast{
    position:absolute; left:calc(100% + 8px); top:50%; z-index:5;
    white-space:nowrap; pointer-events:none;
    padding: 2px 8px; border-radius: var(--radius-full);
    font-size: var(--text-2xs); font-weight:600; line-height:1.6;
    color: var(--accent-fg); background: var(--accent-soft); border:1px solid var(--accent-border);
    animation: copy-toast 1.6s ease forwards;
  }
  @keyframes copy-toast{
    0%  { opacity:0; transform: translate(-8px, -50%); }
    15% { opacity:1; transform: translate(0, -50%); }
    75% { opacity:1; transform: translate(0, -50%); }
    100%{ opacity:0; transform: translate(6px, -50%); }
  }
  @media (prefers-reduced-motion: reduce){
    @keyframes copy-toast{
      0%, 75% { opacity:1; transform: translate(0, -50%); }
      100%    { opacity:0; transform: translate(0, -50%); }
    }
  }

  /* Строка цифр и разделитель над ней не должны заезжать под угол. */
  .game-header-foot{ padding-right:132px; }
  .game-header:has(.ach-corner) .game-header-foot::before{ right:132px; }

  @media (max-width: 620px){
    /* Меньше 96px счётчик под процентом перестаёт читаться, а не просто
       мельчает: обе строки уезжают вниз вместе с коробкой. */
    .ach-corner{ right:8px; bottom:8px; width:96px; height:96px; }
    .game-header-foot{ padding-right:108px; }
    .game-header:has(.ach-corner) .game-header-foot::before{ right:108px; }
  }
  .game-about{
    margin:0; padding:0;
    color: var(--text-secondary); font-size:.9rem; line-height:1.65; max-width:78ch;
  }

  /* ============ Рулетка на странице подборок ============
     Колесо рисуется одним SVG в координатах 240×240 и масштабируется
     шириной .wheel-box — никаких размеров в пикселях внутри. Цвета
     секторов — палитра плашек обложек из токенов, восемь штук по кругу. */
  .roulette-filters{
    display:flex; flex-wrap:wrap; gap: var(--space-3); align-items:flex-end;
  }
  .roulette-pools{ flex:1 1 280px; align-items:center; }
  .roulette-filters .field{ min-width:150px; }
  /* Два числовых поля в строку: в 150px четыре цифры и стрелки не влезают. */
  .roulette-filters .roulette-years{ min-width:200px; }

  /* Пилюля-переключатель: тот же .status-badge из макета, но с радиокнопкой
     внутри. Саму кнопку убираем с глаз, а рамку фокуса возвращаем на
     пилюлю — иначе с клавиатуры не видно, что выбрано. */
  label.status-badge{ cursor:pointer; }
  label.status-badge:not(.is-active){ opacity:.55; }
  label.status-badge:hover{ filter:brightness(1.15); }
  label.status-badge input{ appearance:none; width:0; height:0; margin:0; border:0; }
  label.status-badge:has(input:focus-visible){ outline:2px solid var(--accent); outline-offset:2px; }

  /* Колесо — в средней колонке, карточка выпавшей игры в правой, левая
     пустая: боковые колонки равны, поэтому барабан стоит ровно посередине
     блока и не съезжает вбок, когда карточка появляется. Высота колонки с
     карточкой задана и равна колесу — иначе строка сетки росла бы в момент
     выпадения игры и блок подскакивал. 410px — карточка (352) плюс кнопка
     и отступ, с запасом на игру без достижений. */
  .roulette-stage{
    display:grid; grid-template-columns: 1fr auto 1fr;
    align-items:center; gap: var(--space-6);
  }

  .wheel-box{ grid-column:2; position:relative; width:min(410px, 62vw); aspect-ratio:1; }
  /* Пустой набор занимает место колеса, чтобы блок не менял размер. */
  .wheel-box-empty{ display:flex; align-items:center; justify-content:center; }
  .wheel{ width:100%; height:auto; transform-origin:50% 50%; transition: transform 4.2s cubic-bezier(.16,.84,.26,1); }
  /* Человеку, который выключил анимации, колесо доворачивается сразу;
     скрипт в этом случае и карточку показывает без задержки. */
  @media (prefers-reduced-motion: reduce){
    .wheel{ transition:none; }
  }
  /* Границы клиньев рисует .wheel-edge поверх обложки, плашке обводка не
     нужна — иначе под полупрозрачной картинкой проступала бы вторая линия. */
  .wheel-slice{ stroke:none; }
  .wheel-slice.t1{ fill: var(--cover-1); }
  .wheel-slice.t2{ fill: var(--cover-2); }
  .wheel-slice.t3{ fill: var(--cover-3); }
  .wheel-slice.t4{ fill: var(--cover-4); }
  .wheel-slice.t5{ fill: var(--cover-5); }
  .wheel-slice.t6{ fill: var(--cover-6); }
  .wheel-slice.t7{ fill: var(--cover-7); }
  .wheel-slice.t8{ fill: var(--cover-8); }
  /* Размер подписи — в координатах viewBox, не в пикселях экрана: SVG
     масштабируется целиком, и на широком колесе текст растёт вместе с ним. */
  /* Обложка в секторе — фон, а не картинка: приглушена и не перехватывает
     клики по колесу. Грань сектора рисуется поверх неё отдельным контуром,
     иначе картинка закрывала бы линию между клиньями. */
  .wheel-cover{
    opacity:.36; pointer-events:none;
    /* Светлые обложки без этого выбеливают свой клин и съедают подпись;
       тёмные от того же коэффициента почти не меняются. */
    filter: brightness(.78) saturate(.9);
    transition: opacity .12s ease, filter .12s ease;
  }
  /* Контур обрезан по своему же сектору, поэтому наружу торчит только
     внутренняя половина штриха. Это не косметика: соседний клин рисуется
     позже и закрывал бы обводку подсвеченного сектора с одной стороны —
     подсветка выходила бы разной толщины слева и справа. Ширина взята
     вдвое, чтобы видимая половина осталась прежней. */
  .wheel-edge{
    fill:none; stroke: var(--bg); stroke-width:3;
    transition: stroke .12s ease, stroke-width .12s ease;
  }

  /* Наведение на сектор: обводка акцентом, обложка ярче. Ловит вся группа —
     плашка, картинка и подпись, — поэтому клин подсвечивается целиком. */
  .wheel-sector:hover .wheel-edge{ stroke: var(--accent-fg); stroke-width:6; }
  .wheel-sector:hover .wheel-cover{ opacity:.55; filter: brightness(1) saturate(1); }
  .wheel-sector:hover .wheel-slice{ filter: brightness(1.2); }
  .wheel-label{
    font-family: var(--font-ui); font-size:8px; font-weight:600;
    fill: var(--text-primary); pointer-events:none;
    /* Тёмная обводка под буквами: поверх светлого места обложки белая
       подпись иначе теряется. paint-order кладёт обводку под заливку. */
    paint-order:stroke; stroke: rgba(0,0,0,.6); stroke-width:2px; stroke-linejoin:round;
  }
  .wheel-hole{ fill: var(--bg-elevated); stroke: var(--border-strong); }

  .wheel-pointer{
    position:absolute; top:-4px; left:50%; transform:translateX(-50%); z-index:2;
    width:0; height:0;
    border-left:9px solid transparent; border-right:9px solid transparent;
    border-top:18px solid var(--accent-fg);
    filter: drop-shadow(var(--shadow-sm));
  }
  .wheel-hub{
    position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); z-index:2;
    width:23%; height:23%; border-radius: var(--radius-full);
    background: var(--surface); color: var(--text-primary);
    border:1px solid var(--border-strong); box-shadow: var(--shadow-md);
    font-family:inherit; font-size: var(--text-2xs); font-weight:700;
    letter-spacing:.06em; text-transform:uppercase; cursor:pointer;
  }
  .wheel-hub:hover{ background: var(--surface-hover); color: var(--accent-fg); border-color: var(--accent-border); }

  /* Список выпавшего слева от колеса. Ширина та же, что у колонки с
     карточкой: боковые колонки сетки должны быть равны, иначе колесо
     перестанет стоять ровно посередине. Высота ограничена высотой колеса
     по той же причине, что и справа, — блок не должен расти. */
  .roulette-history{
    grid-column:1; width:182px; justify-self:end;
    max-height:410px; overflow:hidden;
    display:flex; flex-direction:column; gap: var(--space-2);
  }
  .roulette-history h3{ font-size: var(--text-sm); }
  .roulette-history .recent-row b{ font-size: var(--text-xs); }

  .roulette-prizes{
    grid-column:3; width:182px; min-height:410px;
    display:flex; flex-direction:column; justify-content:center; gap: var(--space-4);
  }
  /* Узкий экран: колонки в столбик, колесо сверху. Место под карточку тут
     не резервируем — на телефоне пустая треть экрана хуже, чем сдвиг. */
  @media (max-width: 900px){
    .roulette-stage{ grid-template-columns:1fr; justify-items:center; }
    .wheel-box, .roulette-prizes, .roulette-history{ grid-column:auto; justify-self:center; }
    .roulette-prizes{ min-height:0; }
    /* В столбик история уезжает вниз: сверху нужен барабан, а не список
       того, что выпало в прошлый раз. */
    .wheel-box{ order:1; }
    .roulette-prizes{ order:2; }
    .roulette-history{ order:3; max-height:none; }
  }
  .roulette-prize{ display:flex; flex-direction:column; gap: var(--space-3); align-items:flex-start; }
  /* Свой display перебивает браузерное [hidden]{display:none}: без этой
     строки на странице висят сразу все карточки барабана, а не выпавшая. */
  .roulette-prize[hidden]{ display:none; }
  .roulette-prize .game-card{ width:172px; }

  /* — Страница «Статистика»: гистограммы по месяцам.
       Цвет у каждого ряда свой и по смыслу: пройденные — цветом статуса
       «Пройдено», опыт — золотом трофейных тиров, достижения — акцентом.
       Ряд на графике один, поэтому легенды нет — ряд называет заголовок.
       Столбик ужат до 86% высоты поля: сверху остаётся место под число. — */
  /* Четыре гистограммы — сеткой по две в ряд, уже 980px — в столбик.
     Карточки в ряду прижаты к низу секции (margin-top:auto): заголовок с
     подписью «всего за год» может переноситься, и без этого карточки
     соседей стояли бы на разной высоте. */
  .mchart-grid{ display:grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: var(--space-8) var(--space-5); }
  .mchart-grid > section.block > .mchart,
  .mchart-grid > section.block > .empty-state{ margin-top:auto; }
  @media (max-width: 980px){
    .mchart-grid{ grid-template-columns: minmax(0,1fr); }
  }
  .mchart{
    --bar: var(--accent);
    display:grid; grid-template-columns: repeat(12, minmax(0,1fr)); gap:2px;
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-3) var(--space-2);
  }
  .mchart-xp{ --bar: var(--tier-gold); }
  .mchart-launches{ --bar: var(--status-playing); }
  .mchart-completed{ --bar: var(--status-completed); }
  .mchart-col{
    display:flex; flex-direction:column; gap: var(--space-2);
    border-radius: var(--radius-xs); outline:none; cursor:default;
  }
  .mchart-col:focus-visible{ box-shadow: 0 0 0 2px var(--accent-border); }
  .mchart-plot{
    position:relative; height:110px;
    border-bottom:1px solid var(--border-strong);
  }
  .mchart-bar{
    position:absolute; left:14%; right:14%; bottom:0;
    height: calc(var(--h) * .86); min-height:2px;
    background: var(--bar); border-radius: 4px 4px 0 0;
    transition: filter .12s ease;
  }
  /* Столбик запусков сложен из кусков по играм. Куски идут сверху вниз в
     том же порядке, что строки в подсказке, и разделены линией фона, а не
     зазором: зазор на низком столбике съедал бы сам кусок. */
  .mchart-bar.is-split{ background:none; display:flex; flex-direction:column; overflow:hidden; }
  .mchart-seg{ flex:none; }
  .mchart-seg + .mchart-seg{ border-top:1px solid var(--surface); }

  /* Подсказка со списком игр: всплывает по наведению и по фокусу с
     клавиатуры. Отсчитывается от верха поля графика и растёт вниз, а не
     вверх над столбиком: список из восьми игр, поднятый над карточкой,
     уезжал за верх экрана. У крайних месяцев прижимается к своему краю —
     иначе половина уходила бы за карточку. */
  .mchart-col{ position:relative; }
  .mchart-tip{
    display:none; position:absolute; z-index:20;
    left:50%; transform:translateX(-50%); top:0;
    min-width:210px; max-width:280px;
    flex-direction:column; gap: var(--space-2);
    padding: var(--space-3);
    background: var(--bg-elevated); border:1px solid var(--border-strong);
    border-radius: var(--radius-md); box-shadow: var(--shadow-md);
    text-align:left; cursor:default;
  }
  .mchart-col:hover .mchart-tip, .mchart-col:focus-visible .mchart-tip{ display:flex; }
  .mchart-col:first-child .mchart-tip{ left:0; transform:none; }
  .mchart-col:last-child .mchart-tip{ left:auto; right:0; transform:none; }
  .mchart-tip-head{ font-size: var(--text-xs); color: var(--text-primary); }
  .mchart-tip-list{ display:flex; flex-direction:column; gap:5px; }
  .mchart-tip-row{
    display:grid; grid-template-columns: 8px 1fr auto; align-items:center; gap: var(--space-2);
    font-size: var(--text-2xs); color: var(--text-secondary);
  }
  .mchart-tip-row .dot{ width:8px; height:8px; border-radius:50%; }
  /* У опыта точек нет — цвет там ничего не значит, и колонка под них не нужна. */
  .mchart-tip-row.no-dot{ grid-template-columns: 1fr auto; }
  .mchart-tip-title{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .mchart-tip-num{ font-family: var(--font-mono); color: var(--text-tertiary); }
  .mchart-tip-more{ font-size: var(--text-2xs); color: var(--text-tertiary); }
  .mchart-col:hover .mchart-bar, .mchart-col:focus-visible .mchart-bar{ filter:brightness(1.2); }
  .mchart-value{
    position:absolute; left:0; right:0; bottom: calc(var(--h) * .86 + 4px);
    text-align:center; white-space:nowrap;
    font-family: var(--font-mono); font-size: var(--text-2xs); color: var(--text-secondary);
    opacity:0; transition: opacity .12s ease;
  }
  .mchart-col.is-peak .mchart-value,
  .mchart-col:hover .mchart-value,
  .mchart-col:focus-visible .mchart-value{ opacity:1; }
  .mchart-col:hover .mchart-value, .mchart-col:focus-visible .mchart-value{ color: var(--text-primary); }
  .mchart-note{ font-size: var(--text-xs); color: var(--text-tertiary); max-width:70ch; margin:0; }
  .mchart-month{
    text-align:center; font-size: var(--text-2xs); color: var(--text-tertiary);
    text-transform: capitalize; white-space:nowrap; overflow:hidden;
  }
  @media (max-width: 620px){
    .mchart{ padding: var(--space-3) var(--space-2) var(--space-2); gap:1px; position:relative; }
    .mchart-plot{ height:100px; }
    /* На телефоне столбик уже подсказки, и центровать её по нему негде:
       подсказка растягивается на всю карточку графика. Для этого точкой
       отсчёта становится сама карточка, а не столбик. */
    .mchart-col{ position:static; }
    /* Правила для крайних месяцев специфичнее — их тоже надо перебить,
       иначе январь и декабрь останутся с шириной по содержимому. */
    .mchart-tip,
    .mchart-col:first-child .mchart-tip,
    .mchart-col:last-child .mchart-tip{
      left: var(--space-2); right: var(--space-2); transform:none;
      min-width:0; max-width:none;
    }
  }

  /* — Внешний вид профиля: выбор любимых игр —
       Полей под игры в разметке всегда шесть, лишние прячутся по выбранному
       количеству через :has — без скрипта. Браузер без :has покажет все
       шесть, а сервер всё равно возьмёт только первые N. */
  .fav-count{ max-width:240px; }
  .fav-slots{
    display:grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: var(--space-3); width:100%;
  }
  .fav-picker:has(select[name="count"] option[value="1"]:checked) .fav-slot:nth-child(n+2),
  .fav-picker:has(select[name="count"] option[value="2"]:checked) .fav-slot:nth-child(n+3),
  .fav-picker:has(select[name="count"] option[value="3"]:checked) .fav-slot:nth-child(n+4),
  .fav-picker:has(select[name="count"] option[value="4"]:checked) .fav-slot:nth-child(n+5),
  .fav-picker:has(select[name="count"] option[value="5"]:checked) .fav-slot:nth-child(n+6){ display:none; }
  .block-head a.hint:hover{ color: var(--text-secondary); }

  /* — Таблица лидеров —
       Сетка, а не <table>: строка целиком — ссылка на профиль, а <a>
       вокруг <tr> не бывает. Роли table/row/cell возвращают семантику.
       Места 1–3 — цвета кубков из токенов тиров. */
  .leader-list{
    display:flex; flex-direction:column;
    background: var(--surface); border:1px solid var(--border);
    border-radius: var(--radius-md); overflow:hidden;
  }
  .leader-row{
    display:grid;
    grid-template-columns: 40px minmax(0,1fr) 72px 100px 72px 72px 72px;
    align-items:center; gap: var(--space-3);
    padding: var(--space-2) var(--space-4);
    border-bottom:1px solid var(--border-subtle);
  }
  /* В периоде нет колонки часов: она последняя. */
  .leader-list.is-period .leader-row{
    grid-template-columns: 40px minmax(0,1fr) 72px 100px 72px 72px;
  }
  .leader-row:last-child{ border-bottom:none; }
  a.leader-row{ color:inherit; }
  a.leader-row:hover{ background: var(--surface-hover); }
  .leader-row.is-me{ background: var(--accent-soft); }
  .leader-head{
    font-size: var(--text-2xs); color: var(--text-tertiary);
    text-transform: uppercase; letter-spacing:.04em; font-weight:600;
    padding-top: var(--space-3); padding-bottom: var(--space-3);
  }
  .leader-head > span:nth-child(n+3){ text-align:right; }
  .leader-head .is-sorted{ color: var(--accent-fg); }
  .leader-rank{
    font-family: var(--font-mono); font-weight:700; font-size: var(--text-sm);
    color: var(--text-tertiary); text-align:center;
  }
  .leader-row.rank-1 .leader-rank{ color: var(--tier-gold); }
  .leader-row.rank-2 .leader-rank{ color: var(--tier-silver); }
  .leader-row.rank-3 .leader-rank{ color: var(--tier-bronze); }
  .leader-player{ display:flex; align-items:center; gap: var(--space-3); min-width:0; }
  .leader-player .friend-avatar{
    width:36px; height:36px; flex:none; border-radius: var(--radius-sm);
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size:10.5px;
    color: var(--text-primary);
  }
  .leader-name{
    font-size: var(--text-sm); font-weight:600;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .leader-you{
    flex:none; font-size: var(--text-2xs); color: var(--accent-fg);
    border:1px solid var(--accent-border); border-radius: var(--radius-full);
    padding: 0 var(--space-2);
  }
  .leader-num{
    font-family: var(--font-mono); font-size: var(--text-sm);
    color: var(--text-secondary); text-align:right; white-space:nowrap;
  }
  .leader-num.is-sorted{ color: var(--text-primary); font-weight:700; }
  .leader-label{ display:none; }
  .leader-scope{
    display:flex; flex-wrap:wrap; justify-content:space-between; gap: var(--space-2);
  }
  .leader-note{ font-size: var(--text-xs); color: var(--text-tertiary); }
  .leader-records a{ color:inherit; }
  .leader-records a:hover{ color: var(--accent-fg); }
  .leader-records .leader-record-player{
    margin-top:auto; padding-top: var(--space-2);
    font-size: var(--text-xs); font-weight:600; color: var(--accent-fg);
  }
  .leader-gap{
    text-align:center; color: var(--text-tertiary);
    padding: var(--space-1); border-bottom:1px solid var(--border-subtle);
  }
  @media (max-width: 760px){
    /* На узком экране семи колонок не уместить: место и игрок — первой
       строкой, числа — по три в ряд, каждое со своей подписью. */
    .leader-head{ display:none; }
    .leader-row,
    .leader-list.is-period .leader-row{
      grid-template-columns: 28px repeat(3, minmax(0,1fr));
      row-gap: var(--space-2); column-gap: var(--space-2);
      padding: var(--space-3);
    }
    .leader-player{ grid-column: 2 / -1; }
    .leader-num{ text-align:left; display:flex; flex-direction:column; gap:2px; }
    .leader-num:nth-child(3),
    .leader-num:nth-child(6){ grid-column:2; }
    .leader-label{
      display:block; font-family: var(--font-ui); font-size: var(--text-2xs);
      color: var(--text-tertiary); font-weight:400;
      overflow:hidden; text-overflow:ellipsis;
    }
  }

  /* — Страница 404: EmptyState с предупреждением — */
  .empty-state.is-warning{ border-style:solid; }
  .empty-state.is-warning .icon-wrap{ background: var(--status-dropped-bg); border-color: var(--status-dropped-bd); }
  .empty-state.is-warning .icon-wrap svg{ stroke: var(--status-dropped-fg); }
  .error-code{
    font-family: var(--font-mono); font-size: var(--text-2xl); font-weight:700;
    color: var(--text-primary); line-height:1;
  }

  /* — Бегущая строка в шапке (apps/siteadmin): текст из «Администрирования
     сайта» пиксельным шрифтом. На широком экране строка — слой под
     элементами шапки: у лого, поиска и блока пользователя фон шапки и по
     полосе того же цвета слева и справа, поэтому текст виден только в
     промежутках между ними. Полосы — тенью со сдвигом, а не с растяжкой:
     растяжка вылезла бы вниз на вкладки. Слой начинается и кончается у
     внутренних полей шапки, иначе текст мелькал бы у самых краёв экрана.

     На телефоне промежутков нет, а при «меньше движения» бежать нельзя —
     там это неподвижная полоса под шапкой с многоточием, и шапка выше на её
     высоту. Высота идёт через --topbar-h: на него завязаны липкие вкладки,
     панель колокольчика и якоря настроек. 56px — высота шапки из макета.

     Скорость постоянная: длительность прохода ставит скрипт в base.html
     (длина пути / 70 px в секунду); 30s ниже — на случай без JS.
     Press Start 2P — с кириллицей; размер 10px выбран сравнением 8/10/12/16:
     8 мелко, 12 и 16 спорят с поиском. — */
  :root{ --font-pixel: "Press Start 2P", var(--font-mono); --ticker-h: 22px; }
  .ticker{ position:absolute; inset:0; z-index:0; overflow:hidden; display:flex; align-items:center; }
  .ticker-track{
    flex:none; padding-left:100%; white-space:nowrap;
    font-family: var(--font-pixel); font-size:10px; line-height:1;
    color: var(--accent-fg);
    animation: ticker-run 30s linear infinite;
  }
  .ticker:hover .ticker-track{ animation-play-state:paused; }
  @keyframes ticker-run{ to{ transform: translateX(-100%); } }

  @media (min-width: 621px) and (prefers-reduced-motion: no-preference){
    .ticker{ inset:0 var(--space-6); }
    :where(.has-ticker .topbar > .brand, .has-ticker .topbar > .search,
           .has-ticker .topbar > .account, .has-ticker .topbar > .topbar-actions,
           .has-ticker .topbar > .btn-row){
      position:relative; z-index:1; background: var(--bg);
      box-shadow: calc(-1 * var(--space-4)) 0 0 var(--bg), var(--space-4) 0 0 var(--bg);
    }
  }
  @media (max-width: 620px), (prefers-reduced-motion: reduce){
    .has-ticker{ --topbar-h: calc(56px + var(--ticker-h)); }
    .has-ticker .topbar{ padding-bottom: var(--ticker-h); }
    .ticker{
      inset:auto 0 0 0; height: var(--ticker-h);
      background: var(--bg-elevated); border-top:1px solid var(--border-subtle);
    }
  }
  @media (prefers-reduced-motion: reduce){
    .ticker-track{
      flex:1 1 auto; max-width:100%; padding-left: var(--space-3);
      overflow:hidden; text-overflow:ellipsis; animation:none;
    }
  }

  /* — Бегущая строка в «Администрировании сайта»: группы по языкам, поле
     строки с крестиком, «+» под группой (static/js/ticker_admin.js) и
     переключатель «Рандомно». Переключатель — обычный чекбокс с
     role="switch", нарисованный дорожкой с ползунком. — */
  .ticker-form{ align-items:stretch; }
  .ticker-lang{ border:0; margin:0; padding:0; display:flex; flex-direction:column; gap: var(--space-2); }
  .ticker-lang legend{
    padding:0 0 var(--space-2); display:flex; align-items:baseline; gap: var(--space-2);
    font-size: var(--text-2xs); text-transform:uppercase; letter-spacing:.07em; color: var(--text-tertiary);
  }
  .ticker-lang legend b{ font-weight:600; color: var(--text-secondary); }
  .ticker-lines{ display:flex; flex-direction:column; gap: var(--space-2); }
  .ticker-line{ display:flex; align-items:center; gap: var(--space-2); }
  .ticker-line input{
    flex:1 1 auto; min-width:0; background: var(--surface-sunken); color: var(--text-primary);
    border:1px solid var(--border); border-radius: var(--radius-sm);
    padding: 9px 11px; font-family:inherit; font-size: var(--text-sm);
  }
  .ticker-line input:focus{ outline:none; border-color: var(--accent-border); background: var(--bg-elevated); }
  .ticker-add{ align-self:flex-start; border-color: var(--border); border-style:dashed; }
  /* Срок строки: подпись «до» / «истекла» и datetime-local. Истёкшая
     строка приглушена — на сайте её уже нет. */
  .ticker-expires{ display:flex; align-items:center; gap: var(--space-2); flex:none; }
  .ticker-expires span{ font-size: var(--text-2xs); color: var(--text-tertiary); white-space:nowrap; }
  .ticker-line .ticker-expires input{ flex:none; width:auto; }
  .ticker-line.is-expired > input[type="text"]{ color: var(--text-tertiary); text-decoration: line-through; }
  .ticker-line.is-expired .ticker-expires span{ color: var(--status-dropped-fg); }
  @media (max-width: 620px){
    .ticker-line{ flex-wrap:wrap; }
    .ticker-line > input[type="text"]{ flex-basis:100%; }
  }

  .switch-row{ display:flex; align-items:flex-start; gap: var(--space-3); cursor:pointer; }
  .switch-row > span{ display:flex; flex-direction:column; gap:2px; }
  .switch-row b{ font-size: var(--text-sm); }
  .switch-row .helptext{ font-size: var(--text-2xs); color: var(--text-tertiary); }
  .switch-row input{
    appearance:none; flex:none; position:relative; margin:1px 0 0;
    width:34px; height:20px; border-radius: var(--radius-full);
    background: var(--surface-sunken); border:1px solid var(--border-strong);
    cursor:pointer; transition: background .15s, border-color .15s;
  }
  .switch-row input::before{
    content:""; position:absolute; top:2px; left:2px; width:14px; height:14px;
    border-radius: var(--radius-full); background: var(--text-tertiary);
    transition: transform .15s, background .15s;
  }
  .switch-row input:checked{ background: var(--accent); border-color: var(--accent); }
  .switch-row input:checked::before{ transform: translateX(14px); background: var(--bg); }
  .switch-row input:focus-visible{ outline:2px solid var(--accent-border); outline-offset:2px; }

  /* — Расход Steam API на странице администрирования (integrations/steam/usage.py).
     Полоса — из макета (.progress-track/.progress-fill), таблицы — простые. — */
  .usage-today{ display:flex; flex-direction:column; gap: var(--space-2); }
  .usage-today b{ font-size: var(--text-md); }
  .usage-table{ width:100%; border-collapse:collapse; font-size: var(--text-sm); }
  .usage-table th, .usage-table td{
    padding: var(--space-1) 0; border-bottom:1px solid var(--border-subtle); text-align:left;
  }
  .usage-table th{ font-weight:500; font-size: var(--text-xs); color: var(--text-tertiary); }
  .usage-table .num{ text-align:right; font-variant-numeric: tabular-nums; }

  /* — Подвал (base.html, footer.site-footer): слева столбиком подпись
     источников данных, каждый источник своей строкой, рядом таким же
     столбиком — правовые документы и оговорка о Valve. После контента, в
     левом нижнем углу страницы. Прикреплять подпись к углу окна
     (position:fixed) пробовали — она ехала вместе с прокруткой поверх
     страницы, это мешало. — */
  .site-footer{
    display:flex; flex-wrap:wrap; align-items:flex-end; gap: var(--space-4) var(--space-10);
    padding: 0 var(--space-6) var(--space-6);
    font-size: var(--text-2xs); color: var(--text-tertiary);
  }
  .source-credits, .legal-links{
    display:flex; flex-direction:column; align-items:flex-start; gap: var(--space-1);
  }
  .valve-note{ max-width:60ch; }
  .legal-links a, .valve-note a{ color: var(--text-secondary); text-decoration:none; }
  .legal-links a:hover, .valve-note a:hover{ color: var(--accent-fg); text-decoration:underline; }
  /* Короткая страница: подпись прижата к низу окна, а не висит под контентом. */
  .shell > .main{ flex:1 0 auto; }
  .source-credits a{ color: var(--text-secondary); text-decoration:none; }
  .source-credits a:hover{ color: var(--accent-fg); text-decoration:underline; }
  @media (max-width: 620px){
    .site-footer{ padding: 0 var(--space-4) var(--space-4); }
  }

  /* — Шрифты со своего сервера (static/fonts) вместо Google Fonts: иначе IP
     каждого посетителя уходил бы в Google (pravovoe.md). Файлы — из пакетов
     Fontsource (Golos Text и JetBrains Mono — переменные, один файл на все
     начертания), лицензии OFL лежат рядом. Имена семейств те же, что были у
     Google, поэтому токены --font-* не менялись. Подмножества — кириллица и
     латиница, как отдавал Google для этого набора. — */
  @font-face{ font-family:"Golos Text"; font-style:normal; font-display:swap; font-weight:400 900;
    src:url("../fonts/golos-text-cyrillic-wght-normal.2b8fbbb33a14.woff2") format("woff2"); unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116; }
  @font-face{ font-family:"Golos Text"; font-style:normal; font-display:swap; font-weight:400 900;
    src:url("../fonts/golos-text-latin-wght-normal.f57df9832ab8.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:"JetBrains Mono"; font-style:normal; font-display:swap; font-weight:100 800;
    src:url("../fonts/jetbrains-mono-cyrillic-wght-normal.615bf869ebeb.woff2") format("woff2"); unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116; }
  @font-face{ font-family:"JetBrains Mono"; font-style:normal; font-display:swap; font-weight:100 800;
    src:url("../fonts/jetbrains-mono-latin-wght-normal.b058178d7f30.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:"Press Start 2P"; font-style:normal; font-display:swap; font-weight:400;
    src:url("../fonts/press-start-2p-cyrillic-400-normal.2b2262225fd8.woff2") format("woff2"); unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116; }
  @font-face{ font-family:"Press Start 2P"; font-style:normal; font-display:swap; font-weight:400;
    src:url("../fonts/press-start-2p-latin-400-normal.5c7e04d0202b.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; }

  /* — Правовые документы (apps/legal, templates/legal). Глобальный ul в
     макете без маркеров — в тексте документа они нужны. — */
  .legal-doc{ display:flex; flex-direction:column; gap: var(--space-5); max-width:760px; line-height:1.6; }
  .legal-doc h1{ font-size: var(--text-xl); }
  .legal-doc h2{ font-size: var(--text-md); margin-bottom: var(--space-2); }
  .legal-doc p + p{ margin-top: var(--space-2); }
  .legal-doc ul{ list-style:disc; padding-left: var(--space-6); display:flex; flex-direction:column; gap: var(--space-1); }
  .legal-doc code{ font-family: var(--font-mono); font-size: var(--text-sm); }
  .legal-edition{ font-size: var(--text-xs); color: var(--text-tertiary); }
  .legal-accept{ margin-top: var(--space-2); }

  /* — Заявка на регистрацию (accounts/register.html, apps/siteadmin). Поле-
     ловушка для ботов .hp убрано за край экрана, а не display:none: часть
     ботов пропускает скрытые поля, а мимо уехавшего за край проходит. — */
  .hp{ position:absolute; left:-10000px; width:1px; height:1px; overflow:hidden; }

  /* — Фильтры страницы поиска (catalog/search.html): карточка в правой
     колонке .page-layout, того же вида, что «Статус у игроков». Подписи
     групп — <legend>, поэтому оформление .field > label повторено для них. — */
  .search-filters{
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md);
    padding: var(--space-4); display:flex; flex-direction:column; gap: var(--space-4);
  }
  .search-filters fieldset{ border:0; margin:0; padding:0; min-width:0; }
  .search-filters legend{
    padding:0; margin-bottom:5px;
    font-size: var(--text-2xs); font-weight:600; text-transform:uppercase; letter-spacing:.07em; color: var(--text-tertiary);
  }
  .search-filters .block-head .hint:hover{ color: var(--text-primary); }
  .range-row{ display:flex; align-items:center; gap: var(--space-2); color: var(--text-tertiary); }
  .range-row input{ min-width:0; flex:1; }
  .genre-checks{ display:flex; flex-direction:column; gap:2px; }
  .genre-checks label{
    display:flex; align-items:center; gap: var(--space-2);
    padding:3px 5px; border-radius: var(--radius-sm);
    font-size: var(--text-sm); color: var(--text-secondary); cursor:pointer;
  }
  .genre-checks label:hover{ background: var(--surface-hover); color: var(--text-primary); }
  .genre-checks label:has(input:checked){ color: var(--accent-fg); }
  /* Группа жанров — тоже .field, а .field input растягивает поле на всю
     ширину с отступами текстового ввода. Галочке это не нужно. */
  .genre-checks input{ accent-color: var(--accent); margin:0; flex:none; width:auto; padding:0; }
  /* На странице результатов список идёт во всю высоту: ограничение
     .search-panel нужно выпадающему списку под полем, а тут рядом стоит
     колонка фильтров, и прокрутка в коробке на 420px выглядела бы обрубком. */
  .search-page-results{ max-height:none; box-shadow:none; }
  /* В одну колонку фильтры встают над выдачей, а не под сотней строк. */
  @media (max-width: 980px){
    .search-layout .page-aside{ order:-1; }
  }

  /* — Радар жанров пройденных игр (partials/genre_radar.html). Карточка —
     как у гистограмм статистики; фигура — акцент сайта, один ряд, поэтому
     легенды нет: ряд называет заголовок блока, оси подписаны числами. — */
  .radar{
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md);
    padding: var(--space-3) var(--space-4);
  }
  .radar svg{ display:block; width:100%; max-width:600px; height:auto; margin-inline:auto; overflow:visible; }
  .radar-ring{ fill:none; stroke: var(--border); stroke-width:1; }
  .radar-axis{ stroke: var(--border-subtle); stroke-width:1; }
  .radar-area{ fill: var(--accent); fill-opacity:.2; stroke: var(--accent); stroke-width:2; stroke-linejoin:round; }
  .radar-dot{ fill: var(--accent); stroke: var(--surface); stroke-width:2; transition: r .12s ease; }
  .radar-hit{ fill: transparent; }
  .radar-point{ cursor:default; outline:none; }
  .radar-point:hover .radar-dot, .radar-point:focus-visible .radar-dot{ r:6; }
  .radar-label{ font-size:12px; fill: var(--text-secondary); }
  .radar-count{ fill: var(--text-primary); font-family: var(--font-mono); font-weight:600; }
  .radar + .mchart-note{ margin-top: var(--space-2); }

  /* — Знак вопроса с пояснением у заголовка блока (partials/help_tip.html).
     Подсказка — CSS по наведению и фокусу: кнопка получает фокус и от Tab,
     и от касания на телефоне. Растёт вниз от кнопки, прижата к её левому
     краю: заголовки стоят слева, и справа место есть всегда. — */
  .block-title{ display:flex; align-items:center; gap: var(--space-2); min-width:0; }
  .help-tip{ position:relative; display:inline-flex; }
  .help-tip-btn{
    width:18px; height:18px; border-radius:50%; padding:0; flex:none;
    display:inline-flex; align-items:center; justify-content:center;
    border:1px solid var(--border-strong); background: var(--surface);
    color: var(--text-tertiary); font: 600 11px/1 var(--font-mono); cursor:help;
  }
  .help-tip-btn:hover, .help-tip-btn:focus-visible{ color: var(--text-primary); border-color: var(--accent-border); outline:none; }
  .help-tip-body{
    display:none; position:absolute; z-index:30; top:calc(100% + 6px); left:0;
    width:max-content; max-width:min(320px, 80vw);
    padding: var(--space-3); border-radius: var(--radius-md);
    background: var(--bg-elevated); border:1px solid var(--border-strong); box-shadow: var(--shadow-md);
    font-size: var(--text-xs); line-height:1.5; color: var(--text-secondary); font-weight:400;
  }
  .help-tip:hover .help-tip-body, .help-tip-btn:focus + .help-tip-body{ display:block; }

  /* — «Нашли ошибку?» (partials/bug_report.html) — кнопка с жучком в
     подвале шапки игры. На широком экране (от 1400px, где слева от
     контента есть поле) она вынесена за левый край карточки на уровень
     строки цифр; уже — стоит первой в этой строке. Окно — тот же вид,
     что у окна подтверждения, только шире: в нём поле для текста. — */
  .bug-btn{
    display:inline-flex; align-items:center; justify-content:center; flex:none;
    width:30px; height:30px; padding:0; cursor:pointer;
    background: var(--surface); color: var(--text-tertiary);
    border:1px solid var(--border); border-radius: var(--radius-sm);
  }
  .bug-btn svg{ width:16px; height:16px; stroke: currentColor; }
  .bug-btn:hover, .bug-btn:focus-visible{ color: var(--text-primary); border-color: var(--border-strong); outline:none; }
  /* Ручка правки и жучок — парой (game_detail.html): рядом в строке, а на
     широком экране столбиком слева от карточки, ручка над жучком. */
  .game-tools{ display:inline-flex; gap: var(--space-2); flex:none; }
  @media (min-width: 1400px){
    .game-header-foot .game-tools{ position:absolute; right: calc(100% + var(--space-6) + var(--space-4)); bottom:-5px; flex-direction:column; }
  }
  .bug-dialog{ width: min(480px, calc(100vw - 2 * var(--space-4))); }
  .bug-dialog .field{ margin-bottom: var(--space-5); }
  .bug-dialog textarea{ min-height:120px; }
  .settings-subhead{ font-size: var(--text-sm); font-weight:600; margin:0; }
  /* «Игровые профили» в настройках: Steam, PlayStation и Xbox — частями одной
     карточки, разделёнными линией; условия — под «?» у подзаголовка. */
  .platform-profile{ display:flex; flex-direction:column; gap: var(--space-4); }
  .platform-profile + .platform-profile{ padding-top: var(--space-5); border-top:1px solid var(--border); }
  .bug-report-text{ white-space:normal; color: var(--text-primary); }
  /* Разделы чужой страницы (partials/user_tabs.html): в шапке страницы — справа. */
  .page-head .user-tabs{ margin-left:auto; }
  /* «Сбросить» в ряду фильтров библиотеки: справа и ростом с пилюлю статуса
     (тот же шрифт, line-height и вертикальные отступы, что у .status-badge),
     чтобы ряд не менял высоту. Без фильтра — невидима, но место держит. */
  .status-filters .filter-reset{
    margin-left:auto; display:inline-flex; align-items:center; gap:5px;
    font-size: var(--text-2xs); font-weight:600; line-height:1.6; white-space:nowrap;
    padding: 3px 11px 3px 8px; border-radius: var(--radius-full);
    border:1px solid var(--border-strong); background: var(--surface); color: var(--text-primary);
    transition: background .12s ease, border-color .12s ease;
  }
  .status-filters .filter-reset svg{ width:11px; height:11px; stroke:currentColor; flex:none; }
  .status-filters .filter-reset:hover, .status-filters .filter-reset:focus-visible{ background: var(--surface-hover); border-color: var(--accent); outline:none; }
  .status-filters .filter-reset.is-idle{ visibility:hidden; }

  /* Фильтры библиотеки под пилюлями статуса (library/index.html,
     apps/library/list_filters.py) — строка полей, как у рулетки; на узком
     экране переносятся. Даты — своей шириной, а не flex:1 из .range-row:
     в сжатом поле дата обрезается. */
  .library-filters{ display:flex; flex-wrap:wrap; gap: var(--space-3); align-items:flex-end; margin-top: var(--space-4); }
  .library-filters .lib-pct{ width:200px; }
  .library-filters .lib-played .range-row{ flex-wrap:wrap; }
  .library-filters .lib-played select{ width:auto; }
  .library-filters .lib-played input[type="date"]{ flex:none; width:150px; }
  .library-filters .lib-device{ min-width:180px; }
  .library-filters .lib-platform{ min-width:150px; }
  /* У .btn-primary макета align-self:flex-start — в строке полей кнопка
     вставала вровень с подписями, а не с полями. Тут она внизу и ростом с
     поле: тот же вертикальный отступ 9px и прозрачная рамка 1px вместо
     рамки поля. */
  .library-filters .btn-primary{ align-self:flex-end; padding: 9px 16px; border:1px solid transparent; }

  /* — Статистика: одна строка плиток и переключатель «Общее / Steam /
       PlayStation» над ней. Пилюли — .ach-filter, как годы ниже; строка
       въезжает сбоку, с той стороны, куда переключили. — */
  .stat-slides{ display:flex; flex-direction:column; gap: var(--space-3); }
  /* Сдвиг не больше бокового поля страницы — без горизонтальной прокрутки
     и без overflow:hidden, который срезал бы обводку фокуса у пилюль. */
  button.ach-filter{ background:none; cursor:pointer; }
  .stat-slide.is-from-right{ animation: stat-slide-right .22s ease; }
  .stat-slide.is-from-left{ animation: stat-slide-left .22s ease; }
  @keyframes stat-slide-right{ from{ opacity:0; transform: translateX(16px); } to{ opacity:1; transform:none; } }
  @keyframes stat-slide-left{ from{ opacity:0; transform: translateX(-16px); } to{ opacity:1; transform:none; } }
  @media (prefers-reduced-motion: reduce){
    .stat-slide.is-from-right, .stat-slide.is-from-left{ animation:none; }
  }

  /* Лента серии на странице игры (partials/series_shelf.html) */
  .series-row{ position:relative; }
  .series-row .game-card{ width:140px; flex:none; }
  .series-card[aria-current]{ border-color: var(--accent-border); box-shadow: 0 0 0 1px var(--accent-border) inset; }
  .series-card[data-missing]{ opacity:.45; }
  .series-card[data-missing]:hover{ transform:none; box-shadow:none; border-color: var(--border); }
  .series-kind{ font-size: var(--text-2xs); color: var(--text-tertiary); text-align:right; }

  /* «Мои устройства» и блок «Устройства» в профиле (partials/device_card.html) */
  .device-grid{ display:grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--space-3); }
  .device-card{
    background: var(--bg-elevated); border:1px solid var(--border); border-radius: var(--radius-md);
    overflow:hidden; display:flex; flex-direction:column; min-width:0;
  }
  .device-photo{ display:block; aspect-ratio: 16 / 10; background: var(--surface-sunken); border-bottom:1px solid var(--border-subtle); }
  .device-photo img{ width:100%; height:100%; object-fit:cover; display:block; }
  .device-body{ padding: var(--space-4); display:flex; flex-direction:column; gap: var(--space-3); flex:1; }
  .device-head{ display:flex; flex-direction:column; gap:2px; }
  .device-head b{ font-size: var(--text-md); overflow-wrap:anywhere; }
  .device-kind{ font-size: var(--text-2xs); font-weight:600; text-transform:uppercase; letter-spacing:.07em; color: var(--text-tertiary); }
  .device-specs{ display:flex; flex-direction:column; gap: var(--space-2); margin:0; }
  .device-specs div{ display:grid; grid-template-columns: minmax(7.5em, 40%) 1fr; gap: var(--space-2); font-size: var(--text-xs); line-height:1.4; }
  .device-specs dt{ color: var(--text-tertiary); display:flex; align-items:flex-start; gap:6px; }
  /* Иконка комплектующей (#i-cpu, #i-gpu…): чуть светлее подписи, чтобы
     строки различались с одного взгляда, а не сливались в столбик. */
  .device-specs dt svg, .device-parts .field > label svg{
    width:14px; height:14px; flex:none; stroke: var(--text-secondary);
  }
  .device-specs dt svg{ margin-top:1px; }
  .device-parts .field > label{ display:flex; align-items:center; gap:6px; }
  .device-ram{ display:grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
  /* Значение прижато к правому краю карточки: подпись слева, модель справа —
     как строки «Сколько проходят» на странице игры. */
  .device-specs dd{ margin:0; color: var(--text-primary); overflow-wrap:anywhere; text-align:right; }
  .device-actions{ display:flex; gap: var(--space-2); flex-wrap:wrap; align-items:center; margin-top:auto; }
  .device-form-main{ display:grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-3); width:100%; }
  .device-parts{
    width:100%; min-width:0; margin:0; padding: var(--space-4);
    border:1px solid var(--border); border-radius: var(--radius-md);
    display:grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-3);
  }
  .device-parts legend{ padding: 0 var(--space-2); font-size: var(--text-2xs); font-weight:600; text-transform:uppercase; letter-spacing:.07em; color: var(--text-secondary); }
  /* Комплектующие только у компьютера и ноутбука (Device.PC_KINDS) — без
     скрипта, по выбранному типу. Без :has() блок просто виден всегда. */
  .device-form:has(select[name="kind"] option:checked:not([value="pc"]):not([value="laptop"])) .device-parts{ display:none; }
  .device-photo-current{ width:160px; aspect-ratio: 16 / 10; object-fit:cover; border-radius: var(--radius-sm); border:1px solid var(--border); }

  /* «Оценка сайта» приколота к правому верхнему углу шапки игры absolute'ом
     и в раскладке места не занимает. Колонка названия тянется до правого
     края шапки, и длинное название (VA-11 Hall-A: Cyberpunk Bartender
     Action) или строка жанров уезжали под оценку — та появляется, как
     только игру кто-то оценил. Строкам, что стоят на её высоте, оставляем
     справа поле шире блока оценки («Оценка сайта» / «10,0/10»). */
  .game-header:has(.game-header-score) .game-header-title-row,
  .game-header:has(.game-header-score) .game-header-meta{ padding-right: 7.5rem; }

  /* Страницы библиотеки (library/index.html): пилюли .ach-filter под списком */
  .pager{ justify-content:center; margin-top: var(--space-4); }
  .pager-gap{ align-self:center; color: var(--text-tertiary); padding: 0 var(--space-1); }

  /* Доступ к данным Steam в карточке настроек и предупреждение об импорте
     (accounts/settings.html, apps/library/import_status.py) */
  .access-list{ display:flex; flex-direction:column; gap: var(--space-2); }
  .access-list li{ display:flex; align-items:flex-start; gap: var(--space-2); font-size: var(--text-sm); color: var(--text-tertiary); }
  .access-list li b{ color: var(--text-secondary); font-weight:600; margin-right: var(--space-1); }
  .access-list svg{ width:16px; height:16px; flex:none; margin-top:2px; stroke: var(--text-tertiary); fill:none; }
  .access-list li.is-ok svg{ stroke: var(--status-completed-fg); }
  .access-list li.is-fail{ color: var(--status-dropped-fg); }
  .access-list li.is-fail svg{ stroke: var(--status-dropped-fg); }
  .import-problem{
    font-size: var(--text-xs); line-height:1.5; color: var(--status-dropped-fg);
    background: var(--status-dropped-bg); border:1px solid var(--status-dropped-bd);
    border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3);
  }

  /* Устройство под статусом на странице игры: тот же пикер, что у статуса,
     но приглушённый — это уточнение, а не главное о игре. Длинное
     название устройства обрезается многоточием, ширина — по обложке. */
  .game-device-picker select.status-badge{
    color: var(--text-secondary); font-size: var(--text-xs);
    text-overflow: ellipsis; white-space: nowrap; overflow:hidden;
  }

  /* На чём играли — квадратик в строке библиотеки (partials/game_row.html).
     Значок типа устройства, название — в подсказке title. */
  .row-device{ display:flex; justify-content:center; }
  .device-chip{
    width:24px; height:24px; flex:none;
    display:flex; align-items:center; justify-content:center;
    background: var(--surface-sunken); border:1px solid var(--border);
    border-radius: var(--radius-sm); color: var(--text-secondary); cursor:help;
  }
  .device-chip svg{ width:14px; height:14px; stroke:currentColor; }
  .game-row:hover .device-chip{ border-color: var(--border-strong); color: var(--text-primary); }

  /* Карточка устройства по наведению на квадратик: название, тип и у
     компьютера — комплектующие. Строка под курсором поднимается над
     соседями: иначе карточку перекрыла бы следующая строка (у строк на
     сотню есть filter, а он заводит свой контекст наложения). */
  .game-row:hover, .game-row:focus-within{ position:relative; z-index:3; }
  /* Карточка, оставшаяся открытой по клику (фокус на квадратике), — над
     строкой под курсором: иначе у соседней строки тот же z-index, она ниже
     по DOM и рисовалась поверх карточки. Квадратик под курсором — ещё выше,
     его карточка поверх «закреплённой». */
  .game-row:has(.device-chip:focus){ z-index:4; }
  .game-row:has(.device-chip:hover){ z-index:5; }
  .device-chip{ position:relative; }
  .device-chip:focus-visible{ outline:2px solid var(--accent-border); outline-offset:2px; }
  .device-tip{
    display:none; position:absolute; top: calc(100% + 6px); left:50%; transform:translateX(-50%);
    width:max-content; min-width:180px; max-width:340px;
    flex-direction:column; gap:2px; padding: var(--space-3);
    background: var(--surface); border:1px solid var(--border-strong);
    border-radius: var(--radius-md); box-shadow: var(--shadow-lg);
    color: var(--text-primary); text-align:left; cursor:default; pointer-events:none;
  }
  .device-chip:hover .device-tip, .device-chip:focus .device-tip{ display:flex; }
  .device-tip > b{ font-size: var(--text-sm); }
  .device-tip .device-specs{ display:flex; flex-direction:column; gap:4px; margin-top: var(--space-2); }
  .device-tip .device-specs > span{
    display:grid; grid-template-columns: 14px auto 1fr; align-items:center; gap:6px;
    font-size: var(--text-xs); color: var(--text-tertiary);
  }
  .device-tip .device-specs svg{ width:13px; height:13px; stroke: var(--text-secondary); }
  .device-tip .device-specs b{ font-weight:500; color: var(--text-primary); text-align:right; }

  /* — Шапка на телефоне. На 390px логотип с надписью, поиск, аватар,
       колокольчик, шестерёнка и «выйти» не помещались, и страница
       уезжала вбок на ~60px — браузер телефона из-за этого уменьшал её
       целиком. Остаётся значок логотипа без надписи, у поиска снимается
       подсказка «/» (клавиатуры нет), а сам он может сжиматься до нуля:
       min-width:auto у flex-элемента держал его по ширине поля. — */
  @media (max-width: 620px){
    .topbar .brand-name{ display:none; }
    .topbar .search{ min-width:0; }
    .search kbd{ display:none; }
    .search input{ padding-right: var(--space-3); }
    .topbar-actions{ gap: var(--space-1); }
  }

  /* «Любимые игры» на профиле: полоса прогресса шириной 300px не
     помещалась в панель на 320px и выталкивала страницу вбок. На телефоне
     статус и полоса занимают строку целиком, полоса — всё, что осталось. */
  @media (max-width: 620px){
    .favourites .ach-panel-meta{ width:100%; margin-left:0; }
    .favourites .ach-panel-meta .progress{ flex:1; width:auto; min-width:0; }
  }

  /* — Правка страницы игры и «Модерация сайта» (apps/edits). Форма слева,
       история справа; правка — карточкой-коммитом: хеш, автор, время,
       состояние, ниже сравнение строками «−» и «+», изменённые слова
       подсвечены, как в `git diff --word-diff`. — */
  .edit-layout{ display:grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: var(--space-6); align-items:start; }
  @media (max-width: 980px){
    .edit-layout{ grid-template-columns: minmax(0, 1fr); }
  }
  .edit-langs{ margin-left:auto; }
  .edit-form{ display:flex; flex-direction:column; gap: var(--space-5); }
  .edit-form textarea{ min-height:220px; }
  .edit-cover-row{ display:flex; gap: var(--space-4); align-items:flex-start; }
  .edit-cover-now{
    width:84px; aspect-ratio:3/4; flex:none; position:relative; overflow:hidden;
    border-radius: var(--radius-sm); display:flex; align-items:center; justify-content:center;
  }
  .edit-cover-now .mono-letters{ font-family: var(--font-mono); font-weight:700; font-size: var(--text-lg); color: var(--text-primary); }
  .edit-cover-now img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
  .edit-cover-inputs{ display:flex; flex-direction:column; gap: var(--space-2); flex:1; min-width:0; }
  .edit-series{ border:0; padding:0; margin:0; min-width:0; }
  .edit-series legend{
    padding:0; margin-bottom:5px;
    font-size: var(--text-2xs); font-weight:600; text-transform:uppercase; letter-spacing:.07em; color: var(--text-tertiary);
  }
  .edit-sublabel{ margin-top: var(--space-3); }
  .field > label.check-row{ font-size: var(--text-sm); font-weight:400; text-transform:none; letter-spacing:0; color: var(--text-primary); }
  .check-row{ display:flex; align-items:center; gap: var(--space-2); font-size: var(--text-sm); color: var(--text-primary); cursor:pointer; }
  .field .check-row input{ width:auto; padding:0; margin:0; flex:none; }
  .edit-submit{ display:flex; align-items:center; gap: var(--space-3); flex-wrap:wrap; }

  .edit-card{
    display:flex; flex-direction:column; gap: var(--space-3);
    margin-bottom: var(--space-3); padding: var(--space-4);
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md);
  }
  .edit-card:target{ border-color: var(--accent-border); }
  .edit-card-head{ display:flex; align-items:center; gap: var(--space-2); flex-wrap:wrap; font-size: var(--text-sm); }
  .edit-hash{
    font-family: var(--font-mono); font-size: var(--text-xs); color: var(--accent);
    background: var(--accent-soft); padding:2px 6px; border-radius: var(--radius-xs);
  }
  .edit-card .friend-avatar{
    width:22px; height:22px; border-radius: var(--radius-full); flex:none;
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size:9px; color: var(--text-primary);
  }
  .edit-author{ font-weight:600; color: var(--text-primary); }
  .edit-time{ font-size: var(--text-xs); color: var(--text-tertiary); }
  .edit-state{
    margin-left:auto; padding:2px 9px; border:1px solid; border-radius: var(--radius-full);
    font-size: var(--text-2xs); font-weight:600;
  }
  .edit-state[data-state="pending"]{ color: var(--status-paused-fg); background: var(--status-paused-bg); border-color: var(--status-paused-bd); }
  .edit-state[data-state="approved"]{ color: var(--status-completed-fg); background: var(--status-completed-bg); border-color: var(--status-completed-bd); }
  .edit-state[data-state="rejected"]{ color: var(--status-dropped-fg); background: var(--status-dropped-bg); border-color: var(--status-dropped-bd); }
  .edit-message, .edit-game, .edit-review, .edit-empty, .edit-conflict{ margin:0; }
  .edit-message{ color: var(--text-primary); }
  .edit-game{ font-size: var(--text-sm); }
  .edit-review{ font-size: var(--text-xs); color: var(--text-tertiary); }
  .edit-file{ border:1px solid var(--border); border-radius: var(--radius-sm); overflow:hidden; }
  .edit-file-head{
    display:flex; justify-content:space-between; gap: var(--space-2);
    padding: 6px var(--space-3); background: var(--surface-sunken); border-bottom:1px solid var(--border);
    font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-secondary);
  }
  .edit-stat-add{ color: var(--status-completed-fg); }
  .edit-stat-del{ color: var(--status-dropped-fg); }
  .edit-diff{ font-family: var(--font-mono); font-size: var(--text-xs); line-height:1.6; max-height:420px; overflow:auto; }
  .diff-line{ display:grid; grid-template-columns: 22px minmax(0, 1fr); }
  .diff-sign{ text-align:center; color: var(--text-tertiary); user-select:none; }
  .diff-text{ white-space:pre-wrap; overflow-wrap:anywhere; padding-right: var(--space-3); color: var(--text-secondary); }
  .diff-text mark{ color:inherit; border-radius:2px; }
  .diff-line[data-sign="-"]{ background: var(--status-dropped-bg); }
  .diff-line[data-sign="-"] .diff-sign, .diff-line[data-sign="-"] .diff-text{ color: var(--status-dropped-fg); }
  .diff-line[data-sign="-"] mark{ background: var(--status-dropped-bd); }
  .diff-line[data-sign="+"]{ background: var(--status-completed-bg); }
  .diff-line[data-sign="+"] .diff-sign, .diff-line[data-sign="+"] .diff-text{ color: var(--status-completed-fg); }
  .diff-line[data-sign="+"] mark{ background: var(--status-completed-bd); }
  .edit-empty{ padding: var(--space-3); font-size: var(--text-sm); color: var(--text-tertiary); }
  .edit-covers{ display:flex; align-items:center; gap: var(--space-4); padding: var(--space-3); }
  .edit-cover{ margin:0; display:flex; flex-direction:column; align-items:center; gap:4px; }
  .edit-cover img, .edit-cover-none{
    width:72px; aspect-ratio:3/4; object-fit:cover; border:2px solid var(--border); border-radius: var(--radius-xs);
    display:flex; align-items:center; justify-content:center;
    background: var(--surface-sunken); font-size: var(--text-2xs); color: var(--text-tertiary);
  }
  .edit-cover[data-sign="-"] img, .edit-cover[data-sign="-"] .edit-cover-none{ border-color: var(--status-dropped-bd); }
  .edit-cover[data-sign="+"] img, .edit-cover[data-sign="+"] .edit-cover-none{ border-color: var(--status-completed-bd); }
  .edit-cover figcaption{ font-size: var(--text-2xs); color: var(--text-tertiary); }
  .edit-arrow{ width:16px; height:16px; stroke: var(--text-tertiary); transform: rotate(180deg); }
  .edit-conflict{ display:flex; align-items:center; gap: var(--space-2); font-size: var(--text-sm); color: var(--status-dropped-fg); }
  .edit-conflict svg{ width:16px; height:16px; stroke: currentColor; flex:none; }
  .edit-actions{ display:flex; align-items:center; gap: var(--space-2); flex-wrap:wrap; }
  .edit-reject{ flex:1; min-width:240px; }
  .edit-reject input{
    flex:1; min-width:0; padding: 7px 10px;
    background: var(--surface-sunken); color: var(--text-primary);
    border:1px solid var(--border); border-radius: var(--radius-sm);
    font-family:inherit; font-size: var(--text-sm);
  }

  /* — Жалобы на комментарии: пометка под отправленной, форма с причинами
       (partials/comment.html), карточка во вкладке «Комментарии» модерации. — */
  .comment-actions .comment-report-link:hover{ color: var(--status-dropped-fg); }
  .comment-reported{ font-size: var(--text-xs); color: var(--text-tertiary); }
  .comment-report-reasons{ display:flex; flex-wrap:wrap; gap: var(--space-2) var(--space-4); border:0; padding:0; margin:0; min-width:0; }
  .comment-report-reasons legend{ padding:0; margin-bottom: var(--space-2); font-size: var(--text-xs); color: var(--text-secondary); }
  .comment-report-reasons input{ margin:0; }
  .comment-report > input[type="text"]{
    padding: 7px 10px; background: var(--surface-sunken); color: var(--text-primary);
    border:1px solid var(--border); border-radius: var(--radius-sm);
    font-family:inherit; font-size: var(--text-sm);
  }
  .report-body{ padding: var(--space-3); background: var(--surface-sunken); border-radius: var(--radius-sm); }
  .report-list{ margin:0; padding-left: var(--space-5); display:flex; flex-direction:column; gap: var(--space-1); font-size: var(--text-sm); }

  /* — Сообщества (templates/communities, doc/soobshchestva.md). Обложка —
       как у игр: плашка цвета --cover-N с инициалами, картинка поверх. — */
  .page-head-action{ margin-left:auto; align-self:center; gap: var(--space-2); }
  .page-head-action svg{ width:14px; height:14px; stroke:currentColor; }
  .community-search{ max-width:480px; }
  .community-search input{
    padding: 8px 12px; background: var(--surface-sunken); color: var(--text-primary);
    border:1px solid var(--border); border-radius: var(--radius-sm);
    font-family:inherit; font-size: var(--text-sm);
  }
  .community-grid{ display:grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--space-4); }
  /* Карточка — аватар слева, текст справа: широкая обложка живёт только
     в шапке страницы сообщества. */
  .community-card{
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md);
    padding: var(--space-4); display:flex; align-items:center; gap: var(--space-4); min-width:0; color: inherit;
    transition: border-color .15s ease, transform .15s ease, box-shadow .15s ease;
  }
  .community-card:hover{ border-color: var(--border-strong); box-shadow: var(--shadow-md); transform: translateY(-2px); }
  .community-avatar, .community-thumb, .community-avatar-lg{
    position:relative; flex:none; overflow:hidden;
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; color: var(--text-primary);
    border-radius: var(--radius-md);
  }
  .community-avatar{ width:64px; height:64px; font-size: var(--text-lg); }
  .community-thumb{ width:56px; height:56px; font-size: var(--text-md); }
  /* В шапке аватар наезжает на нижний край обложки, рамка цвета карточки
     отделяет его от картинки. */
  .community-avatar-lg{
    width:104px; height:104px; font-size: var(--text-xl);
    margin-top: calc(-52px - var(--space-5));
    border:3px solid var(--surface); border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
  }
  .community-avatar img, .community-thumb img, .community-avatar-lg img,
  .community-banner img, .community-cover-now img{
    position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  }
  .community-banner, .community-cover-now{
    position:relative; display:block; overflow:hidden;
    background-image: repeating-linear-gradient(135deg, rgba(255,255,255,.05) 0 2px, transparent 2px 14px);
  }
  .community-banner{ aspect-ratio: 4 / 1; border-bottom:1px solid var(--border-subtle); }
  .community-cover-now{ width:100%; max-width:480px; aspect-ratio: 4 / 1; border-radius: var(--radius-sm); border:1px solid var(--border); }
  .community-card-body{ display:flex; flex-direction:column; gap: var(--space-1); min-width:0; flex:1; }
  .community-card-title{ display:flex; align-items:center; gap: var(--space-2); min-width:0; }
  .community-card-title b{ font-size: var(--text-md); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .community-lock{ width:14px; height:14px; flex:none; stroke: var(--text-tertiary); }
  .community-card-meta{ font-size: var(--text-xs); color: var(--text-tertiary); }
  .community-role{
    align-self:flex-start; margin-top: var(--space-1);
    font-size: var(--text-2xs); font-weight:600; text-transform:uppercase; letter-spacing:.07em;
    color: var(--accent-fg); background: var(--accent-soft); border:1px solid var(--accent-border);
    border-radius: var(--radius-full); padding: 2px 8px;
  }
  .community-role.is-invited{ color: var(--status-planned-fg); background: var(--status-planned-bg); border-color: var(--status-planned-bd); }

  .community-header{
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md); overflow:hidden;
  }
  .community-header-body{ position:relative; padding: var(--space-5); display:flex; flex-direction:column; gap: var(--space-3); }
  .community-header-title{ display:flex; align-items:center; gap: var(--space-3); flex-wrap:wrap; }
  .community-header-title h1{ font-size: var(--text-xl); overflow-wrap:anywhere; }
  .community-kind{
    display:inline-flex; align-items:center; gap:4px;
    font-size: var(--text-2xs); font-weight:600; text-transform:uppercase; letter-spacing:.07em;
    color: var(--text-secondary); border:1px solid var(--border-strong); border-radius: var(--radius-full); padding: 2px 8px;
  }
  .community-kind svg{ width:12px; height:12px; stroke: currentColor; }
  .community-header .hint, .settings-row .hint{ font-size: var(--text-xs); color: var(--text-tertiary); }
  .community-header a.btn-ghost{ display:inline-flex; align-items:center; gap: var(--space-2); }
  .community-about{ max-width:70ch; color: var(--text-secondary); line-height:1.6; overflow-wrap:anywhere; display:flex; flex-direction:column; gap: var(--space-3); }
  .community-leave{ display:flex; flex-direction:column; align-items:flex-start; gap: var(--space-2); }
  .community-game-results:empty{ display:none; }
  .community-game-results{
    display:flex; flex-direction:column; gap: var(--space-3);
    padding: var(--space-3); background: var(--surface-sunken); border-radius: var(--radius-sm);
  }
  .community-game-results .settings-row:last-child{ border-bottom:0; padding-bottom:0; }
  .community-game-results .btn-primary{ display:inline-flex; align-items:center; gap: var(--space-1); }
  .community-game-results .btn-primary svg{ width:13px; height:13px; stroke:currentColor; }
  @media (max-width: 620px){
    .community-banner{ aspect-ratio: 3 / 1; }
    .community-avatar-lg{ width:80px; height:80px; margin-top: calc(-40px - var(--space-5)); font-size: var(--text-lg); }
    .page-head-action{ margin-left:0; }
  }

  /* — Страница сообщества: сверху на всю ширину шапка и «О сообществе»,
       ниже две колонки — игры, участники и приглашения слева, обсуждения
       справа на уровне «Игр». Страница шире обычных 1280px ровно на правую
       колонку и зазор: обсуждения встают в пустое место справа, а не
       теснят игры. Уже 1100px колонка уезжает вниз. — */
  .content:has(> .community-page){ max-width: calc(1280px + 340px + var(--space-6)); }
  .community-page{ display:flex; flex-direction:column; gap: var(--space-8); min-width:0; }
  .community-cols{ display:grid; grid-template-columns: minmax(0, 1fr) 340px; gap: var(--space-6); align-items:start; }
  .community-main{ display:flex; flex-direction:column; gap: var(--space-8); min-width:0; }
  .community-side{ min-width:0; position:sticky; top: calc(var(--topbar-h) + var(--tabbar-h) + var(--space-4)); }
  @media (max-width: 1100px){
    .community-cols{ grid-template-columns: minmax(0, 1fr); gap: var(--space-8); }
  }
  .community-side .block{ gap: var(--space-3); }
  .topic-new{ display:inline-flex; align-items:center; gap: var(--space-2); }
  .topic-new svg{ width:14px; height:14px; stroke:currentColor; }
  .topic-list{
    display:flex; flex-direction:column;
    background: var(--surface); border:1px solid var(--border); border-radius: var(--radius-md); overflow:hidden;
  }
  .topic-list:has(> .settings-note){ background:none; border:0; }
  .topic-row{
    display:flex; flex-direction:column; gap:2px; padding: var(--space-3) var(--space-4);
    border-bottom:1px solid var(--border-subtle); color: inherit; min-width:0;
  }
  .topic-row:last-child{ border-bottom:0; }
  .topic-row:hover{ background: var(--surface-hover); }
  .topic-row-title{ display:flex; align-items:center; gap: var(--space-1); min-width:0; }
  .topic-row-title b{ font-size: var(--text-sm); overflow-wrap:anywhere; }
  .topic-flag{ width:13px; height:13px; flex:none; stroke: var(--text-tertiary); }
  .topic-row-meta{ font-size: var(--text-xs); color: var(--text-tertiary); }
  .topic-head .community-kind{ align-self:center; }
  @media (max-width: 1100px){
    .community-side{ position:static; }
  }

  /* — Роли в настройках сообщества — */
  .role-form{
    display:flex; flex-direction:column; gap: var(--space-3);
    padding-bottom: var(--space-3);
  }
  .role-form.is-new{ padding-top: var(--space-4); border-top:1px solid var(--border-subtle); }
  .role-form-title{ font-size: var(--text-md); }
  .role-form .btn-primary{ display:inline-flex; align-items:center; gap: var(--space-1); }
  .role-form .btn-primary svg{ width:13px; height:13px; stroke:currentColor; }
  .role-delete{ padding-bottom: var(--space-4); border-bottom:1px solid var(--border-subtle); }
  .role-perms{
    border:0; padding:0; margin:0; min-width:0;
    display:grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--space-2) var(--space-4);
  }
  .role-perms .check-row{ align-items:flex-start; }
  .role-perms .check-row input{ width:auto; padding:0; margin:3px 0 0; flex:none; }
  .role-perms .check-row > span{ display:flex; flex-direction:column; gap:2px; }
  .member-role-form{ display:flex; gap: var(--space-2); align-items:center; }
  .member-role-form select{
    padding: 6px 8px; background: var(--surface-sunken); color: var(--text-primary);
    border:1px solid var(--border); border-radius: var(--radius-sm);
    font-family:inherit; font-size: var(--text-sm); max-width:180px;
  }

  /* — Помощь сайту (templates/help_site.html) —
       Список — строки настроек, вкладки — те же пилюли, что фильтры
       достижений на странице игры. — */
  .help-intro{ max-width:760px; color: var(--text-secondary); font-size: var(--text-sm); line-height:1.55; }
  .help-filters{ margin: var(--space-2) 0 var(--space-4); }
  .help-games .settings-row:last-child{ padding-bottom:0; border-bottom:0; }
  .help-games .btn-ghost{ display:inline-flex; align-items:center; gap: var(--space-1); }

  /* — Комментарии: «Форматирование» с подсказкой и галочка подписки —
       Подсказка разметки свёрнута в одно слово с «?» (partials/format_help.html);
       галочка «Уведомлять о новых» — справа от заголовка
       (partials/comment_subscribe.html). — */
  .format-help{ display:inline-flex; align-items:center; gap:6px; }
  .comment-subscribe label{
    display:inline-flex; align-items:center; gap:6px; cursor:pointer;
    font-size: var(--text-xs); color: var(--text-secondary);
  }
  .comment-subscribe input{ width:14px; height:14px; margin:0; accent-color: var(--accent); }

  /* — Скриншоты сообщества (communities/detail.html) —
       Сетка превью 16:9, щелчок — окно с картинкой целиком. Окно — тот же
       .confirm-dialog, только шире: картинка вписывается по высоте экрана. — */
  .shot-grid{ display:grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: var(--space-3); }
  .shot-thumb{
    display:block; padding:0; cursor:zoom-in; aspect-ratio: 16 / 9; overflow:hidden;
    border:1px solid var(--border); border-radius: var(--radius-sm); background: var(--surface-sunken);
  }
  .shot-thumb:hover, .shot-thumb:focus-visible{ border-color: var(--accent-border); outline:none; }
  .shot-thumb img{ display:block; width:100%; height:100%; object-fit:cover; }
  .confirm-dialog.shot-dialog{ width:min(1100px, 94vw); max-width:none; }
  .shot-dialog img{
    display:block; width:100%; max-height:72vh; object-fit:contain;
    border-radius: var(--radius-sm); background: var(--surface-sunken);
  }
  .shot-meta{ display:flex; flex-wrap:wrap; align-items:center; gap: var(--space-3); margin-top: var(--space-3); }
  .shot-meta .btn-row{ margin-left:auto; }

  /* — Правая колонка шапки профиля —
       Кольцо уровня по-прежнему посередине по высоте, а соцсети (Discord) —
       в правом нижнем углу, на одной линии со строкой цифр слева: три
       строки сетки, средняя — уровень, нижняя прижата к низу. На телефоне
       колонка встаёт строкой под цифрами: уровень слева, Discord справа. — */
  .profile-side{
    flex:none; align-self:stretch;
    display:grid; grid-template-rows: 1fr auto 1fr; justify-items:end;
  }
  .profile-side .profile-level{ grid-row:2; }
  .profile-side .profile-socials{ grid-row:3; align-self:end; }
  @media (max-width: 620px){
    .profile-side{
      flex-basis:100%; display:flex; flex-wrap:wrap; align-items:center;
      justify-content:space-between; gap: var(--space-3);
    }
  }

  /* — «Играли вместе» на странице игры (apps/library/coop.py) —
       Строка под статусом и устройством: подпись, аватары отмеченных
       друзей и плюс. Ширина колонки — по обложке, аватары переносятся.
       В окне — список всех друзей с кнопкой «Отметить» / «Снять»,
       длинный список прокручивается внутри окна. — */
  .coop-row{
    display:flex; flex-direction:column; gap: 6px;
    margin-top: var(--space-1);
    scroll-margin-top: calc(var(--topbar-h) + var(--tabbar-h) + var(--space-6));
  }
  .coop-label{
    font-size: var(--text-2xs); color: var(--text-tertiary);
    font-family: var(--font-mono); text-transform: uppercase; letter-spacing:.04em;
  }
  .coop-people{ display:flex; flex-wrap:wrap; gap: 6px; align-items:center; }
  .coop-person{ display:block; flex:none; border-radius: var(--radius-sm); }
  .coop-person:hover .friend-avatar, .coop-person:focus-visible .friend-avatar{ outline:1px solid var(--accent-border); }
  .coop-people .friend-avatar, .coop-item .friend-avatar{
    width:28px; height:28px; border-radius: var(--radius-sm);
    display:flex; align-items:center; justify-content:center;
    font-family: var(--font-mono); font-weight:700; font-size:10px; color: var(--text-primary);
  }
  .coop-add{
    width:28px; height:28px; flex:none; padding:0; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    background:none; color: var(--text-tertiary);
    border:1px dashed var(--border); border-radius: var(--radius-sm);
  }
  .coop-add svg{ width:14px; height:14px; stroke: currentColor; }
  /* «+N» — кто не влез в два ряда. Квадратик того же размера, что аватар. */
  .coop-more{
    width:28px; height:28px; flex:none; padding:0; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    background: var(--surface-sunken); color: var(--text-secondary);
    border:1px solid var(--border); border-radius: var(--radius-sm);
    font-family: var(--font-mono); font-size:10px; font-weight:700;
  }
  .coop-more:hover, .coop-more:focus-visible{ color: var(--accent-fg); border-color: var(--accent-border); outline:none; }
  /* Один ряд: 4 квадратика по 28 px на компьютере (колонка 144 px) и 3 по
     24 px на телефоне (84 px). Лишние аватары и «+N» не той ширины прячутся. */
  .coop-people{ flex-wrap:nowrap; }
  .coop-more.is-narrow-only{ display:none; }
  @media (max-width: 620px){
    .coop-people{ gap:4px; }
    .coop-people .is-wide-only{ display:none; }
    .coop-more.is-narrow-only{ display:flex; }
    .coop-people .friend-avatar, .coop-add, .coop-more{ width:24px; height:24px; }
  }
  /* Окно «+N»: строка — ссылка на профиль. */
  .coop-item-link{ display:flex; align-items:center; gap: var(--space-3); flex:1; min-width:0; color:inherit; text-decoration:none; }
  .coop-item-link:hover .coop-name{ color: var(--accent-fg); }

  .coop-add:hover, .coop-add:focus-visible{ color: var(--accent-fg); border-color: var(--accent-border); outline:none; }
  .coop-list{
    list-style:none; margin:0 0 var(--space-4); padding:0;
    max-height: min(360px, 55vh); overflow-y:auto;
  }
  .coop-item{
    display:flex; align-items:center; gap: var(--space-3);
    padding: var(--space-2) 0; border-bottom:1px solid var(--border-subtle);
  }
  .coop-item:last-child{ border-bottom:0; }
  .coop-name{
    flex:1; min-width:0; font-size: var(--text-sm); font-weight:600;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  .coop-item .btn-primary, .coop-item .btn-ghost{ padding: 5px 10px; font-size: var(--text-xs); }
  .coop-badge{
    display:inline-block; margin-left:4px; padding:0 5px; vertical-align:1px;
    font-size: var(--text-2xs); font-weight:500; font-family: var(--font-mono);
    color: var(--accent-fg); border:1px solid var(--accent-border); border-radius: var(--radius-sm);
  }

  /* — Тема профиля в настройках «Внешний вид» (settings_appearance.html) —
       Образец темы квадратиком слева, у выбранной — подпись вместо кнопки.
       Сами темы — static/css/themes/<ключ>.css, только на странице профиля. */
  .theme-swatch{
    width:56px; height:40px; flex:none; border-radius: var(--radius-sm);
    border:1px solid var(--border);
  }
  .theme-swatch-default{
    background: linear-gradient(var(--accent), var(--accent)) top / 100% 2px no-repeat,
      linear-gradient(180deg, var(--surface), var(--bg));
  }
  /* Образец рисуется цветами самой темы (themes/cyberpunk.css), не сайта. */
  .theme-swatch-cyberpunk{
    border-color:#2d2542;
    background: linear-gradient(90deg, #ff2a6d, #05d9e8) top / 100% 2px no-repeat,
      radial-gradient(40px 24px at 100% 0%, rgba(255,42,109,.45), transparent 70%),
      radial-gradient(36px 22px at 0% 100%, rgba(5,217,232,.35), transparent 70%),
      #0b0912;
  }
  .theme-current{ font-size: var(--text-xs); color: var(--accent-fg); font-weight:600; }

  /* — Чат (templates/chat/*, static/js/chat.js, doc/chat.md) —
       Кнопка в правом нижнем углу на каждой странице вошедшего, окно над
       ней. Вид — как у Telegram: список диалогов и диалог в одной колонке,
       свои сообщения справа акцентом, чужие слева, «хвост» у последнего
       в группе, время и галочки внутри пузыря. На телефоне — во весь экран. */
  .chat{ position:fixed; right: var(--space-5); bottom: var(--space-5); z-index:45; }
  .chat-fab{
    position:relative; width:52px; height:52px; border-radius:50%; border:none; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    background: var(--accent); color: var(--bg-elevated); box-shadow: var(--shadow-lg);
    transition: transform .15s ease, filter .15s ease;
  }
  .chat-fab:hover{ filter:brightness(1.08); }
  .chat-fab:active{ transform: scale(.94); }
  .chat-fab svg{ width:26px; height:26px; stroke:currentColor; }
  .chat-fab-count{
    position:absolute; top:-4px; right:-4px; min-width:20px; height:20px; padding:0 5px;
    border-radius: var(--radius-full); background: var(--status-dropped); color: var(--text-primary);
    border:2px solid var(--bg); font: 700 11px/16px var(--font-mono); text-align:center;
  }
  .chat.is-open .chat-fab-count{ display:none; }

  .chat-window{
    position:absolute; right:0; bottom: calc(100% + var(--space-3));
    width:380px; height:min(600px, calc(100vh - var(--topbar-h) - 110px));
    display:flex; flex-direction:column; overflow:hidden;
    background: var(--bg-elevated); border:1px solid var(--border-strong);
    border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  }
  .chat-window[hidden]{ display:none; }
  .chat-pane, .chat-screen{ display:flex; flex-direction:column; flex:1; min-height:0; }

  .chat-head{
    display:flex; align-items:center; gap: var(--space-2); flex:none;
    padding: var(--space-2) var(--space-2) var(--space-2) var(--space-4);
    min-height:54px; border-bottom:1px solid var(--border);
    background: var(--surface);
  }
  .chat-dialog .chat-head{ padding-left: var(--space-1); }
  .chat-title{ flex:1; font-size: var(--text-md); }
  .chat-icon-btn{
    width:34px; height:34px; flex:none; padding:0; border:none; border-radius:50%; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    background:none; color: var(--text-secondary);
  }
  .chat-icon-btn:hover{ background: var(--surface-hover); color: var(--text-primary); }
  .chat-icon-btn svg{ width:20px; height:20px; stroke:currentColor; }
  .chat-peer{ flex:1; min-width:0; display:flex; align-items:center; gap: var(--space-3); text-decoration:none; }
  .chat-peer .avatar{ width:38px; height:38px; border-radius:50%; font-size:12px; }
  .chat-peer-text{ display:flex; flex-direction:column; min-width:0; line-height:1.25; }
  .chat-peer-text b{ font-size: var(--text-base); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .chat-peer-sub{ font-size: var(--text-xs); color: var(--text-tertiary); }
  .chat-peer-sub.is-typing, .chat-row-text.is-typing{ color: var(--accent-fg); }

  .chat-search{
    display:flex; align-items:center; gap: var(--space-2); flex:none;
    margin: var(--space-3) var(--space-3) var(--space-1); padding: 0 var(--space-3);
    border-radius: var(--radius-full); background: var(--surface-sunken); border:1px solid var(--border-subtle);
  }
  .chat-search:focus-within{ border-color: var(--accent-border); }
  .chat-search svg{ width:16px; height:16px; flex:none; stroke: var(--text-tertiary); }
  .chat-search input{
    flex:1; min-width:0; height:36px; border:none; outline:none; background:none;
    color: var(--text-primary); font: inherit; font-size: var(--text-sm);
  }

  .chat-list{ flex:1; min-height:0; overflow-y:auto; padding: var(--space-1) var(--space-2) var(--space-2); }
  .chat-list[hidden]{ display:none; }
  .chat-row{
    width:100%; display:flex; align-items:center; gap: var(--space-3); text-align:left;
    padding: var(--space-2); border:none; border-radius: var(--radius-md); cursor:pointer;
    background:none; color: inherit; font: inherit;
  }
  .chat-row:hover, .chat-row:focus-visible{ background: var(--surface-hover); }
  .chat-row .avatar{ width:44px; height:44px; border-radius:50%; font-size:13px; }
  .chat-row-main{ flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
  .chat-row-top, .chat-row-bottom{ display:flex; align-items:center; gap: var(--space-2); min-width:0; }
  .chat-row-top b{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size: var(--text-sm); }
  .chat-row-top time{ flex:none; font-size: var(--text-2xs); color: var(--text-tertiary); font-family: var(--font-mono); }
  .chat-row-text{ flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size: var(--text-xs); color: var(--text-secondary); }
  .chat-you{ color: var(--text-tertiary); }
  .chat-badge{
    flex:none; min-width:20px; height:20px; padding:0 6px; border-radius: var(--radius-full);
    background: var(--accent); color: var(--bg-elevated); font: 700 11px/20px var(--font-mono); text-align:center;
  }
  .chat-tag{
    flex:none; padding:0 6px; border-radius: var(--radius-full); border:1px solid var(--accent-border);
    color: var(--accent-fg); font-size: var(--text-2xs); line-height:16px;
  }
  .chat-empty{ padding: var(--space-6) var(--space-4); text-align:center; font-size: var(--text-xs); color: var(--text-tertiary); }

  /* Лента диалога: фон чуть темнее окна, пузыри поверх. */
  .chat-scroll{
    flex:1; min-height:0; overflow-y:auto; overscroll-behavior:contain;
    padding: var(--space-2) var(--space-3) var(--space-3);
    background:
      radial-gradient(circle at 20% 10%, var(--accent-soft), transparent 45%),
      var(--surface-sunken);
  }
  .chat-messages{ display:flex; flex-direction:column; }
  .chat-day{ position:sticky; top:0; z-index:1; display:flex; justify-content:center; padding: var(--space-2) 0; }
  .chat-day span{
    padding:2px 10px; border-radius: var(--radius-full); font-size: var(--text-2xs); font-weight:600;
    background: var(--surface); color: var(--text-secondary); box-shadow: var(--shadow-sm);
  }

  .chat-msg{ position:relative; display:flex; align-items:flex-end; gap:4px; margin-top:2px; max-width:86%; }
  .chat-msg.is-first{ margin-top: var(--space-2); }
  .chat-msg.is-mine{ align-self:flex-end; flex-direction:row-reverse; }
  .chat-bubble{
    position:relative; min-width:0; padding:6px 10px 6px; border-radius:14px;
    background: var(--surface-hover); color: var(--text-primary);
    font-size: var(--text-sm); line-height:1.4; overflow-wrap:anywhere;
  }
  .chat-msg.is-mine .chat-bubble{ background: color-mix(in srgb, var(--accent) 42%, var(--bg-elevated)); }
  /* «Хвост» — у последнего в группе: угол пузыря острый со стороны автора. */
  .chat-msg.is-last:not(.is-mine) .chat-bubble{ border-bottom-left-radius:4px; }
  .chat-msg.is-last.is-mine .chat-bubble{ border-bottom-right-radius:4px; }
  .chat-text p{ margin:0; }
  .chat-text p + p, .chat-text ul, .chat-text ol, .chat-text pre, .chat-text blockquote{ margin-top:4px; }
  .chat-text ul, .chat-text ol{ padding-left:18px; }
  .chat-text ul{ list-style:disc; }
  .chat-text ol{ list-style:decimal; }
  .chat-text a{ color: var(--accent-fg); text-decoration:underline; text-underline-offset:2px; }
  .chat-msg.is-mine .chat-text a{ color: var(--text-primary); }
  .chat-text code{ font-family: var(--font-mono); font-size:.92em; padding:0 3px; border-radius: var(--radius-xs); background: var(--surface-sunken); }
  .chat-text pre{ padding: var(--space-2); border-radius: var(--radius-sm); background: var(--surface-sunken); overflow-x:auto; }
  .chat-text pre code{ padding:0; background:none; }
  .chat-text blockquote{ margin-left:0; padding-left: var(--space-2); border-left:2px solid var(--accent); color: var(--text-secondary); }
  .chat-text .spoiler{ background: var(--text-tertiary); color:transparent; border-radius: var(--radius-xs); padding:0 2px; cursor:pointer; transition: background .15s ease, color .15s ease; }
  .chat-text .spoiler:not(.is-shown) *{ color:transparent; pointer-events:none; }
  .chat-text .spoiler.is-shown, .chat-text .spoiler:focus-visible{ background: var(--surface-sunken); color: inherit; cursor:auto; outline:none; }
  .chat-text .spoiler:focus-visible *{ color: inherit; }

  /* Время и галочки — в правом нижнем углу пузыря, обтекаются текстом. */
  .chat-meta{
    float:right; display:inline-flex; align-items:center; gap:3px;
    margin: 4px 0 -2px 10px; position:relative; top:3px;
    font-size:10.5px; font-family: var(--font-mono); color: var(--text-tertiary); white-space:nowrap;
  }
  .chat-msg.is-mine .chat-meta{ color: var(--text-secondary); }
  .chat-edited{ font-family: var(--font-ui); font-style:italic; }
  .chat-tick, .chat-ticks{ width:15px; height:15px; stroke:currentColor; }
  .chat-msg .chat-ticks, .chat-msg.is-read .chat-tick{ display:none; }
  .chat-msg.is-read .chat-ticks{ display:block; stroke: var(--accent-fg); }

  .chat-game{
    display:flex; align-items:center; gap: var(--space-2); margin-top:6px; clear:both;
    padding:6px; border-radius: var(--radius-md); text-decoration:none;
    background: var(--surface-sunken); border-left:2px solid var(--accent);
  }
  .chat-game:hover{ background: var(--bg); }
  .chat-game .row-cover{ width:30px; }
  .chat-game-text{ display:flex; flex-direction:column; min-width:0; line-height:1.3; }
  .chat-game-text b{ font-size: var(--text-xs); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .chat-game-text span{ font-size: var(--text-2xs); color: var(--text-tertiary); font-family: var(--font-mono); }

  .chat-msg-act{
    flex:none; width:26px; height:26px; padding:0; border:none; border-radius:50%; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    background:none; color: var(--text-tertiary); opacity:0; transition: opacity .12s ease;
  }
  .chat-msg-act svg{ width:16px; height:16px; stroke:currentColor; }
  .chat-msg:hover .chat-msg-act, .chat-msg-act:focus-visible, .chat-msg:has(.chat-menu) .chat-msg-act{ opacity:1; }
  @media (hover: none){ .chat-msg-act{ opacity:.7; } }
  .chat-menu{
    position:absolute; z-index:3; right:0; bottom: calc(100% + 4px);
    display:flex; flex-direction:column; min-width:150px; padding: var(--space-1);
    border-radius: var(--radius-md); background: var(--bg-elevated);
    border:1px solid var(--border-strong); box-shadow: var(--shadow-md);
  }
  .chat-menu.is-below{ bottom:auto; top: calc(100% + 4px); }
  .chat-menu button{
    padding: 7px 10px; border:none; border-radius: var(--radius-sm); cursor:pointer; text-align:left;
    background:none; color: var(--text-primary); font: inherit; font-size: var(--text-sm);
  }
  .chat-menu button:hover, .chat-menu button:focus-visible{ background: var(--surface-hover); outline:none; }
  .chat-menu .is-danger{ color: var(--status-dropped-fg); }
  .chat-menu-ask{ padding: 6px 10px 4px; font-size: var(--text-xs); color: var(--text-secondary); }

  /* Поле ввода. */
  .chat-compose{ flex:none; padding: var(--space-2) var(--space-3) var(--space-2); border-top:1px solid var(--border); background: var(--surface); }
  .chat-compose-row{ display:flex; align-items:flex-end; gap: var(--space-2); }
  .chat-compose textarea{
    flex:1; min-width:0; resize:none; max-height:140px; padding: 9px 14px;
    border-radius:20px; border:1px solid var(--border); background: var(--surface-sunken);
    color: var(--text-primary); font: inherit; font-size: var(--text-sm); line-height:1.4;
  }
  .chat-compose textarea:focus{ outline:none; border-color: var(--accent-border); }
  .chat-send{
    width:38px; height:38px; flex:none; padding:0; border:none; border-radius:50%; cursor:pointer;
    display:flex; align-items:center; justify-content:center;
    background: var(--accent); color: var(--bg-elevated);
  }
  .chat-send svg{ width:19px; height:19px; stroke:currentColor; }
  .chat-compose.is-busy .chat-send{ opacity:.6; cursor:progress; }
  .chat-compose-hint{ display:flex; align-items:center; gap: var(--space-3); margin-top:4px; padding-left: var(--space-3); min-height:18px; }
  .chat-compose-hint .helptext{ font-size: var(--text-2xs); color: var(--text-tertiary); display:inline-flex; align-items:center; gap:4px; }
  /* Подсказка разметки — вверх: снизу окно её обрезало бы. */
  .chat-compose .help-tip-body{ top:auto; bottom: calc(100% + 6px); }
  .chat-error{ font-size: var(--text-2xs); color: var(--status-dropped-fg); }
  .chat-editing{ display:flex; align-items:center; gap: var(--space-2); margin-bottom: var(--space-2); padding-left: var(--space-2); border-left:2px solid var(--accent); }
  .chat-editing[hidden]{ display:none; }
  .chat-editing > svg{ width:16px; height:16px; flex:none; stroke: var(--accent-fg); }
  .chat-editing-text{ flex:1; min-width:0; display:flex; flex-direction:column; line-height:1.3; font-size: var(--text-xs); }
  .chat-editing-text b{ color: var(--accent-fg); }
  .chat-editing-text span{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color: var(--text-secondary); }
  .chat-blocked{
    flex:none; display:flex; align-items:center; justify-content:center; gap: var(--space-2);
    padding: var(--space-4); border-top:1px solid var(--border); background: var(--surface);
    font-size: var(--text-xs); color: var(--text-secondary); text-align:center;
  }
  .chat-blocked svg{ width:16px; height:16px; flex:none; stroke:currentColor; }

  /* «Написать» в разделах чужой страницы (partials/user_tabs.html). */
  .chat-write{ display:inline-flex; align-items:center; gap:5px; color: var(--accent-fg); border-color: var(--accent-border); }
  .chat-write svg{ width:14px; height:14px; stroke:currentColor; }

  @media (max-width: 620px){
    .chat{ right: var(--space-3); bottom: var(--space-3); }
    .chat-fab{ width:48px; height:48px; }
    /* На телефоне окно — во весь экран, кнопка под ним не нужна. */
    .chat.is-open{ inset:0; }
    .chat.is-open .chat-fab{ display:none; }
    .chat-window{ position:fixed; inset:0; width:auto; height:auto; border:none; border-radius:0; }
    html.chat-is-open, html.chat-is-open body{ overflow:hidden; }
    .chat-msg{ max-width:90%; }
  }

  /* — Эмоуты (apps/emotes, static/js/emotes.js, doc/emoty.md) —
       В тексте — картинка высотой со строку-полторы, как в чате Twitch.
       Кнопка выбора — рядом с «Форматированием», сетка всплывает над ней. */
  img.emote{ display:inline-block; height:28px; width:auto; vertical-align:middle; margin:-4px 1px; }
  .format-tools{ position:relative; display:inline-flex; align-items:center; gap: var(--space-2); }
  .emote-btn{
    width:24px; height:24px; flex:none; padding:0; border:none; border-radius:50%; cursor:pointer;
    display:inline-flex; align-items:center; justify-content:center;
    background:none; color: var(--text-tertiary);
  }
  .emote-btn:hover, .emote-btn:focus-visible{ color: var(--accent-fg); background: var(--surface-hover); outline:none; }
  .emote-btn svg{ width:18px; height:18px; stroke:currentColor; }
  .emote-picker{
    position:absolute; z-index:40; left:0; bottom: calc(100% + 6px);
    width:300px; max-width:calc(100vw - 2 * var(--space-4)); padding: var(--space-2);
    border-radius: var(--radius-md); background: var(--bg-elevated);
    border:1px solid var(--border-strong); box-shadow: var(--shadow-md);
  }
  .emote-search{
    width:100%; height:32px; padding:0 var(--space-3); margin-bottom: var(--space-2);
    border-radius: var(--radius-sm); border:1px solid var(--border); background: var(--surface-sunken);
    color: var(--text-primary); font: inherit; font-size: var(--text-sm);
  }
  .emote-search:focus{ outline:none; border-color: var(--accent-border); }
  .emote-grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(40px, 1fr)); gap:2px; max-height:220px; overflow-y:auto; }
  /* Ячейка — кнопка выбора и звёздочка «в избранное» в углу. Звезда видна
     при наведении и у избранных; на тачскрине — всегда, бледно. */
  .emote-cell{ position:relative; height:40px; }
  .emote-pick{
    width:100%; height:100%; padding:4px; border:none; border-radius: var(--radius-sm); cursor:pointer;
    display:flex; align-items:center; justify-content:center; background:none;
  }
  .emote-pick:hover, .emote-pick:focus-visible{ background: var(--surface-hover); outline:none; }
  .emote-pick img{ max-height:32px; max-width:100%; }
  .emote-star{
    position:absolute; top:-2px; right:-2px; width:18px; height:18px; padding:0;
    border:none; border-radius:50%; background:none; cursor:pointer;
    font-size:12px; line-height:18px; color: var(--text-tertiary); opacity:0;
  }
  .emote-cell:hover .emote-star, .emote-star:focus-visible, .emote-star.is-on{ opacity:1; }
  .emote-star:hover, .emote-star:focus-visible{ color: var(--accent-fg); background: var(--bg-elevated); outline:none; }
  .emote-star.is-on{ color: var(--tier-gold); }
  @media (hover: none){ .emote-star{ opacity:.5; } }
  .emote-section{
    grid-column:1 / -1; margin: var(--space-2) 0 0; padding: 0 var(--space-1);
    font-size: var(--text-xs); color: var(--text-tertiary);
  }
  .emote-section:first-child{ margin-top:0; }
  .emote-empty{ grid-column:1 / -1; padding: var(--space-3); text-align:center; font-size: var(--text-xs); color: var(--text-tertiary); }

  /* ── Страница входа: руки с редкими достижениями (doc/stranica-vhoda.md) ──
     Сцена — во всю ширину окна, а не .content: иначе на широком экране
     предплечья обрывались бы посреди страницы. 100vw шире окна на полосу
     прокрутки, поэтому у body этой страницы overflow-x:clip (clip, а не
     hidden: hidden сделал бы body контейнером прокрутки и сломал sticky
     шапку). Координаты орбит посчитаны от картинки руки: ладонь — 40-я
     единица из 134 по ширине SVG. */
  .page-login{ overflow-x:clip; }
  .login-stage{ position:relative; width:100vw; margin-inline:calc(50% - 50vw); min-height:600px; display:flex; align-items:center; justify-content:center; overflow:hidden; }
  .login-stage > .form-shell{ position:relative; z-index:2; }
  .login-hand{ position:absolute; inset:0; pointer-events:none; }
  .login-hand img{ position:absolute; bottom:90px; width:480px; height:auto; -webkit-mask-image:linear-gradient(to left, transparent 0, #000 22%); mask-image:linear-gradient(to left, transparent 0, #000 22%); filter:drop-shadow(0 -6px 18px var(--accent-soft)); }
  .login-hand-r img{ right:-100px; }
  .login-hand-l img{ left:-100px; transform:scaleX(-1); }
  .login-glow{ position:absolute; bottom:190px; width:220px; height:60px; border-radius: var(--radius-full); background:radial-gradient(closest-side, var(--accent-border), transparent); }
  .login-hand-r .login-glow{ right:155px; }
  .login-hand-l .login-glow{ left:155px; }

  .login-orbit{ --dur:26s; position:absolute; bottom:246px; width:300px; height:220px; z-index:1; pointer-events:none; }
  .login-orbit-r{ right:115px; }
  .login-orbit-l{ left:115px; }
  .login-badge{ position:absolute; top:0; left:0; width:112px; display:flex; flex-direction:column; align-items:center; gap: var(--space-1); text-align:center; pointer-events:auto; offset-rotate:0deg; animation: login-orbit-move var(--dur) linear infinite, login-orbit-depth var(--dur) linear infinite; animation-delay: calc(var(--dur) * var(--i) / var(--n) * -1); }
  .login-orbit-l .login-badge{ offset-path:path('M150 144 A115 34 0 1 1 150 76 A115 34 0 1 1 150 144'); }
  .login-orbit-r .login-badge{ offset-path:path('M150 144 A115 34 0 1 0 150 76 A115 34 0 1 0 150 144'); animation-delay: calc(var(--dur) * (var(--i) + .5) / var(--n) * -1); }
  /* Анимации выключены (система или переключатель сайта) — орбита стоит,
     но значки уже разложены по кругу отрицательными задержками. */
  html:not(.motion-on) .login-badge{ animation-play-state:paused; }
  @keyframes login-orbit-move{ from{ offset-distance:0%; } to{ offset-distance:100%; } }
  @keyframes login-orbit-depth{
    0%, 100%{ transform:scale(1.08); opacity:1; z-index:10; filter:none; }
    25%, 75%{ transform:scale(.84); opacity:.78; z-index:5; }
    50%{ transform:scale(.6); opacity:.38; z-index:1; filter:blur(.6px); }
  }
  .login-badge-tile{ position:relative; width:56px; height:56px; display:grid; place-items:center; border-radius: var(--radius-lg); background: var(--surface); border:2px solid var(--tier-gold); box-shadow: var(--shadow-md); overflow:hidden; outline:2px solid transparent; outline-offset:3px; transition: outline-color .2s, transform .2s; }
  .login-badge.is-platinum .login-badge-tile{ border-color: var(--tier-platinum); }
  .login-badge-tile img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
  .login-badge-fallback{ width:24px; height:24px; color: var(--tier-gold); }
  .login-badge-name{ max-width:100%; font-size: var(--text-xs); font-weight:600; color: var(--text-primary); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; transition: color .2s; }
  .login-badge-game{ max-width:100%; font-size: var(--text-2xs); color: var(--text-secondary); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; transition: color .2s; }
  .login-badge:hover .login-badge-tile{ outline-color: var(--text-primary); transform:translateY(-3px); }
  .login-badge:hover .login-badge-game{ color: var(--text-primary); }
  /* Уже ~1300px руки наезжают на форму — оставляем одну форму. */
  @media (max-width:1300px){
    .login-hand, .login-orbit{ display:none; }
    .login-stage{ width:auto; margin-inline:0; min-height:0; }
  }

