/* QUST RUST — site styles
   Palette is sampled from the server logo; lime is reserved for live state. */

:root{
  --bg:#0C0E13;
  --surface:#151922;
  --surface-2:#1C212C;
  --line:#28303D;
  --line-soft:#1E2530;

  --amber:#FF8A1F;
  --ember:#E8452A;
  --amber-dim:rgba(255,138,31,.14);

  /* магазин: единственная холодная точка в тёплой шапке */
  --shop:#2DD4BF;
  /* Тёмный конец подобран по контрасту, а не на глаз: с #0E8FA8 подпись давала
     4.36 при норме 4.5 для такого кегля. Здесь 5.33, и градиент не выпрямился. */
  --shop-deep:#12A0B8;

  --live:#9EE83C;
  --warn:#FFC53D;

  --text:#EAEDF2;
  --muted:#7E8899;
  --faint:#5A6474;

  --ui:"Segoe UI",system-ui,-apple-system,Roboto,sans-serif;
  --mono:Consolas,"JetBrains Mono","SF Mono",ui-monospace,monospace;

  --gut:clamp(.85rem,3vw,1.75rem);
  --maxw:1280px;
  --head-h:54px;
}

*{box-sizing:border-box}

/* element rules below set display on svg/img, which outranks the browser's own
   [hidden] rule — restate it so the attribute keeps working */
[hidden]{display:none !important}

body{
  margin:0;
  background:var(--bg);
  color:var(--text);
  font-family:var(--ui);
  font-size:14px;
  line-height:1.55;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}

.wrap{max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gut)}

/* ---------- type ---------- */
h1,h2,h3,h4{margin:0;font-weight:700;letter-spacing:-.005em;line-height:1.2;text-wrap:balance}
h1{font-size:1.375rem;text-transform:uppercase;letter-spacing:.01em}
h2{font-size:1.0625rem;text-transform:uppercase;letter-spacing:.02em}
h3{font-size:.9375rem}
.mono{font-family:var(--mono);font-variant-numeric:tabular-nums}
.lbl{font-family:var(--mono);font-size:.625rem;letter-spacing:.14em;text-transform:uppercase;color:var(--faint)}
a{color:inherit}

/* ---------- header ---------- */
.head{
  position:sticky;top:0;z-index:30;
  height:var(--head-h);
  display:flex;align-items:center;gap:var(--gut);
  padding-inline:var(--gut);
  background:rgba(12,14,19,.9);
  backdrop-filter:blur(14px);
  border-bottom:1px solid var(--line);
}
.brand{display:flex;align-items:center;gap:.55rem;text-decoration:none;flex:0 0 auto}
.brand img{width:30px;height:30px;display:block}
.brand .txt{display:block}
.brand .txt b{font-size:.8125rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;line-height:1;display:block;color:var(--text)}
.brand .txt span{font-family:var(--mono);font-size:.5625rem;letter-spacing:.16em;color:var(--faint);text-transform:uppercase;display:block;margin-top:.15rem}

.menu{display:flex;gap:.1rem;margin-left:auto;overflow-x:auto;scrollbar-width:none}
.menu::-webkit-scrollbar{display:none}
.menu a{
  font-size:.75rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  color:var(--muted);text-decoration:none;padding:.45rem .65rem;border-radius:4px;white-space:nowrap;
  transition:color .14s,background .14s;
}
.menu a:hover,.menu a:focus-visible{color:var(--text);background:var(--surface-2)}
.menu a.on{color:var(--amber);background:var(--amber-dim)}
/* the shop lives on another site — mark the jump so it is not a surprise */
.menu-out::after{content:"↗";margin-left:.25rem;font-size:.75em;opacity:.7}

.signin{
  flex:0 0 auto;font-size:.75rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  padding:.45rem .85rem;border:1px solid var(--line);border-radius:4px;text-decoration:none;
  transition:border-color .14s,background .14s;
}
.signin:hover{border-color:var(--muted);background:var(--surface)}
@media(max-width:800px){.signin{display:none}}

/* signed-in player */
.me{display:flex;align-items:center;gap:.5rem;flex:0 0 auto}
.me img{width:26px;height:26px;border-radius:4px;display:block;background:var(--surface-2)}
.me-name{font-size:.75rem;font-weight:600;max-width:9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.me form{margin:0}
.me-out{
  background:none;border:1px solid var(--line);border-radius:4px;cursor:pointer;
  color:var(--muted);font-family:var(--ui);font-size:.6875rem;letter-spacing:.04em;
  text-transform:uppercase;padding:.35rem .6rem;transition:color .14s,border-color .14s;
}
.me-out:hover{color:var(--text);border-color:var(--muted)}

.flash{border-bottom:1px solid var(--line);font-size:.8125rem}
.flash .wrap{padding-block:.6rem}
.flash-error{background:rgba(232,69,42,.14);color:#FFC9BC}
.flash-ok{background:rgba(158,232,60,.12);color:#DCF7B0}

/* ---------- rewards and the level ladder ---------- */
.rew{display:flex;align-items:center;gap:.8rem;padding:.7rem .85rem;border-bottom:1px solid var(--line-soft)}
.rew:last-child{border-bottom:0}
.rew form{margin:0}
.rew-icon{
  width:38px;height:38px;flex:0 0 auto;border-radius:6px;overflow:hidden;
  background:var(--surface-2);border:1px solid var(--line);display:grid;place-items:center;
}
.rew-icon img{width:100%;height:100%;object-fit:cover;display:block}
/* several reward icons point at files that no longer exist — a mark beats a hole */
.rew-icon-none{color:var(--amber);font-size:1rem;line-height:1}
.rew-body{flex:1 1 auto;min-width:0;display:grid;gap:.1rem}
.rew-body b{font-size:.875rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rew-past{opacity:.6}

.rung{display:flex;align-items:center;gap:.8rem;padding:.5rem .85rem;border-bottom:1px solid var(--line-soft)}
.rung:last-child{border-bottom:0}
.rung-n{width:2rem;flex:0 0 auto;font-variant-numeric:tabular-nums;color:var(--faint);font-size:.8125rem}
.rung-title{flex:1 1 auto;font-size:.8125rem;color:var(--muted)}
.rung-xp{flex:0 0 auto}
.rung-done .rung-n{color:var(--live)}
.rung-done .rung-title{color:var(--text)}
.rung-now{background:var(--amber-dim)}
.rung-now .rung-n,.rung-now .rung-title{color:var(--amber);font-weight:700}

/* ---------- status strip ---------- */
.status{
  position:sticky;top:var(--head-h);z-index:25;
  border-bottom:1px solid var(--line);
  background:rgba(12,14,19,.92);
  backdrop-filter:blur(14px);
}
.status-in{max-width:var(--maxw);margin-inline:auto;padding:.7rem var(--gut);display:flex;align-items:center;gap:1.5rem;flex-wrap:wrap}
.stat{display:flex;align-items:baseline;gap:.5rem}
.stat .v{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:1.0625rem;font-weight:700;line-height:1}
.stat .v.live{color:var(--live)}
.stat .v.warn{color:var(--warn)}
.pip{width:6px;height:6px;border-radius:50%;background:var(--live);align-self:center;animation:pip 2.4s ease-out infinite}
@keyframes pip{
  0%{box-shadow:0 0 0 0 rgba(158,232,60,.55)}
  70%{box-shadow:0 0 0 9px rgba(158,232,60,0)}
  100%{box-shadow:0 0 0 0 rgba(158,232,60,0)}
}
.status .grow{flex:1 1 auto}
/* Адрес сервера — кнопка копирования.

   font:inherit и margin:0 обязательны: без них браузер подставляет кнопке
   свой системный шрифт, и моноширинный адрес в шапке съезжает. */
.ip{
  font-family:var(--mono);font-size:.75rem;color:var(--muted);
  border:1px solid var(--line);border-radius:4px;padding:.4rem .6rem;
  background:var(--bg);margin:0;cursor:pointer;
  transition:color .15s,border-color .15s;
}
.ip:hover{color:var(--tx);border-color:var(--brand)}
.ip:active{transform:translateY(1px)}
.ip:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
.join{
  font-size:.75rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;
  padding:.55rem 1.1rem;border-radius:4px;border:0;cursor:pointer;text-decoration:none;
  background:linear-gradient(160deg,var(--amber),var(--ember));color:#1A0A04;
  transition:transform .14s,box-shadow .14s;display:inline-block;
}
.join:hover,.join:focus-visible{transform:translateY(-1px);box-shadow:0 8px 20px -8px rgba(232,69,42,.8)}
.join:disabled{cursor:wait;opacity:.8}
.join:disabled:hover{transform:none;box-shadow:none}
.join.on{box-shadow:0 0 0 3px rgba(255,138,31,.25)}

/* ---------- page shell ---------- */
main{padding-block:1.5rem 3rem}
.crumb{font-family:var(--mono);font-size:.625rem;letter-spacing:.14em;text-transform:uppercase;color:var(--faint);margin:0 0 1rem}
.crumb b{color:var(--amber);font-weight:400}
.ptitle{display:flex;align-items:flex-end;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin-bottom:1.25rem}
.ptitle p{color:var(--muted);margin:.35rem 0 0;max-width:52ch;font-size:.8125rem}

/* ---------- online gauge, inline in the status strip ---------- */
.gauge-wrap{display:flex;align-items:center;gap:.55rem;flex:1 1 10rem;min-width:7rem;max-width:32rem}
.gauge{
  position:relative;flex:1 1 auto;height:10px;border-radius:5px;overflow:hidden;
  border:1px solid var(--line);
  background:
    repeating-linear-gradient(90deg,transparent 0 calc(10% - 1px),var(--line-soft) calc(10% - 1px) 10%),
    var(--surface-2);
}
.gauge .fill{
  position:absolute;left:0;top:0;bottom:0;min-width:6px;border-radius:5px;
  background:linear-gradient(90deg,rgba(158,232,60,.4),var(--live));
  box-shadow:0 0 12px rgba(158,232,60,.55);
}
@media(max-width:620px){.gauge-wrap{order:9;flex-basis:100%;max-width:none}}

/* ---------- hub grid ---------- */
.hub{display:grid;gap:1rem;grid-template-columns:1fr;align-items:start}
@media(min-width:900px){
  .hub{grid-template-columns:minmax(0,1.55fr) minmax(0,1fr)}
  /* the side column is shorter than the feed — pin it so it stays in view
     instead of leaving a dead gap at the bottom */
  .hub>.col:last-child{position:sticky;top:calc(var(--head-h) + 60px)}
}
.col{display:grid;gap:1rem;align-content:start;min-width:0}

/* ---------- card ---------- */
.card{border:1px solid var(--line);border-radius:6px;background:var(--surface);overflow:hidden}
.card-h{display:flex;align-items:center;gap:.6rem;padding:.6rem .85rem;border-bottom:1px solid var(--line-soft);background:var(--surface-2)}
.card-h h2,.card-h h3{flex:1 1 auto;min-width:0}
.card-h a{font-family:var(--mono);font-size:.625rem;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);text-decoration:none}
.card-h a:hover{color:var(--amber)}
.card-b{padding:.85rem}
.card-b.flush{padding:0}

/* ---------- news ---------- */
.meta{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}
.meta time{font-family:var(--mono);font-size:.625rem;letter-spacing:.1em;color:var(--faint)}
/* was .5625rem — nine pixels of uppercase mono is below what anyone reads,
   and these are tags people scan */
.chip{font-family:var(--mono);font-size:.6875rem;letter-spacing:.08em;text-transform:uppercase;color:var(--amber);background:var(--amber-dim);padding:.12rem .4rem;border-radius:3px}

/* The lead story: a picture with its text underneath, not on top of it.
   Text laid over a photograph is only readable when the photograph agrees to
   it, and news covers are whatever the editor uploaded — here the date line
   sat on bare image and the summary was drawn in a grey meant for a dark
   surface, so the two ran together. The text has its own surface now, joined
   to the picture by a hairline so the two still read as one card. */
.lead{
  display:block;position:relative;text-decoration:none;overflow:hidden;
  border-bottom:1px solid var(--line-soft);
}
.lead-pic{display:block;position:relative;overflow:hidden}
.lead img{
  display:block;width:100%;height:auto;aspect-ratio:21/8;object-fit:cover;
  transition:transform .45s ease;
}
.lead:hover img,.lead:focus-visible img{transform:scale(1.035)}

/* a short fade at the foot of the picture so it settles into the text panel
   instead of stopping at a hard edge */
.lead-pic::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:35%;
  background:linear-gradient(180deg,transparent,color-mix(in srgb,var(--surface) 85%,transparent));
  pointer-events:none;
}

.lead .tx{
  display:grid;gap:.35rem;padding:.85rem .95rem 1rem;
  background:var(--surface);border-top:1px solid var(--line-soft);
}
/* one notch under the section heading above it, never over: a card shouting
   louder than the section that contains it inverts the hierarchy */
.lead h3{
  font-size:1rem;line-height:1.25;letter-spacing:-.01em;
  transition:color .14s;
}
.lead:hover h3,.lead:focus-visible h3{color:var(--amber)}
/* readable over a surface, unlike the --muted grey it used to wear */
/* two lines, then an ellipsis: the card is a doorway, not the article */
.lead p{
  margin:0;color:#C7CEDA;font-size:.875rem;line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}


.nrow{display:flex;gap:.75rem;align-items:flex-start;padding:.7rem .85rem;text-decoration:none;border-bottom:1px solid var(--line-soft);transition:background .14s}
.nrow:last-child{border-bottom:0}
.nrow:hover,.nrow:focus-visible{background:var(--surface-2)}
.nrow img{width:92px;height:62px;object-fit:cover;border-radius:4px;flex:0 0 auto;display:block}
.nrow .tx{display:grid;gap:.25rem;min-width:0}
.nrow p{
  margin:0;color:var(--muted);font-size:.8125rem;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
/* posts without a cover keep the same footprint */
.cover-none{
  width:92px;height:62px;border-radius:4px;flex:0 0 auto;display:block;
  background:linear-gradient(140deg,var(--surface-2),rgba(255,138,31,.16));
  border:1px solid var(--line);
}
.lead-none{width:100%;height:auto;aspect-ratio:21/8;border-radius:0;border:0}
.nrow.big .cover-none{width:158px;height:100px;border-radius:5px}
@media(max-width:560px){.nrow.big .cover-none{width:104px;height:70px}}

.empty-state{margin:0;padding:1rem .85rem;color:var(--faint);font-size:.8125rem}
.ch.on{background:var(--surface-2);box-shadow:inset 2px 0 0 var(--amber)}

.nrow.big{padding:.85rem;gap:1rem}
.nrow.big img{width:158px;height:100px;border-radius:5px}
@media(max-width:560px){.nrow.big img{width:104px;height:70px}}

/* ---------- article ---------- */
.article-cover{display:block;width:100%;height:auto;aspect-ratio:57/25;object-fit:cover}
.article-head{padding:1rem .95rem .25rem;display:grid;gap:.5rem}
.article-head h1{font-size:1.5rem;text-transform:none;letter-spacing:-.01em;line-height:1.2}

/* CMS bodies were written as standalone pages — these rules give them the
   site's typography without letting their own markup dictate the layout */
.article{padding:.5rem .95rem 1.25rem;max-width:70ch;color:var(--text)}
.article > *:first-child{margin-top:0}
.article p{margin:0 0 .9rem;color:#C7CEDA;font-size:.9375rem;line-height:1.65}
.article h1,.article h2,.article h3,.article h4{
  margin:1.6rem 0 .6rem;text-transform:none;letter-spacing:-.01em;line-height:1.25;
}
.article h1{font-size:1.25rem}
.article h2{font-size:1.125rem}
.article h3{font-size:1rem}
.article ul,.article ol{margin:0 0 .9rem;padding-left:1.2rem;color:#C7CEDA;font-size:.9375rem}
.article li{margin-bottom:.35rem}
.article a{color:var(--amber);text-decoration:underline;text-underline-offset:2px}
.article a:hover{color:var(--ember)}
.article img{max-width:100%;height:auto;border-radius:5px;margin:.5rem 0}
.article strong,.article b{color:var(--text)}
.article hr{border:0;border-top:1px solid var(--line);margin:1.5rem 0}
.article blockquote{
  margin:0 0 .9rem;padding:.6rem .9rem;border-left:2px solid var(--amber);
  background:var(--surface-2);border-radius:0 4px 4px 0;color:var(--muted);
}
.article code{font-family:var(--mono);font-size:.85em;background:var(--surface-2);padding:.1rem .3rem;border-radius:3px}
.article pre{overflow-x:auto;background:var(--surface-2);padding:.8rem;border-radius:5px;border:1px solid var(--line)}
.article table{width:100%;border-collapse:collapse;font-size:.875rem;margin:0 0 .9rem;display:block;overflow-x:auto}
.article th,.article td{border:1px solid var(--line);padding:.4rem .6rem;text-align:left}

.comment-cta{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;border-top:1px solid var(--line-soft)}
.comment-cta p{margin:0;color:var(--muted);font-size:.8125rem}

.comment-form{border-top:1px solid var(--line-soft);display:grid;gap:.6rem}
.cf-head{display:flex;align-items:center;gap:.5rem;font-size:.8125rem;font-weight:600}
.cf-head img{width:26px;height:26px;border-radius:4px;display:block}
.comment-form textarea{
  width:100%;resize:vertical;min-height:4.5rem;
  background:var(--bg);color:var(--text);
  border:1px solid var(--line);border-radius:5px;padding:.6rem .7rem;
  font-family:var(--ui);font-size:.875rem;line-height:1.5;
}
.comment-form textarea:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}
.comment-form textarea::placeholder{color:var(--faint)}
.cf-actions{display:flex;align-items:center;justify-content:space-between;gap:1rem}
.cf-error{margin:0;color:#FF9B86;font-size:.75rem}

/* ---------- rating ---------- */
.tabs{display:flex;overflow-x:auto;border-bottom:1px solid var(--line-soft);scrollbar-width:thin;background:var(--surface-2)}
.tabs a{
  flex:0 0 auto;border-bottom:2px solid transparent;text-decoration:none;
  font-family:var(--mono);font-size:.625rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);padding:.6rem .75rem;white-space:nowrap;
  transition:color .14s,border-color .14s;
}
.tabs a:hover{color:var(--text)}
.tabs a.on{color:var(--amber);border-bottom-color:var(--amber)}

.rrow{display:flex;align-items:center;gap:.7rem;padding:.55rem .85rem;border-bottom:1px solid var(--line-soft);text-decoration:none;transition:background .14s}
.rrow:last-child{border-bottom:0}
.rrow:hover{background:var(--surface-2)}
.rrow .n{font-family:var(--mono);font-size:.75rem;color:var(--faint);width:1.5rem;flex:0 0 auto}
.rrow:first-child .n{color:var(--amber)}
/* the ring itself comes from cosmetics.css; this only says how big the row's
   avatar is and what an unringed one looks like */
.rrow .av{flex:0 0 auto}
.rrow .av:not([class*=cos-av-]){box-shadow:0 0 0 1px var(--line)}
.rrow:first-child .av:not([class*=cos-av-]){box-shadow:0 0 0 1px color-mix(in srgb,var(--amber) 45%,var(--line))}
.nick-mark{flex:0 0 auto;font-size:.75rem;line-height:1}
.rrow .nick{
  flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:.8125rem;display:flex;align-items:center;gap:.1rem;
}
/* a plate or an underline needs room to draw around the letters */
.rrow .nick .cos-name{min-width:0;overflow:hidden;text-overflow:ellipsis}
.rrow .sc{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:.8125rem;flex:0 0 auto}
.rrow:first-child .sc{color:var(--live)}

/* Six earned achievements say who someone is; the rest open on request so a
   long collection does not own the page. */
.achmore{margin-top:.6rem}
.achmore > summary{
  list-style:none;cursor:pointer;padding:.45rem .7rem;border-radius:5px;
  border:1px dashed var(--line);color:var(--muted);font-size:.8125rem;text-align:center;
}
.achmore > summary::-webkit-details-marker{display:none}
.achmore > summary:hover{border-color:var(--amber);color:var(--amber)}
.achmore .achgrid{margin-top:.6rem}
.achmore .achmore-close{display:none}
.achmore[open] .achmore-open{display:none}
.achmore[open] .achmore-close{display:inline}

/* the summary card in the right column */
.facts{display:grid;gap:.5rem}
.fact{display:flex;align-items:baseline;justify-content:space-between;gap:.75rem}
.fact b{font-size:.8125rem;text-align:right}

/* numbers that no ranking covers — the filler that stops a plain profile
   being a level and nothing else */
.feats{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(9rem,1fr))}
.feat{
  display:grid;gap:.1rem;padding:.6rem .7rem;
  border:1px solid var(--line);border-radius:6px;background:var(--surface-2);
}
.feat b{font-size:1.0625rem;line-height:1.2;color:var(--text)}

/* ---------- profile showcase ---------- */
.showcase{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))}
.showcase-base,.showcase-ach{
  display:flex;align-items:center;gap:.7rem;padding:.6rem;text-decoration:none;
  border:1px solid var(--line);border-radius:6px;background:var(--surface-2);
}
.showcase-base:hover{border-color:var(--amber)}
.showcase-img{width:76px;height:48px;flex:0 0 auto;border-radius:4px;overflow:hidden;background:var(--bg)}
.showcase-img img{width:100%;height:100%;object-fit:cover;display:block}
.showcase-tx{display:grid;gap:.1rem;min-width:0}
.showcase-tx b{font-size:.875rem;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.showcase-base:hover .showcase-tx b{color:var(--amber)}
.showcase-ach{border-left:2px solid var(--tier,var(--line))}
.showcase-ach.t-1{--tier:#c77b3e}.showcase-ach.t-2{--tier:#afbac9}.showcase-ach.t-3{--tier:var(--amber)}

.profileform{display:grid;gap:.7rem;justify-items:start;margin-top:.6rem}
.profileform-row{display:grid;gap:.7rem;grid-template-columns:repeat(auto-fit,minmax(13rem,1fr));width:100%}
.profileform .field{width:100%}
.profileform textarea,.profileform select{
  width:100%;background:var(--bg);color:var(--text);
  border:1px solid var(--line);border-radius:5px;padding:.5rem .6rem;
  font-family:var(--ui);font-size:.8125rem;
}
.profileform textarea{resize:vertical}
.profileform textarea:focus,.profileform select:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}

/* ---------- the shop ---------- */
/* cold against the amber RAD balance beside it, so the two never blur together */
.kpi-wallet .kpi-k,.kpi-wallet .kpi-v,.wallet-count{color:#5fd4e8}
/* the mark and its number travel together and never wrap apart */
.coin{display:inline-flex;align-items:center;gap:.3rem;white-space:nowrap}
.coin-img{display:block;flex:0 0 auto}
.coin-mark{line-height:1}
.coin-n{font-family:var(--mono);font-variant-numeric:tabular-nums}
.shop-off{background:none;border:0;cursor:pointer;color:var(--faint)}
.shop-off:hover{color:var(--ember)}

.shopgrid{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fill,minmax(9.5rem,1fr))}
.shopitem{
  display:grid;gap:.45rem;padding:.7rem;align-content:start;
  border:1px solid var(--line);border-radius:6px;background:var(--surface-2);
}
.shopitem.on{border-color:#5fd4e8;box-shadow:inset 0 0 0 1px rgba(95,212,232,.25)}

/* every card shows the thing itself — nobody should buy a look unseen */
.shop-preview{height:4.25rem;display:grid;place-items:center;border-radius:5px;background:var(--bg)}
.shop-av{width:44px;height:44px;border-radius:50%;object-fit:cover;display:block}
.shop-name{font-size:.9375rem;font-weight:600}
.shop-cover{width:80%;height:2.5rem;border-radius:4px;background:linear-gradient(135deg,var(--c1),var(--c2))}
.shop-mark{font-size:1.75rem;line-height:1}

.shop-tx{display:grid;gap:.1rem}
.shop-tx b{font-size:.8125rem;line-height:1.25}
.shop-price{font-family:var(--mono);font-size:.75rem;color:#5fd4e8}
.shop-btn{width:100%;text-align:center;justify-content:center;font-size:.75rem;padding:.35rem .6rem}
.shop-btn:disabled{opacity:.45;cursor:not-allowed}
.shop-btn.ghost{background:var(--surface);color:var(--text);box-shadow:inset 0 0 0 1px var(--line)}
.shop-worn{font-size:.75rem;color:#5fd4e8;text-align:center}

.ledger{display:grid;gap:.15rem;margin-top:.5rem}
.ledger-row{display:flex;align-items:baseline;gap:.6rem;padding:.35rem 0;border-bottom:1px solid var(--line-soft)}
.ledger-row:last-child{border-bottom:0}
.ledger-d{font-family:var(--mono);font-size:.8125rem;width:3.5rem;flex:0 0 auto;text-align:right}
.ledger-d.plus{color:var(--live)}
.ledger-d.minus{color:var(--ember)}
.ledger-why{flex:1 1 auto;min-width:0;font-size:.8125rem;color:var(--muted)}
.ledger-after{flex:0 0 auto;font-family:var(--mono)}

/* ---------- profile decoration ---------- */
.player-card{overflow:hidden}
/* Plain surface when nothing is worn — an empty strip should read as part of
   the card, not as an image that failed to load. */
.player-bio{margin:.35rem 0 0;color:var(--muted);font-size:.8125rem;line-height:1.5;max-width:52ch}

/* ---------- player profile ---------- */
.player-head{display:flex;align-items:center;gap:1rem;flex-wrap:wrap}
.player-av{width:72px;height:72px;border-radius:6px;display:block;flex:0 0 auto;background:var(--surface-2)}
.player-av-none{border:1px solid var(--line);background:linear-gradient(140deg,var(--surface-2),rgba(255,138,31,.16))}
.player-id{flex:1 1 12rem;min-width:0;display:grid;gap:.25rem}
.player-id h1{font-size:1.375rem;text-transform:none;letter-spacing:-.01em}
.player-facts{display:flex;gap:1rem;flex-wrap:wrap;color:var(--muted);font-size:.8125rem;margin-top:.15rem}
.player-facts b{color:var(--text)}
.btn-steam-link{
  flex:0 0 auto;font-size:.75rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  padding:.5rem .9rem;border:1px solid var(--line);border-radius:4px;text-decoration:none;
  transition:border-color .14s,background .14s;
}
.btn-steam-link:hover{border-color:var(--muted);background:var(--surface-2)}

.player-actions{display:flex;align-items:center;gap:.5rem;flex:0 0 auto}
.player-actions form{margin:0}
.likebtn{
  display:inline-flex;align-items:center;gap:.4rem;cursor:pointer;text-decoration:none;
  background:var(--surface-2);border:1px solid var(--line);border-radius:4px;
  color:var(--muted);font-family:var(--ui);font-size:.8125rem;padding:.45rem .75rem;
  transition:color .14s,border-color .14s,background .14s;
}
.likebtn:hover{color:var(--ember);border-color:var(--ember)}
.likebtn.on{color:var(--ember);border-color:var(--ember);background:rgba(232,69,42,.12)}
.likebtn.static{cursor:default}
.likebtn.static:hover{color:var(--muted);border-color:var(--line)}

.rankrow{display:flex;align-items:center;gap:.8rem;padding:.6rem .85rem;border-bottom:1px solid var(--line-soft);text-decoration:none;transition:background .14s}
.rankrow:last-child{border-bottom:0}
.rankrow:hover{background:var(--surface-2)}
.rank-place{font-family:var(--mono);font-variant-numeric:tabular-nums;font-size:.9375rem;color:var(--muted);width:2.75rem;flex:0 0 auto}
.rank-place.top{color:var(--amber);font-weight:700}
.rank-label{flex:1 1 auto;font-size:.875rem}
.rank-of{flex:0 0 auto}
.rank-value{flex:0 0 auto;font-variant-numeric:tabular-nums;font-size:.875rem;color:var(--text)}

/* ---------- cabinet ---------- */
/* a thin lit edge marks the page you are "inside" rather than browsing */
.cab-head{margin-bottom:1rem;position:relative;overflow:hidden}
.cab-head::before{
  content:"";position:absolute;inset:0 0 auto 0;height:2px;
  background:linear-gradient(90deg,var(--amber),var(--ember),transparent 75%);
}
.cab-id{display:flex;align-items:center;gap:1rem;flex-wrap:wrap;padding:.95rem}
.cab-id-actions{display:flex;align-items:center;gap:.5rem;margin-left:auto;flex:0 0 auto}
.cab-id-actions form{margin:0}

/* the four figures a player checks first */
.kpis{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));
  gap:1px;background:var(--line-soft);border-top:1px solid var(--line-soft);
}
.kpi{background:var(--surface);padding:.85rem .95rem;display:grid;gap:.2rem;align-content:start}
.kpi-k{font-family:var(--mono);font-size:.5625rem;letter-spacing:.14em;text-transform:uppercase;color:var(--faint)}
.kpi-v{font-size:1.25rem;line-height:1.15;font-variant-numeric:tabular-nums}
.kpi-v.hot{color:var(--amber)}
.kpi-v.none{color:var(--faint);font-size:.9375rem;font-weight:400}
.kpi-sub{font-size:.6875rem;color:var(--muted)}
.kpi-bar{display:block;height:3px;border-radius:2px;background:var(--surface-2);overflow:hidden;margin-top:.25rem}
.kpi-bar>span{display:block;height:100%;background:linear-gradient(90deg,var(--amber),var(--ember))}
.kpi-level{background:linear-gradient(140deg,rgba(255,138,31,.10),var(--surface) 70%)}

/* sidebar + pane */
.cabinet{display:grid;gap:1rem;grid-template-columns:1fr;align-items:start}
@media(min-width:900px){
  .cabinet{grid-template-columns:14rem minmax(0,1fr)}
  .cab-nav{position:sticky;top:calc(var(--head-h) + 60px)}
}
.cab-nav{
  display:flex;flex-direction:column;gap:1px;
  background:var(--line-soft);border:1px solid var(--line);border-radius:6px;overflow:hidden;
}
@media(max-width:899px){.cab-nav{flex-direction:row;overflow-x:auto;gap:1px}}
.cab-nav a{
  display:flex;align-items:center;justify-content:space-between;gap:.5rem;
  background:var(--surface);padding:.6rem .85rem;text-decoration:none;
  font-size:.8125rem;color:var(--muted);white-space:nowrap;
  transition:color .14s,background .14s;
}
.cab-nav a:hover{color:var(--text);background:var(--surface-2)}
.cab-nav a.on{color:var(--amber);background:var(--amber-dim);box-shadow:inset 2px 0 0 var(--amber)}
.cab-nav-badge{
  font-family:var(--mono);font-size:.625rem;padding:0 .35rem;border-radius:20px;
  background:var(--surface-2);color:var(--muted);
}
.cab-nav a.on .cab-nav-badge{background:var(--amber);color:#1A0A04}
/* staff only — set apart so it does not read as another player section */
.cab-nav-admin{border-top:1px solid var(--line)}
.cab-nav-admin span:first-child{color:var(--ember)}
.cab-nav-admin .cab-nav-badge{text-transform:uppercase;font-size:.5625rem;letter-spacing:.08em}
/* .card clips its corners, but the inventory's detail panel has to escape the
   pane to be readable — it is the one card that must not clip */
.cab-pane{min-width:0;overflow:visible}

/* pane heading and its tools */
.pane-head{
  display:flex;align-items:flex-end;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  padding:.85rem .95rem;border-bottom:1px solid var(--line-soft);
}
.pane-head h2{font-size:1rem}
.pane-head p{margin:.25rem 0 0;color:var(--muted);font-size:.8125rem;max-width:52ch}
.pane-tools{
  display:flex;align-items:center;gap:.75rem;flex-wrap:wrap;
  padding:.7rem .95rem;border-bottom:1px solid var(--line-soft);background:var(--surface-2);
}
.switch{display:flex;gap:1px;background:var(--line);border:1px solid var(--line);border-radius:5px;overflow:hidden}
.switch a{
  display:flex;align-items:center;gap:.35rem;padding:.4rem .8rem;text-decoration:none;
  background:var(--surface);color:var(--muted);font-size:.75rem;transition:color .14s,background .14s;
}
.switch a:hover{color:var(--text)}
.switch a.on{background:var(--amber);color:#1A0A04;font-weight:600}
.switch a span{font-family:var(--mono);font-size:.6875rem;opacity:.8}
.pane-search{
  flex:1 1 14rem;min-width:0;background:var(--bg);color:var(--text);
  border:1px solid var(--line);border-radius:5px;padding:.45rem .7rem;
  font-family:var(--ui);font-size:.8125rem;
}
.pane-search:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}

/* reward cards */
/* ---------- inventory: item tiles ---------- */
/* Rarity is the whole visual language here — the tint drives the border, the
   glow, the corner wedge and the name, so one variable per tier sets all of it. */
/* One ladder, matching App\Items\Rarity — the card sets --rar inline from it,
   so these are the fallback for anything rendered without one. */
.item.r-common   {--rar:#8B95A5}
.item.r-uncommon {--rar:#9EE83C}
.item.r-rare     {--rar:#4EA8FF}
.item.r-epic     {--rar:#B36BFF}
.item.r-legendary{--rar:#FFC24A}

.invgrid{
  display:grid;gap:.6rem;
  grid-template-columns:repeat(auto-fill,minmax(7.5rem,1fr));
}

.item{position:relative;display:grid;gap:.4rem;cursor:default}
.item[hidden]{display:none}

.item-cell{
  position:relative;aspect-ratio:1;display:grid;place-items:center;
  border:1px solid color-mix(in srgb,var(--rar) 45%,var(--line));
  border-radius:6px;overflow:hidden;
  background:
    radial-gradient(120% 90% at 50% 100%,color-mix(in srgb,var(--rar) 22%,transparent),transparent 70%),
    var(--surface-2);
  transition:border-color .14s,transform .14s,box-shadow .14s;
}
.item:hover .item-cell,
.item:focus-visible .item-cell{
  border-color:var(--rar);
  transform:translateY(-2px);
  box-shadow:0 6px 20px -8px color-mix(in srgb,var(--rar) 70%,transparent);
}
.item:focus-visible{outline:none}

/* the corner wedge reads as rarity at a glance, the way a game inventory does */
.item-cell::after{
  content:'';position:absolute;right:0;bottom:0;
  border:.42rem solid transparent;border-right-color:var(--rar);border-bottom-color:var(--rar);
  opacity:.9;
}

/* the tile is a button when the thing inside can be tried on */
button.item-cell{
  width:100%;padding:0;margin:0;font:inherit;color:inherit;
  cursor:pointer;-webkit-appearance:none;appearance:none;
}
button.item-cell:focus-visible{outline:2px solid var(--rar);outline-offset:2px}
.item:hover .item-cell{border-color:var(--rar)}

.item-icon{max-width:72%;max-height:72%;object-fit:contain;display:block}
.item-icon-none{font-size:1.75rem;color:var(--rar);opacity:.75}

.item-mark{
  position:absolute;left:.35rem;top:.35rem;display:grid;place-items:center;
  width:1.15rem;height:1.15rem;border-radius:50%;
  background:rgba(12,14,19,.85);color:var(--live);font-size:.6875rem;line-height:1;
}
.item-mark.auto{color:var(--amber)}
.item-mark.on{color:var(--live)}
.item-mark.left{right:auto;left:.3rem}
.item-mark.left.hold{left:auto;right:1.9rem}
.item.is-taken .item-cell{opacity:.62}
.item.is-taken:hover .item-cell{opacity:1}

.item-name{
  font-size:.75rem;line-height:1.25;color:var(--text);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}

/* The item's number, printed on the tile the way a game stencils a serial on a
   crate. Quiet by default — it is an address, not a name — and legible the
   moment the tile is under the pointer. */
.item-uid{
  font-family:var(--mono);font-size:.5625rem;letter-spacing:.06em;
  color:var(--faint);opacity:.7;transition:color .14s,opacity .14s;
}
.item:hover .item-uid,
.item:focus-within .item-uid{color:var(--rar);opacity:1}

.uid-copy{
  font-family:var(--mono);font-size:.6875rem;
  background:none;border:0;padding:0;cursor:pointer;
  color:var(--muted);border-bottom:1px dashed var(--line);
}
.uid-copy:hover{color:var(--rar);border-bottom-color:var(--rar)}
.uid-copy.done{color:var(--live);border-bottom-color:transparent}

.inv-slot-uid{
  font-family:var(--mono);font-size:.5625rem;letter-spacing:.06em;color:var(--faint);
}

/* Read-only panel, Steam-style: floats over the grid, never pushes it.

   pointer-events:none is the whole trick. It holds nothing to click, so the
   pointer passes straight through it — it cannot swallow a click meant for the
   tile underneath, and it cannot be «reached», which means the gap between it
   and its tile stops mattering. The buttons live in the item's window instead.

   Shown by a class, not by :hover, so inventory.js can place it before it
   appears — showing first and moving second is what made it jump. The :hover
   rule below is the fallback for a grid the script has not claimed. */
.item-tip{
  position:absolute;left:50%;top:calc(100% + .45rem);transform:translate(-50%,4px);
  width:16rem;max-width:78vw;z-index:30;
  display:grid;gap:.45rem;padding:.75rem;
  background:var(--surface);border:1px solid var(--rar);border-radius:6px;
  box-shadow:0 14px 34px -12px rgba(0,0,0,.85);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .13s,transform .13s,visibility .13s;
}
.item.tip-on .item-tip,
.invgrid:not([data-tip="js"]) .item:hover .item-tip,
.item:focus-within .item-tip{opacity:1;visibility:visible;transform:translate(-50%,0)}
.item.tip-on .item-tip[style*="fixed"],
.item:focus-within .item-tip[style*="fixed"]{transform:none}

.pop-open{font-size:.625rem;text-align:center;padding-top:.15rem;border-top:1px solid var(--line-soft);color:var(--faint)}

.pop-name{font-size:.875rem;line-height:1.25}
.pop-rarity{font-size:.6875rem;color:var(--rar);text-transform:uppercase;letter-spacing:.06em}
.pop-note{margin:0;color:var(--muted);font-size:.75rem;line-height:1.45}
.pop-meta{margin:0;display:grid;gap:.2rem;padding-top:.4rem;border-top:1px solid var(--line-soft)}
.pop-meta > div{display:flex;justify-content:space-between;gap:.6rem}
.pop-meta dt{color:var(--faint);font-size:.6875rem}
.pop-meta dd{margin:0;font-size:.6875rem;color:var(--muted);text-align:right;overflow-wrap:anywhere}
.pop-meta code{font-family:var(--mono);font-size:.625rem}
.pop-btn{width:100%;text-align:center;justify-content:center;margin-top:.15rem}
.pop-auto{text-align:center;padding-top:.2rem;display:block;color:var(--muted);font-size:.75rem}
.item-acts form{margin:0}
.item-acts .mkt-btn{width:100%}

/* On a phone there is no hover and no room to float: tapping a tile focuses it
   and the details rise from the bottom of the screen instead. */
/* On a phone there is no hover at all: a tap opens the item's window, which is
   where everything is anyway, so the panel simply stays out of the way. */
@media(max-width:640px){
  .item-tip{display:none}
}

/* What the last press did, said where it happened. The page-wide flash bar
   sits at the top and a frame swap never scrolls there, so it would have
   announced itself to nobody. */
.bag-said{
  margin:0 0 .75rem;padding:.5rem .75rem;font-size:.8125rem;
  border:1px solid color-mix(in srgb,var(--live) 40%,var(--line));border-radius:6px;
  background:color-mix(in srgb,var(--live) 8%,transparent);color:var(--text);
}
.bag-said.bad{
  border-color:rgba(232,69,42,.5);background:rgba(232,69,42,.14);color:#FFC9BC;
}

/* Доля игроков, взявших ступень — как в Steam. Одно число отвечает на вопрос,
   на который карточка сама ответить не может: это трудно или этим просто никто
   не занимался. Полоса даёт то же самое, не заставляя читать цифру. */
.achcard-rare{
  display:grid;grid-template-columns:1fr auto;gap:.15rem .5rem;align-items:baseline;
  margin-top:.45rem;padding-top:.4rem;border-top:1px solid var(--line-soft);
}
.achcard-rare .rare-band{font-size:.625rem;letter-spacing:.04em;text-transform:uppercase;color:var(--rar)}
.achcard-rare .rare-pct{font-size:.6875rem;color:var(--muted)}
.achcard-rare .rare-bar{
  grid-column:1 / -1;height:2px;border-radius:2px;background:var(--line);overflow:hidden;
}
.achcard-rare .rare-bar > span{display:block;height:100%;background:var(--rar)}

.achcard-rare.r-common   {--rar:#8B95A5}
.achcard-rare.r-uncommon {--rar:#9EE83C}
.achcard-rare.r-rare     {--rar:#4EA8FF}
.achcard-rare.r-epic     {--rar:#B36BFF}
.achcard-rare.r-legendary{--rar:#FFC24A}

.pane-count{font-family:var(--mono);font-size:1.125rem;color:var(--live);white-space:nowrap}
.chip-muted{color:var(--muted);background:var(--surface);border:1px solid var(--line)}
.rewgrid-none{padding:1rem;text-align:center}
.rewgrid-none[hidden]{display:none}

/* ---------- referrals ---------- */
.reflink{display:grid;gap:.4rem;margin-bottom:1rem}
.reflink-row{display:flex;gap:.5rem;flex-wrap:wrap}
.reflink-row input{
  flex:1 1 16rem;min-width:0;background:var(--bg);color:var(--text);
  border:1px solid var(--line);border-radius:5px;padding:.55rem .7rem;
  font-family:var(--mono);font-size:.8125rem;
}
.reflink-row input:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}

.refsum{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(7rem,1fr));margin-bottom:1rem}
.refsum-i{
  display:grid;gap:.1rem;padding:.6rem .75rem;border-radius:6px;
  background:var(--surface-2);border:1px solid var(--line);
}
.refsum-i b{font-family:var(--mono);font-size:1.25rem;line-height:1}
.refsum-i.good b{color:var(--live)}
.refrewards{display:grid;gap:.4rem}
.refreward-list{display:flex;flex-wrap:wrap;gap:.35rem}

/* level catalogue */
.lvl-top{display:grid;gap:1rem;grid-template-columns:1fr;border-bottom:1px solid var(--line-soft)}
@media(min-width:760px){.lvl-top{grid-template-columns:1fr 1fr}}
.lvl-now,.lvl-next{
  display:grid;gap:.3rem;align-content:start;padding:.85rem;
  border:1px solid var(--line);border-radius:6px;background:var(--surface-2);
}
.lvl-now{background:linear-gradient(140deg,rgba(255,138,31,.12),var(--surface-2) 70%)}
.lvl-now b{font-size:1.5rem;line-height:1}
.lvl-now-title{color:var(--amber);font-size:.875rem}
.lvl-next p{margin:0}

.lvlgrid{display:grid;gap:.75rem;grid-template-columns:repeat(auto-fill,minmax(12rem,1fr))}
.lvlcard{
  display:grid;gap:.35rem;align-content:start;padding:.7rem;
  border:1px solid var(--line);border-radius:6px;background:var(--surface-2);opacity:.65;
}
.lvlcard.is-open{opacity:1}
.lvlcard.is-now{border-color:var(--amber);background:linear-gradient(140deg,rgba(255,138,31,.14),var(--surface-2) 70%);opacity:1}
.lvlcard header{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
.lvlcard h3{font-size:.875rem}

.chips{display:flex;flex-wrap:wrap;gap:.3rem;margin-top:.15rem}
.rchip{
  display:inline-flex;align-items:center;gap:.3rem;
  background:var(--surface);border:1px solid var(--line);border-radius:4px;
  padding:.15rem .4rem;font-size:.6875rem;color:var(--muted);
}
.rchip img{width:14px;height:14px;object-fit:contain;display:block}

/* in-game appearance */
.ingame{display:grid;gap:1.5rem;grid-template-columns:1fr}
@media(min-width:820px){.ingame{grid-template-columns:1fr 1fr}}
.ingame-block{display:grid;gap:.6rem;align-content:start;min-width:0}

/* a live sample says more than two hex codes */
.chatline{
  padding:.7rem .85rem;border-radius:6px;border:1px solid var(--line);
  background:#07090C;font-size:.875rem;line-height:1.5;
}
.chatline-nick{font-weight:600}
.chatline-prefix{opacity:.85;margin-right:.25rem}

.swatches{display:grid;gap:.5rem;grid-template-columns:repeat(auto-fit,minmax(11rem,1fr))}
.swatch{
  display:flex;align-items:center;gap:.6rem;padding:.55rem .7rem;
  border:1px solid var(--line);border-radius:6px;background:var(--surface-2);
}
.swatch-dot{width:22px;height:22px;border-radius:6px;flex:0 0 auto;box-shadow:inset 0 0 0 1px rgba(255,255,255,.14)}
.swatch-tx{display:grid;gap:.1rem;min-width:0}
/* the labels are short but must not wrap — a two-line caption skews the row */
.swatch-tx .lbl{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.swatch-tx b{font-size:.8125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.priv{
  display:flex;align-items:center;gap:.7rem;padding:.6rem .7rem;
  border:1px solid var(--line);border-radius:6px;background:var(--surface-2);
}
.priv-mark{color:var(--amber);flex:0 0 auto}
.priv-tx{flex:1 1 auto;min-width:0;display:grid;gap:.1rem}
.priv-tx b{font-size:.8125rem}
.priv-until{flex:0 0 auto;text-align:right;font-size:.75rem;color:var(--muted);display:grid;gap:.1rem}
.priv-until.forever{color:var(--live)}

/* an empty section explains itself rather than showing a dash */
.blank{display:grid;gap:.5rem;justify-items:center;text-align:center;padding:1.75rem 1rem;max-width:34rem;margin-inline:auto}
.blank-mark{font-size:1.75rem;line-height:1;opacity:.65}
.blank b{font-size:.9375rem}
.blank p{margin:0;color:var(--muted);font-size:.8125rem;line-height:1.55}
.blank .join{margin-top:.35rem}
.blank-line{margin:0;color:var(--faint);font-size:.8125rem;line-height:1.55}

.tab-badge{
  display:inline-block;margin-left:.3rem;padding:0 .3rem;border-radius:20px;
  background:var(--amber-dim);color:var(--amber);font-size:.9em;
}

.cab-grid{display:grid;gap:1.5rem;grid-template-columns:1fr}
@media(min-width:820px){.cab-grid{grid-template-columns:1fr 1fr}}
.cab-grid-2{display:grid;gap:1.5rem;grid-template-columns:1fr}
@media(min-width:820px){.cab-grid-2{grid-template-columns:1fr 1fr}}
.cab-block{display:grid;gap:.5rem;align-content:start;min-width:0}
.cab-block-h{display:flex;align-items:baseline;justify-content:space-between;gap:1rem}
.cab-block-h a{text-decoration:none}
.cab-block-h a:hover{color:var(--amber)}
.cab-h{font-size:.75rem;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:700;margin:0}
.rungs{display:grid;border:1px solid var(--line-soft);border-radius:5px;overflow:hidden}

.cab-hint{border-top:1px solid var(--line-soft);border-bottom:1px solid var(--line-soft)}
.cab-hint p{margin:0;color:var(--muted);font-size:.8125rem}
.cab-hint-row{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap}
.cab-hint-row form{margin:0}

.mini-ach{display:grid;gap:.3rem;padding:.5rem 0;border-bottom:1px solid var(--line-soft)}
.mini-ach:last-child{border-bottom:0}
.mini-ach-top{display:flex;align-items:baseline;justify-content:space-between;gap:.75rem}
.mini-ach-top b{font-size:.8125rem}

.ach-group{display:flex;align-items:baseline;gap:.75rem;padding:.6rem .85rem;background:var(--surface-2);border-bottom:1px solid var(--line-soft)}
.ach-group-h{font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--amber)}

.mine-row{display:flex;align-items:center;gap:.7rem;padding:.55rem 0;border-bottom:1px solid var(--line-soft);text-decoration:none}
.mine-row:last-child{border-bottom:0}
.mine-thumb{width:54px;height:36px;flex:0 0 auto;border-radius:4px;overflow:hidden;background:var(--surface-2);border:1px solid var(--line)}
.mine-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.mine-tx{flex:1 1 auto;min-width:0;display:grid;gap:.1rem}
.mine-tx b{font-size:.8125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mine-stats{flex:0 0 auto;display:flex;gap:.9rem;text-align:right}
.mine-stat{display:grid;gap:.05rem;line-height:1.2}
.mine-stat b{font-family:var(--mono);font-size:.8125rem;color:var(--muted)}
.mine-stat.hot b{color:var(--live)}

.ref-row{display:flex;align-items:center;gap:.7rem;padding:.6rem .85rem;border-bottom:1px solid var(--line-soft)}
.ref-row:last-child{border-bottom:0}
/* no overflow:hidden — a bought frame draws outside the circle and would be cut off */
.ref-av{flex:0 0 auto}
.ref-tx{flex:1 1 8rem;min-width:0;display:grid;gap:.1rem}
.ref-tx b{font-size:.8125rem}
.ref-tx a{text-decoration:none}
.ref-tx a:hover b{color:var(--amber)}
.ref-bar{flex:0 0 6rem;height:4px;background:var(--surface-2);border-radius:2px;overflow:hidden}
.ref-bar>span{display:block;height:100%;background:linear-gradient(90deg,var(--amber),var(--ember))}
.ref-status{flex:0 0 auto;font-family:var(--mono);font-size:.625rem;letter-spacing:.06em}
.tone-good{color:var(--live)}
.tone-bad{color:var(--ember)}
.tone-info{color:var(--muted)}
.tone-gray{color:var(--faint)}

.note-row{display:flex;align-items:flex-start;gap:.75rem;padding:.65rem .85rem;border-bottom:1px solid var(--line-soft)}
.note-row:last-child{border-bottom:0}
.note-tx{flex:1 1 auto;min-width:0;display:grid;gap:.15rem}
.note-tx b{font-size:.8125rem}
.note-body{color:var(--muted);font-size:.8125rem}
.note-link{flex:0 0 auto;text-decoration:none}
.note-link:hover{color:var(--amber)}
.note-unread{box-shadow:inset 2px 0 0 var(--amber)}
.note-danger .note-tx b{color:#FF9B86}
.note-success .note-tx b{color:var(--live)}
.note-warning .note-tx b{color:var(--warn)}

/* ---------- cabinet: level and achievements ---------- */
.me-link{display:flex;align-items:center;gap:.55rem;text-decoration:none}
.me-link:hover .me-name{color:var(--amber)}

/* The level bar is the ring around the avatar: a progress bar in a 54px header
   would be a two-pixel sliver nobody could read, while a ring reads as filled
   or not at a glance. conic-gradient rather than an SVG arc — one property,
   and --p is the only thing that changes. */
.me-av{
  position:relative;flex:0 0 auto;display:grid;place-items:center;
  width:34px;height:34px;border-radius:50%;
  background:conic-gradient(var(--amber) var(--p,0%),rgba(255,255,255,.10) 0);
}
/* Аватар теперь лежит внутри купленной оправы, а не сам по себе.
   Размер задаёт оправа через --px, картинке остаётся заполнить её. */
.me-av>.cos-av{--px:24px}
.me-av img{width:100%;height:100%;border-radius:50%;object-fit:cover;display:block}

/* Высокие эффекты имени в шапке прячем.
   
   Пламя под строкой — шесть десятков пикселей, а шапка вся пятьдесят четыре:
   обрезанный по пояс огонь выглядит поломкой, а не украшением. Цвет, обводка и
   начертание при этом работают — их и видно. */
.me-name .pixfx-canvas{display:none}
.me-lv{
  position:absolute;right:-3px;bottom:-3px;
  min-width:15px;height:15px;padding:0 3px;border-radius:8px;
  background:var(--surface);box-shadow:0 0 0 1px var(--line);
  font-family:var(--mono);font-size:.5625rem;line-height:15px;text-align:center;color:var(--amber);
}
.me-tx{display:grid;gap:.05rem;min-width:0}
.me-sub{display:flex;align-items:center;gap:.35rem;font-size:.6875rem;color:var(--muted)}
.me-bell{
  font-style:normal;font-family:var(--mono);font-size:.5625rem;
  min-width:14px;padding:0 4px;border-radius:999px;text-align:center;
  background:var(--ember);color:#fff;
}
@media(max-width:800px){.me-tx{display:none}}

.level-box{border-top:1px solid var(--line-soft);display:grid;gap:.6rem}
.level-line{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}
.level-badge{
  width:38px;height:38px;flex:0 0 auto;border-radius:8px;display:grid;place-items:center;
  background:linear-gradient(160deg,var(--amber),var(--ember));color:#1A0A04;
  font-weight:700;font-size:1.0625rem;
}
.level-title{display:grid;gap:.1rem;flex:1 1 auto;min-width:0}
.level-title b{font-size:.9375rem}
.level-next{flex:0 0 auto}

.ach{display:flex;align-items:center;gap:.8rem;padding:.7rem .85rem;border-bottom:1px solid var(--line-soft)}
.ach:last-child{border-bottom:0}
.ach-icon{
  width:34px;height:34px;flex:0 0 auto;border-radius:6px;display:grid;place-items:center;
  background:var(--surface-2);border:1px solid var(--line);
}
/* the icons come from the old site as dark monochrome SVGs, invisible on this
   background — force them to a white silhouette and use opacity for state */
.ach-icon img{width:20px;height:20px;display:block;filter:brightness(0) invert(1);opacity:.4}
.ach-done .ach-icon{background:linear-gradient(160deg,rgba(255,138,31,.28),rgba(232,69,42,.18));border-color:rgba(255,138,31,.5)}
.ach-done .ach-icon img{opacity:1}
.ach-icon img[data-started]{opacity:.75}
.ach-body{flex:1 1 auto;min-width:0;display:grid;gap:.2rem}
.ach-top{display:flex;align-items:baseline;gap:.6rem;flex-wrap:wrap}
.ach-top b{font-size:.875rem}
.ach-done .ach-top b{color:var(--amber)}
.ach-desc{color:var(--muted);font-size:.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ach-track{display:block;height:3px;background:var(--surface-2);border-radius:2px;overflow:hidden}
.ach-track>span{display:block;height:100%;background:linear-gradient(90deg,var(--amber),var(--ember))}
.ach-value{flex:0 0 auto;font-variant-numeric:tabular-nums;font-size:.8125rem;text-align:right}

/* achievement cards — same language as the inventory, with the tier reached
   colouring the card the way a medal would */
.achcard.t-0{--tier:var(--line)}
.achcard.t-1{--tier:#C77B3E}
.achcard.t-2{--tier:#AFBAC9}
.achcard.t-3{--tier:var(--amber)}

.achgrid{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fill,minmax(15rem,1fr))}
.achcard{
  display:grid;gap:.35rem;align-content:start;padding:.75rem;
  border:1px solid var(--line);border-left:2px solid var(--tier);border-radius:6px;
  background:var(--surface-2);
}
.achcard.is-done{
  background:linear-gradient(150deg,rgba(255,138,31,.10),var(--surface-2) 55%);
  border-color:color-mix(in srgb,var(--amber) 35%,var(--line));
}
.achcard-top{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
.achcard-icon{
  width:32px;height:32px;flex:0 0 auto;border-radius:6px;display:grid;place-items:center;
  background:var(--surface);border:1px solid var(--line);
}
.achcard-icon img{width:20px;height:20px;display:block;filter:brightness(0) invert(1);opacity:.45}
.achcard.t-1 .achcard-icon img,.achcard.t-2 .achcard-icon img{opacity:.8}
.achcard.is-done .achcard-icon{border-color:color-mix(in srgb,var(--amber) 55%,var(--line))}
.achcard.is-done .achcard-icon img{opacity:1}
.achcard-mark{color:var(--tier);font-size:1rem}

/* Точки ступеней. Обязательно внутри .pips: имя .pip уже занято зелёным
   индикатором онлайна в шапке, и безадресное правило здесь его перекрывало —
   индикатор пульсировал, но цветом var(--line), то есть серым. */
.pips{display:flex;gap:.2rem}
.pips .pip{width:.4rem;height:.4rem;border-radius:50%;background:var(--line);border:1px solid var(--line);animation:none}
.pips .pip.on{background:var(--tier);border-color:var(--tier)}

.achcard-name{font-size:.875rem;line-height:1.25}
.achcard.is-done .achcard-name{color:var(--amber)}
.achcard-desc{
  margin:0;color:var(--muted);font-size:.75rem;line-height:1.4;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.achcard-foot{display:grid;gap:.25rem;margin-top:.2rem}
.achcard-num{font-size:.75rem;font-variant-numeric:tabular-nums;color:var(--muted)}
.achcard-done{font-size:.75rem;color:var(--amber)}

/* ---------- player bases ---------- */
.basegrid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fill,minmax(17rem,1fr))}
.basecard{
  display:block;text-decoration:none;border:1px solid var(--line);border-radius:6px;
  background:var(--surface);overflow:hidden;transition:border-color .14s,transform .14s;
}
.basecard:hover{border-color:var(--muted);transform:translateY(-2px)}
.basecard-img{position:relative;display:block;aspect-ratio:16/9;background:var(--surface-2)}
.basecard-img img{width:100%;height:100%;object-fit:cover;display:block}
.basecard-score{
  position:absolute;right:.5rem;bottom:.5rem;
  background:rgba(12,14,19,.85);color:var(--live);
  font-size:.6875rem;padding:.15rem .45rem;border-radius:3px;
}
.basecard-tx{display:grid;gap:.2rem;padding:.7rem .85rem}
.basecard-tx b{font-size:.9375rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.gallery{display:grid;gap:1px;background:var(--line-soft)}
.gallery-main{width:100%;height:auto;max-height:32rem;object-fit:contain;background:#07090C;display:block}
.gallery-strip{display:flex;gap:1px;overflow-x:auto;background:var(--line-soft)}
.gallery-thumb{
  flex:0 0 auto;border:0;padding:0;cursor:pointer;background:var(--surface);
  width:96px;height:64px;opacity:.55;transition:opacity .14s;
}
.gallery-thumb.on,.gallery-thumb:hover{opacity:1}
.gallery-thumb img{width:100%;height:100%;object-fit:cover;display:block}

.vote-box{display:grid;gap:.75rem;justify-items:start}
.vote-score{display:flex;align-items:baseline;gap:.5rem}
.vote-score b{font-size:2rem;line-height:1;color:var(--live)}
.join.voted{background:var(--surface-2);color:var(--muted);box-shadow:inset 0 0 0 1px var(--line)}

.baseform{display:grid;gap:1.1rem}
.field{display:grid;gap:.35rem}
.field input[type=text],.field textarea{
  width:100%;background:var(--bg);color:var(--text);
  border:1px solid var(--line);border-radius:5px;padding:.6rem .7rem;
  font-family:var(--ui);font-size:.875rem;line-height:1.5;
}
.field textarea{resize:vertical}
.field input[type=text]:focus,.field textarea:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}
.field input[type=file]{font-family:var(--mono);font-size:.75rem;color:var(--muted)}
.field input[type=file]::file-selector-button{
  background:var(--surface-2);color:var(--text);border:1px solid var(--line);
  border-radius:4px;padding:.4rem .7rem;margin-right:.6rem;cursor:pointer;font-family:var(--ui);
}

/* ---------- promo strip on the home page ---------- */
/* Наверху главной — одна картинка, а не три плитки.

   Три баннера в ряд соревновались между собой, и ни один не был главным; на
   телефоне два из трёх вовсе прятались правилом ниже — половина работы
   редактора не доходила до половины читателей. Теперь по одному и по очереди.

   Правая половина оставлена пустой намеренно: место зарезервировано, а чем
   его занять — решается отдельно. Пустая ячейка сетки держит пропорции, чтобы
   картинка не растянулась во всю ширину. */
.promos{
  display:grid;gap:.75rem;grid-template-columns:1fr 1fr;
  margin-bottom:1rem;align-items:start;
}
@media(max-width:700px){
  .promos{grid-template-columns:1fr}
  /* пустое место на телефоне не занимает экран: там и так тесно */
  .promo-free{display:none}
}

.promo-box{position:relative;border-radius:6px;overflow:hidden}

/* Слайды лежат стопкой и меняются проявлением. Сдвиг «каруселью» на баннере
   такой ширины дёргает глаз сильнее, чем помогает понять, что их несколько:
   для этого есть точки. */
.promo-track{position:relative;aspect-ratio:21/9}
@media(max-width:700px){.promo-track{aspect-ratio:2/1}}

.promo{
  position:absolute;inset:0;display:block;overflow:hidden;text-decoration:none;
  border:1px solid var(--line);border-radius:6px;background:var(--surface-2);
  opacity:0;visibility:hidden;
  transition:opacity .5s ease,visibility .5s,border-color .14s;
}
.promo.is-on{opacity:1;visibility:visible}
a.promo:hover{border-color:var(--amber)}
.promo img{position:absolute;inset:0;width:100%;height:100%;display:block}

/* Два способа показать картинку, и выбирает между ними тот, кто заводит слайд.
   Обрезка верна для скриншота: важное у него в середине, а края — трава. Для
   афиши, нарисованной под свои поля, она же и есть порча. */
.promo-img.is-cover{object-fit:cover}
.promo-img.is-contain{object-fit:contain;z-index:1}

/* Подложка под картинкой, показанной целиком: она же сама, растянутая по рамке
   и размытая. Увеличение на пару процентов прячет края, которые размытие
   иначе оставляет прозрачными. */
.promo-back{
  object-fit:cover;transform:scale(1.06);filter:blur(22px) saturate(1.15) brightness(.62);
}

/* the text sits on a gradient so it stays readable over any screenshot */
.promo-tx{
  position:absolute;inset:auto 0 0 0;display:grid;gap:.15rem;
  padding:1.4rem .85rem .7rem;
  background:linear-gradient(to top,rgba(12,14,19,.94),rgba(12,14,19,.72) 55%,transparent);
}
.promo-tx b{
  color:var(--text);font-size:.875rem;line-height:1.3;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.promo-tx span{color:var(--muted);font-size:.75rem}

/* Точки: и указатель «сколько их всего», и переключатель. Лежат поверх
   градиента подписи, где картинка и так притемнена. */
.promo-dots{
  position:absolute;right:.7rem;bottom:.7rem;z-index:2;
  display:flex;gap:.3rem;
}
.promo-dot{
  width:.45rem;height:.45rem;padding:0;border-radius:50%;cursor:pointer;
  border:1px solid rgba(234,237,242,.5);background:rgba(12,14,19,.5);
  transition:background .2s,border-color .2s,transform .2s;
}
.promo-dot:hover{border-color:var(--amber)}
.promo-dot.is-on{background:var(--amber);border-color:var(--amber);transform:scale(1.15)}
.promo-dot:focus-visible{outline:2px solid var(--amber);outline-offset:2px}

/* Запасной вариант, если чемпионов ещё нет: ничего не рисуем. Пунктирная
   рамка или надпись «скоро» сказали бы посетителю о наших планах, а он пришёл
   не за этим. */
.promo-free{min-height:1px}

/* ---------- витрина лучших рядом с баннером ---------- */

/* Одна категория в кадре, крупно. Цвет каждой живёт на самом слое, поэтому
   подпись, цифра, полоска и точка меняются вместе с содержимым. */
.champ-box{position:relative;border-radius:6px;overflow:hidden;aspect-ratio:21/9}
@media(max-width:700px){.champ-box{aspect-ratio:2/1}}

.champ{
  position:absolute;inset:0;display:block;overflow:hidden;text-decoration:none;
  border:1px solid var(--line);border-radius:6px;background:var(--surface);
  opacity:0;visibility:hidden;
  transition:opacity .45s ease,visibility .45s,border-color .14s;
}
.champ.is-on{opacity:1;visibility:visible}
.champ-box:hover .champ.is-on{border-color:var(--top)}

/* полоска цветом категории по верху — видна даже боковым зрением */
.champ::before{
  content:"";position:absolute;top:0;left:0;right:0;height:2px;z-index:3;
  background:linear-gradient(90deg,var(--top),transparent 75%);
}

/* Двойной класс здесь не для красоты: cosmetics.css подключается после
   site.css, и базовое `.cos-cover{position:relative;height:5.5rem}` побеждало
   при равной силе — купленная обложка занимала верхнюю полосу в 88 пикселей
   вместо всей карточки. */
.champ .champ-cover{position:absolute;inset:0;height:auto;border-radius:0}
.champ-cover::after{
  content:"";position:absolute;inset:0;
  background:
    linear-gradient(105deg,rgba(12,14,19,.96) 42%,rgba(12,14,19,.6) 70%,rgba(12,14,19,.35)),
    radial-gradient(90% 120% at 100% 50%,color-mix(in srgb,var(--top) 20%,transparent),transparent 60%);
}
/* без своей обложки карточка не должна выглядеть пустой */
.champ .cos-cover-none{
  background:
    radial-gradient(120% 130% at 85% 20%,color-mix(in srgb,var(--top) 26%,transparent),transparent 62%),
    linear-gradient(160deg,var(--surface-2),var(--bg));
}

/* Главное — слева и крупно: категория, цифра, за что. */
.champ-in{
  position:absolute;inset:0 auto 0 0;z-index:2;
  display:flex;flex-direction:column;justify-content:center;gap:.15rem;
  padding:0 1rem;max-width:66%;
}
.champ-cat{
  display:inline-flex;align-items:center;gap:.35rem;
  font-size:.6875rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--top);
}
.champ-cat svg{flex:0 0 auto}

/* Цифра — то, ради чего всё. Моноширинная и с выключкой по разрядам, чтобы при
   смене категории она не прыгала по ширине символов. */
.champ-num{
  font-family:var(--mono);font-weight:600;
  font-size:clamp(1.9rem,4.4vw,3.1rem);line-height:1;
  color:var(--text);font-variant-numeric:tabular-nums;
  text-shadow:0 0 26px color-mix(in srgb,var(--top) 45%,transparent);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.champ-note{font-size:.6875rem;color:var(--muted);max-width:30ch}

/* Человек — справа внизу, у своего края: он подпись к цифре, а не наоборот. */
.champ-body{
  position:absolute;inset:auto .9rem .85rem auto;z-index:2;
  display:flex;align-items:center;gap:.65rem;
}
.champ-id{display:grid;gap:.05rem;min-width:0;text-align:right}
.champ-name{
  display:flex;align-items:center;justify-content:flex-end;gap:.3rem;min-width:0;
  font-size:.9375rem;line-height:1.2;
}
/* Обрезаем только простой ник. У наряженного за буквами рисуется пламя или
   искры холстом выше и шире текста, и overflow:hidden срезал бы их по коробке
   букв — то есть спрятал бы ровно то, за что человек заплатил. Наряженный
   отличается тем, что к `cos-name` добавлен `cos-name-<стиль>`. */
.champ-name > .cos-name:not([class*="cos-name-"]){
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
/* Наряженному ограничиваем не текст, а весь блок: разрастись за половину
   карточки и налезть на цифру он всё равно не должен. */
.champ-body{max-width:46%}
.champ-role{
  font-family:var(--mono);font-size:.5625rem;letter-spacing:.12em;
  text-transform:uppercase;color:var(--faint);
}

/* Появление по очереди: категория, цифра, подпись, человек. Глаз успевает
   заметить, что именно поменялось, вместо того чтобы всё мигнуло разом. */
@keyframes champUp{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:none}}
.champ.is-on .champ-cat  {animation:champUp .42s .04s both ease-out}
.champ.is-on .champ-num  {animation:champUp .42s .12s both ease-out}
.champ.is-on .champ-note {animation:champUp .42s .2s  both ease-out}
.champ.is-on .champ-body {animation:champUp .42s .28s both ease-out}

/* ---------- своё появление у каждой категории ----------

   Движение подобрано по смыслу, а не ради движения: рейдер взрывается, строитель
   выкладывается снизу вверх, добытчик отбивает породу. Одинаковая анимация на
   девяти карточках была бы просто девятью одинаковыми карточками.

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

/* Время: стрелка знака доходит до места, цифра потом мерно дышит — как часы,
   которые идут дальше, пока на них смотрят. */
@keyframes cHand{from{transform:rotate(-150deg)}to{transform:rotate(0)}}
@keyframes cBreath{0%,100%{opacity:1}50%{opacity:.78}}
.champ.c-time.is-on .champ-cat svg{animation:cHand 1s .05s both cubic-bezier(.2,.8,.2,1)}
.champ.c-time.is-on .champ-num{animation:champUp .42s .12s both ease-out,cBreath 3.2s 1s ease-in-out infinite}

/* Убийца NPC: цифра приходит сверху и жёстко садится — попадание, а не полёт. */
@keyframes cHit{
  0%{opacity:0;transform:translateY(-16px) scale(1.12)}
  62%{opacity:1;transform:translateY(3px) scale(.97)}
  100%{opacity:1;transform:none}
}
@keyframes cSnap{0%{transform:scale(1.6);opacity:0}60%{transform:scale(.92);opacity:1}100%{transform:none}}
.champ.c-npc.is-on .champ-num{animation:cHit .5s .1s both cubic-bezier(.3,1.4,.5,1)}
.champ.c-npc.is-on .champ-cat svg{animation:cSnap .42s .04s both ease-out}

/* Охотник: цифра выходит слева двумя шагами — как след, а не одним рывком. */
@keyframes cTrack{
  0%{opacity:0;transform:translateX(-22px)}
  45%{opacity:.75;transform:translateX(-7px)}
  100%{opacity:1;transform:none}
}
.champ.c-hunter.is-on .champ-num{animation:cTrack .62s .1s both steps(2,end)}
.champ.c-hunter.is-on .champ-cat svg{animation:cTrack .5s .04s both ease-out}

/* Добытчик: удар киркой — цифра коротко отдаёт вбок и оседает, по ней проходит
   золотой отблеск. */
@keyframes cStrike{
  0%{opacity:0;transform:translateY(-10px)}
  50%{opacity:1;transform:translateY(0)}
  62%{transform:translateX(-3px)}
  74%{transform:translateX(2px)}
  86%{transform:translateX(-1px)}
  100%{transform:none}
}
@keyframes cShine{
  0%,100%{text-shadow:0 0 26px color-mix(in srgb,var(--top) 45%,transparent)}
  40%{text-shadow:0 0 10px var(--top),0 0 40px color-mix(in srgb,var(--top) 70%,transparent)}
}
.champ.c-gather.is-on .champ-num{animation:cStrike .7s .1s both ease-out,cShine 2.4s 1s ease-in-out infinite}
.champ.c-gather.is-on .champ-cat svg{animation:cSnap .4s .04s both ease-out}

/* Строитель: цифра выкладывается снизу вверх, как кладка. */
@keyframes cBuild{
  from{opacity:0;clip-path:inset(100% 0 0 0);transform:translateY(6px)}
  to{opacity:1;clip-path:inset(0 0 0 0);transform:none}
}
/* кирпичи знака встают снизу вверх — тем же движением, что и цифра */
@keyframes cStack{
  0%{opacity:0;transform:translateY(7px)}
  55%{opacity:1;transform:translateY(-2px)}
  100%{transform:none}
}
.champ.c-builder.is-on .champ-num{animation:cBuild .62s .1s both cubic-bezier(.2,.7,.3,1)}
.champ.c-builder.is-on .champ-cat svg{animation:cStack .5s .04s both ease-out}

/* Рейдер: взрыв — цифра разлетается наружу из точки и гаснет вспышкой. */
@keyframes cBlast{
  0%{opacity:0;transform:scale(.55);text-shadow:0 0 0 var(--top)}
  40%{opacity:1;transform:scale(1.08);text-shadow:0 0 34px var(--top),0 0 70px color-mix(in srgb,var(--top) 60%,transparent)}
  100%{opacity:1;transform:none;text-shadow:0 0 26px color-mix(in srgb,var(--top) 45%,transparent)}
}
@keyframes cFlash{0%{opacity:0;transform:scale(2)}45%{opacity:1;transform:scale(.9)}100%{transform:none}}
.champ.c-raider.is-on .champ-num{animation:cBlast .6s .08s both cubic-bezier(.2,1.2,.4,1)}
.champ.c-raider.is-on .champ-cat svg{animation:cFlash .45s both ease-out}

/* Крафтер: удар по наковальне — цифра сминается по высоте и распрямляется. */
@keyframes cForge{
  0%{opacity:0;transform:scaleY(.6) translateY(-8px)}
  55%{opacity:1;transform:scaleY(1.06)}
  78%{transform:scaleY(.97)}
  100%{transform:none}
}
.champ.c-crafter.is-on .champ-num{animation:cForge .58s .1s both ease-out;transform-origin:50% 100%}
.champ.c-crafter.is-on .champ-cat svg{animation:cSnap .4s .04s both ease-out}

/* Ивентер: флаг разворачивается — лёгкий наклон, который выпрямляется. */
@keyframes cWave{
  0%{opacity:0;transform:skewX(-12deg) translateX(-12px)}
  60%{opacity:1;transform:skewX(3deg) translateX(0)}
  100%{transform:none}
}
@keyframes cFlutter{0%,100%{transform:skewX(0)}50%{transform:skewX(-6deg)}}
.champ.c-events.is-on .champ-num{animation:cWave .6s .1s both ease-out}
.champ.c-events.is-on .champ-cat svg{animation:cWave .5s .04s both ease-out,cFlutter 2.8s 1s ease-in-out infinite}

/* Уровень: цифра поднимается, и вокруг неё расцветает ореол — то самое чувство
   «уровень взят», ради которого уровни и придуманы. */
@keyframes cLevel{
  0%{opacity:0;transform:translateY(14px);text-shadow:0 0 0 var(--top)}
  55%{opacity:1;transform:translateY(-3px);text-shadow:0 0 40px var(--top)}
  100%{opacity:1;transform:none;text-shadow:0 0 26px color-mix(in srgb,var(--top) 45%,transparent)}
}
@keyframes cTwinkle{0%,100%{transform:rotate(0) scale(1)}50%{transform:rotate(18deg) scale(1.12)}}
.champ.c-level.is-on .champ-num{animation:cLevel .7s .1s both cubic-bezier(.2,.9,.3,1)}
.champ.c-level.is-on .champ-cat svg{animation:cSnap .4s .04s both ease-out,cTwinkle 3s 1s ease-in-out infinite}

.champ-dots{position:absolute;right:.7rem;top:.7rem;z-index:3;display:flex;gap:.28rem}
.champ-dot{
  width:.4rem;height:.4rem;padding:0;border-radius:50%;cursor:pointer;
  border:1px solid rgba(234,237,242,.45);background:rgba(12,14,19,.5);
  transition:background .2s,border-color .2s,transform .2s;
}
.champ-dot:hover{border-color:var(--top)}
.champ-dot.is-on{background:var(--top);border-color:var(--top);transform:scale(1.3)}
.champ-dot:focus-visible{outline:2px solid var(--top);outline-offset:2px}

@media(max-width:700px){
  .champ-in{max-width:58%;padding:0 .8rem}
  .champ-body{inset:auto .7rem .6rem auto;gap:.5rem}
  .champ-role{display:none}
  /* Размер аватара приходит из разметки как inline-стиль, и обычным правилом
     его не перебить — отсюда важность. Сто четыре пикселя на карточке высотой
     174 съели бы её целиком; шестьдесят держат ту же долю, что и на большом
     экране. */
  .champ-body .cos-av{--px:60px !important}
}

@media(prefers-reduced-motion:reduce){
  .champ{transition:opacity .01s}
  .champ-dot{transition:none}
  /* Гасим всё разом, включая своё у каждой категории: человек попросил
     не двигать — значит не двигаем ничего. */
  .champ.is-on .champ-cat,.champ.is-on .champ-num,
  .champ.is-on .champ-note,.champ.is-on .champ-body,
  .champ.is-on .champ-cat svg{animation:none !important}
}
}

@media(prefers-reduced-motion:reduce){
  .promo{transition:opacity .01s}
  .promo-dot{transition:none}
}

/* a deliberately granted site role, next to the player's name */
/* ---------- метка «кто это» ----------

   Один вид на все случаи: цвет задаётся переменной --role, а вид метки —
   классом. Разный цвет у разных ролей нужен не для красоты: единственный
   модератор в списке из полусотни игроков должен цепляться взглядом, а не
   отыскиваться чтением. */

.rolebadge{
  display:inline-block;vertical-align:middle;margin-left:.4rem;
  padding:.1rem .45rem;border-radius:999px;
  font-family:var(--ui);font-size:.625rem;font-weight:600;line-height:1.5;
  text-transform:none;letter-spacing:.01em;white-space:nowrap;
  --role:var(--muted);
  color:var(--role);
  border:1px solid color-mix(in srgb,var(--role) 45%,transparent);
  background:color-mix(in srgb,var(--role) 12%,transparent);
}

/* Персонал — цветом сайта: он и означает «этот человек отсюда». */
.rolebadge-staff{--role:var(--amber)}

.rolebadge-vip{--role:#ffb020}

/* Заблокированный — единственная метка, которую читают как предупреждение,
   поэтому она заметно плотнее остальных. */
.rolebadge-banned{
  --role:var(--ember);
  background:color-mix(in srgb,var(--ember) 22%,transparent);
}

/* Обычный игрок — тише всех: метка есть, но взгляд на ней не останавливается. */
.rolebadge-player{
  --role:var(--faint);
  border-color:transparent;
  background:color-mix(in srgb,var(--faint) 10%,transparent);
}

/* ---------- voting ---------- */
.voteprize{margin-bottom:1rem;border-left:2px solid var(--amber)}
.voteprize .card-b{display:grid;gap:.1rem;justify-items:start}
.voteprize b{font-size:1.25rem;color:var(--amber);line-height:1.2}
.voterow{
  display:flex;align-items:center;justify-content:space-between;gap:.75rem;
  padding:.5rem .85rem;border-bottom:1px solid var(--line-soft);
}
.voterow:last-child{border-bottom:0}
.voterow-n{font-size:.8125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ---------- error pages ---------- */
.errpage{display:grid;gap:.5rem;justify-items:center;text-align:center;padding:4rem 1rem 5rem}
.err-code{
  font-size:4rem;line-height:1;color:var(--line);
  /* loud enough to orient, quiet enough not to be the message */
  letter-spacing:.05em;
}
.errpage h1{font-size:1.375rem;text-transform:none}
.errpage p{margin:0;color:var(--muted);font-size:.9375rem;max-width:46ch}
.err-links{display:flex;flex-wrap:wrap;gap:.75rem;align-items:center;justify-content:center;margin-top:1rem}
.err-links a:not(.join){color:var(--muted);font-size:.8125rem}
.err-links a:not(.join):hover{color:var(--amber)}

/* ---------- server map ---------- */
.mapfacts{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(9rem,1fr));margin-bottom:1rem}
.mapfact{
  display:grid;gap:.1rem;padding:.7rem .85rem;
  border:1px solid var(--line);border-radius:6px;background:var(--surface);
}
.mapfact b{font-size:1.0625rem;line-height:1.2}
.mapfact .mono{color:var(--amber)}
/* the embed is a square map; letting it drive its own height keeps it whole */
.mapframe{position:relative;aspect-ratio:1;background:var(--bg);border-block:1px solid var(--line)}
.mapframe iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
@media(min-width:900px){.mapframe{aspect-ratio:16/11}}

/* ---------- wiki ---------- */
/* Documentation layout: the whole book stays in the sidebar, the article gets
   a comfortable measure. Twenty-seven articles fit without folding anything. */
.wiki{display:grid;gap:1.25rem;grid-template-columns:15.5rem minmax(0,1fr);align-items:start}
@media(max-width:899px){.wiki{grid-template-columns:1fr}}

.wnav{
  position:sticky;top:4.5rem;max-height:calc(100vh - 6.5rem);overflow-y:auto;
  border:1px solid var(--line);border-radius:6px;background:var(--surface);
  padding:.5rem;scrollbar-width:thin;
}
@media(max-width:899px){.wnav{position:static;max-height:22rem}}
.wnav-search{padding:.15rem .15rem .45rem}
.wnav-search input{
  width:100%;background:var(--bg);color:var(--text);
  border:1px solid var(--line);border-radius:5px;padding:.45rem .6rem;
  font-family:var(--ui);font-size:.8125rem;
}
.wnav-search input:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}

.wnav-home{
  display:block;padding:.4rem .5rem;border-radius:5px;text-decoration:none;
  color:var(--muted);font-size:.8125rem;
}
.wnav-home:hover{background:var(--surface-2);color:var(--text)}
.wnav-home.on{background:var(--surface-2);color:var(--amber)}

.wnav-cat{margin-top:.55rem}
.wnav-cat[hidden]{display:none}
.wnav-cat-h{display:flex;align-items:center;gap:.4rem;padding:.2rem .5rem .3rem;color:var(--faint)}
.wnav-cat-h b{flex:1 1 auto;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em}
.wnav-cat-h i{font-style:normal;font-family:var(--mono);font-size:.5625rem}
.wicon{width:14px;height:14px;flex:0 0 auto}

.wnav-a{
  display:block;padding:.32rem .5rem .32rem .95rem;border-radius:5px;
  text-decoration:none;color:var(--muted);font-size:.8125rem;line-height:1.35;
  border-left:2px solid transparent;
}
.wnav-a[hidden]{display:none}
.wnav-a:hover{background:var(--surface-2);color:var(--text)}
.wnav-a.on{color:var(--amber);border-left-color:var(--amber);background:var(--surface-2)}
.wnav-none{padding:.5rem}
.wnav-none[hidden]{display:none}

.wiki-main{min-width:0}
.wiki-head{margin-bottom:1.25rem}
.wiki-head h1{font-size:1.5rem}
.wiki-head p{margin:.35rem 0 0;color:var(--muted);font-size:.875rem;max-width:60ch}
.wiki-q{display:flex;gap:.5rem;margin-top:.85rem}
.wiki-q input{
  flex:1 1 auto;min-width:0;background:var(--surface);color:var(--text);
  border:1px solid var(--line);border-radius:5px;padding:.55rem .7rem;
  font-family:var(--ui);font-size:.875rem;
}
.wiki-q input:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}

.wcat{margin-bottom:1.5rem}
.wcat-h{display:flex;align-items:flex-start;gap:.6rem;margin-bottom:.7rem}
.wcat-h .wicon{width:18px;height:18px;margin-top:.15rem;color:var(--amber)}
.wcat-h h2{font-size:1rem;text-transform:none}
.wcat-h p{margin:.15rem 0 0;color:var(--muted);font-size:.8125rem;max-width:62ch}
.wcat-list{display:grid;gap:.5rem;grid-template-columns:repeat(auto-fill,minmax(15rem,1fr))}
.wcard{
  display:grid;gap:.2rem;align-content:start;padding:.7rem .8rem;text-decoration:none;
  border:1px solid var(--line);border-left:2px solid var(--line);border-radius:6px;
  background:var(--surface);transition:border-color .14s,transform .14s;
}
.wcard:hover{border-color:var(--line);border-left-color:var(--amber);transform:translateY(-1px)}
.wcard b{font-size:.8125rem;color:var(--text);line-height:1.3}
.wcard:hover b{color:var(--amber)}
.wcard span{color:var(--muted);font-size:.75rem;line-height:1.45}

.wikirow{
  display:grid;gap:.15rem;padding:.6rem .85rem;text-decoration:none;
  border-bottom:1px solid var(--line-soft);transition:background .12s;
}
.wikirow:last-child{border-bottom:0}
.wikirow:hover{background:var(--surface-2)}
.wikirow b{font-size:.8125rem;color:var(--text)}
.wikirow:hover b{color:var(--amber)}
.wikirow span{color:var(--muted);font-size:.75rem;line-height:1.4}

/* --- article --- */
.wart-h{padding-bottom:1rem;border-bottom:1px solid var(--line-soft);margin-bottom:1.1rem}
.wart-cat{display:inline-flex;align-items:center;gap:.35rem;color:var(--amber);font-size:.6875rem;text-transform:uppercase;letter-spacing:.05em}
.wart-h h1{font-size:1.5rem;text-transform:none;margin-top:.4rem;line-height:1.25}
.wart-lead{margin:.55rem 0 0;color:#C7CEDA;font-size:1rem;line-height:1.6;max-width:66ch}
.wart-h .meta{margin-top:.7rem}

.wart-toc{
  /* shares the body's measure: a contents box wider than the text it indexes
     reads as a banner rather than as part of the article */
  max-width:70ch;
  margin-bottom:1.2rem;padding:.7rem .85rem;border-radius:6px;
  background:var(--surface);border:1px solid var(--line);border-left:2px solid var(--amber);
}
.wart-toc ol{margin:.4rem 0 0;padding-left:1.1rem;display:grid;gap:.25rem}
.wart-toc li{color:var(--muted);font-size:.8125rem}
.wart-toc a{color:var(--muted);text-decoration:none}
.wart-toc a:hover{color:var(--text)}
.wart-toc a.on{color:var(--amber)}

/* the measure is the point: long prose needs a line you can track back from */
.wart-body{max-width:70ch}
.wart-sec{margin-bottom:1.6rem;scroll-margin-top:5rem}
.wart-sec h2{
  display:flex;align-items:baseline;gap:.4rem;
  font-size:1.0625rem;text-transform:none;margin-bottom:.55rem;
}
.wart-anchor{color:var(--line);text-decoration:none;font-size:.875rem;opacity:0;transition:opacity .12s}
.wart-sec h2:hover .wart-anchor{opacity:1}
.wart-anchor:hover{color:var(--amber)}
.wart-sec p{margin:0 0 .75rem;color:#C7CEDA;font-size:.9375rem;line-height:1.7}
.wart-sec p:last-child{margin-bottom:0}
.wart-sec ul{margin:.2rem 0 0;padding-left:1.15rem;display:grid;gap:.4rem}
.wart-sec li{color:var(--muted);font-size:.9375rem;line-height:1.6}

.wart-cmds{margin:.2rem 0 0;display:grid;gap:.35rem}
.wart-cmds > div{display:grid;gap:.1rem;padding:.45rem .6rem;border-radius:5px;background:var(--surface-2);border:1px solid var(--line)}
.wart-cmds dt code{font-family:var(--mono);font-size:.8125rem;color:var(--amber)}
.wart-cmds dd{margin:0;color:var(--muted);font-size:.8125rem;line-height:1.5}

/* a note is an aside, not another paragraph — it has to look interruptive */
.wart-note{
  margin:.6rem 0 0 !important;padding:.55rem .75rem;border-radius:5px;
  border-left:2px solid var(--amber);background:rgba(255,138,31,.07);
  color:#C7CEDA;font-size:.875rem;line-height:1.6;
}
.wart-links{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:.7rem}
.wart-links a{
  display:inline-block;padding:.25rem .6rem;border-radius:999px;text-decoration:none;
  border:1px solid var(--line);background:var(--surface-2);
  color:var(--muted);font-size:.75rem;
}
.wart-links a:hover{border-color:var(--amber);color:var(--amber)}

.wart-f{margin-top:2rem;padding-top:1.2rem;border-top:1px solid var(--line-soft);display:grid;gap:1.4rem}
.wart-updown{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(13rem,1fr))}
.wart-nav{
  display:grid;gap:.15rem;padding:.7rem .85rem;text-decoration:none;
  border:1px solid var(--line);border-radius:6px;background:var(--surface);
}
.wart-nav:hover{border-color:var(--amber)}
.wart-nav b{font-size:.8125rem;color:var(--text);line-height:1.3}
.wart-nav:hover b{color:var(--amber)}
.wart-nav.next{text-align:right}
.wart-rel{display:grid;gap:.5rem}
.wart-ask{display:grid;gap:.5rem;justify-items:start}
.wart-ask p{margin:0}

/* ---------- notification switches ---------- */
.prefs{border-top:1px solid var(--line-soft);display:grid;gap:.6rem;justify-items:start}
.prefs-grid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));width:100%}
.prefs-group{display:grid;gap:.3rem;align-content:start}
.pref{display:flex;align-items:center;gap:.45rem;cursor:pointer;font-size:.8125rem;color:var(--muted)}
.pref:hover{color:var(--text)}
.pref input{accent-color:var(--amber);width:.95rem;height:.95rem;flex:0 0 auto}

/* ---------- support tickets ---------- */
.tkt{border-bottom:1px solid var(--line-soft)}
.tkt:last-child{border-bottom:0}
.tkt-h{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin-bottom:.6rem}
.tkt-h b{font-size:.875rem}
.tkt-flow{display:grid;gap:.5rem}
.tkt-msg{
  padding:.5rem .7rem;border-radius:6px;max-width:85%;
  background:var(--surface-2);border:1px solid var(--line);
}
/* the администрация's replies sit on the other side, as in any chat */
.tkt-msg.from-admin{
  margin-left:auto;
  background:rgba(255,138,31,.08);
  border-color:color-mix(in srgb,var(--amber) 35%,var(--line));
}
.tkt-who{display:flex;gap:.4rem;align-items:baseline;font-size:.6875rem;color:var(--faint);margin-bottom:.15rem}
.tkt-who time{font-family:var(--mono);font-size:.5625rem}
.tkt-msg p{margin:0;color:#C7CEDA;font-size:.8125rem;line-height:1.5;white-space:pre-wrap;overflow-wrap:anywhere}
.tkt-form{display:flex;gap:.5rem;align-items:flex-end;margin-top:.7rem}
.tkt-form textarea{
  flex:1 1 auto;min-width:0;resize:vertical;
  background:var(--bg);color:var(--text);border:1px solid var(--line);border-radius:5px;
  padding:.5rem .6rem;font-family:var(--ui);font-size:.8125rem;line-height:1.45;
}
.tkt-form textarea:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}

/* ---------- kits ---------- */
/* The plugin gives each kit a colour; it drives the card's accent so the page
   reads the same way it does in game. */
.kit{--kit:var(--amber)}
.kitgrid{display:grid;gap:.75rem;grid-template-columns:repeat(auto-fill,minmax(16rem,1fr))}
.kit{
  display:grid;gap:.5rem;align-content:start;padding:.8rem;
  border:1px solid var(--line);border-top:2px solid var(--kit);border-radius:6px;
  background:var(--surface-2);
}
.kit-h{display:flex;align-items:center;gap:.6rem}
.kit-img{width:40px;height:40px;flex:0 0 auto;object-fit:contain;border-radius:5px;background:var(--bg)}
.kit-name{min-width:0;display:grid;gap:.1rem}
.kit-name b{font-size:.9375rem;color:var(--kit)}
.kit-name .lbl{font-family:var(--mono);font-size:.5625rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kit-desc{margin:0;color:var(--muted);font-size:.75rem;line-height:1.45}
.kit-items{display:flex;flex-wrap:wrap;gap:.25rem}
.kit-item{
  position:relative;width:34px;height:34px;display:grid;place-items:center;
  border:1px solid var(--line);border-radius:4px;background:var(--bg);
}
.kit-item img{max-width:26px;max-height:26px;object-fit:contain;display:block}
.kit-item i{
  position:absolute;right:1px;bottom:0;font-style:normal;
  font-family:var(--mono);font-size:.5625rem;color:var(--text);
  text-shadow:0 0 3px #000,0 0 3px #000;
}
.kit-more{
  display:grid;place-items:center;min-width:34px;height:34px;padding:0 .3rem;
  border:1px dashed var(--line);border-radius:4px;
  font-family:var(--mono);font-size:.6875rem;color:var(--faint);
}
.kit-f{display:flex;flex-wrap:wrap;gap:.3rem}

/* ---------- winners of the month ---------- */
.podium-card{margin-bottom:1rem}
.podium{display:grid;gap:.85rem;padding:1rem;grid-template-columns:repeat(auto-fit,minmax(14rem,1fr))}
.podium-item{
  display:grid;gap:.55rem;text-decoration:none;
  border:1px solid var(--line);border-radius:6px;overflow:hidden;
  background:var(--surface-2);transition:border-color .14s,transform .14s;
}
.podium-item:hover{transform:translateY(-2px)}
.podium-item.place-1{border-color:var(--amber)}
.podium-item.place-2{border-color:var(--line)}
.podium-item.place-3{border-color:var(--line)}
.podium-img{position:relative;display:block;aspect-ratio:16/9;background:var(--bg)}
.podium-img img{width:100%;height:100%;object-fit:cover;display:block}
.podium-rank{
  position:absolute;left:.5rem;top:.5rem;display:grid;place-items:center;
  width:1.6rem;height:1.6rem;border-radius:50%;
  background:rgba(12,14,19,.88);color:var(--muted);
  font-family:var(--mono);font-size:.8125rem;
}
.place-1 .podium-rank{color:var(--bg);background:var(--amber)}
.podium-tx{display:grid;gap:.15rem;padding:0 .8rem .8rem}
.podium-tx b{font-size:.875rem;color:var(--text);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.podium-likes{font-size:.75rem;color:var(--live)}

/* ---------- co-authors on a base ---------- */
.coauthors{margin-top:.9rem;padding-top:.8rem;border-top:1px solid var(--line-soft);display:grid;gap:.45rem}
.coauthor-list{display:flex;flex-wrap:wrap;gap:.4rem}
.coauthor{
  display:inline-flex;align-items:center;gap:.4rem;text-decoration:none;
  background:var(--surface-2);border:1px solid var(--line);border-radius:999px;
  padding:.2rem .6rem .2rem .2rem;font-size:.75rem;color:var(--text);
}
.coauthor:hover{border-color:var(--muted)}

.mate-row{display:flex;align-items:center;gap:.6rem;padding:.5rem 0;border-bottom:1px solid var(--line-soft)}
.mate-row:last-of-type{border-bottom:0}
.mate-av{flex:0 0 auto}
.mate-tx{flex:1 1 auto;min-width:0;display:grid;gap:.05rem}
.mate-tx b{font-size:.8125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.mate-x{
  flex:0 0 auto;border:1px solid var(--line);background:var(--surface-2);color:var(--muted);
  border-radius:4px;width:26px;height:26px;line-height:1;font-size:1rem;cursor:pointer;
}
.mate-x:hover{border-color:var(--ember);color:var(--ember)}
.mate-ok{
  border:1px solid var(--line);background:var(--surface-2);color:var(--text);
  border-radius:4px;padding:.3rem .7rem;font-family:var(--ui);font-size:.75rem;cursor:pointer;
}
.mate-ok:hover{border-color:var(--live);color:var(--live)}
.mate-form{display:grid;gap:.5rem;justify-items:start;margin-top:.9rem}
.mate-form input{
  width:100%;background:var(--bg);color:var(--text);border:1px solid var(--line);
  border-radius:5px;padding:.5rem .6rem;font-family:var(--mono);font-size:.8125rem;
}
.mate-form input:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}
.mine-acts{flex:0 0 auto;display:flex;align-items:center;gap:.35rem}

/* ---------- comments under a base ---------- */
.cmt{display:flex;gap:.7rem;padding:.85rem 0;border-bottom:1px solid var(--line-soft)}
.cmt:first-child{padding-top:0}
.cmt-av{flex:0 0 auto}
.cmt-body{min-width:0;flex:1}
.cmt-top{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap;margin-bottom:.2rem}
.cmt-who{color:var(--text);font-size:.8125rem;font-weight:600;text-decoration:none}
.cmt-who:hover{color:var(--amber)}
.cmt-tx{margin:0;color:#C7CEDA;font-size:.875rem;line-height:1.6;overflow-wrap:anywhere}

.cmt-form{display:grid;gap:.6rem;justify-items:start;margin-top:1rem}
.cmt-form textarea{
  width:100%;background:var(--bg);color:var(--text);
  border:1px solid var(--line);border-radius:5px;padding:.6rem .7rem;
  font-family:var(--ui);font-size:.875rem;line-height:1.5;resize:vertical;
}
.cmt-form textarea:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}
.cmt-err{margin:0;color:var(--ember);font-size:.8125rem}

/* ---------- activity chart ---------- */
.chart{margin:0;position:relative;min-width:0}
.chart svg{display:block;width:100%;height:auto;overflow:visible}
.chart .axis{font-family:var(--mono);font-size:9px;fill:var(--faint);letter-spacing:.08em}
.chart .peaklab-svg{font-family:var(--mono);font-size:9px;fill:var(--muted);letter-spacing:.06em}
.chart .grid{stroke:var(--line-soft);stroke-width:1}
.chart .cross{stroke:var(--muted);stroke-width:1;stroke-dasharray:2 3;opacity:0}
.chart.live .cross{opacity:1}
.chart .cursor{opacity:0}
.chart.live .cursor{opacity:1}
/* Подсказка графика на «Рейтинге», и только она.
   Раньше правило звалось `.tip` — и цепляло всё с этим классом, включая
   карточки внутри статей: они получали absolute, nowrap, сдвиг на пол-ширины и
   pointer-events:none, то есть уезжали за край экрана и переставали нажиматься.
   Элемент здесь ровно один, у него есть id, и скрипт графика ищет его по нему —
   привязка к id закрывает столкновение имён насовсем. */
#tip{
  position:absolute;pointer-events:none;z-index:5;
  background:var(--bg);border:1px solid var(--line);border-radius:5px;
  padding:.3rem .5rem;white-space:nowrap;
  font-family:var(--mono);font-size:.6875rem;color:var(--text);
  transform:translate(-50%,-135%);
  box-shadow:0 6px 16px -6px rgba(0,0,0,.7);
}
#tip[hidden]{display:none}
#tip b{color:var(--live);font-weight:700}
#tip span{color:var(--faint)}

details.data{border-top:1px solid var(--line-soft)}
details.data summary{cursor:pointer;padding:.45rem .85rem;font-family:var(--mono);font-size:.625rem;letter-spacing:.12em;text-transform:uppercase;color:var(--faint)}
details.data summary:hover{color:var(--muted)}
details.data table{width:100%;border-collapse:collapse;font-family:var(--mono);font-size:.6875rem}
details.data th,details.data td{padding:.25rem .85rem;text-align:left;border-top:1px solid var(--line-soft);color:var(--muted)}
details.data td:last-child{text-align:right;font-variant-numeric:tabular-nums;color:var(--text)}

/* ---------- radio / channels / progress ---------- */
.air{display:flex;align-items:center;gap:.7rem}
.air .btn{width:34px;height:34px;flex:0 0 auto;border:0;border-radius:50%;cursor:pointer;background:linear-gradient(160deg,var(--amber),var(--ember));color:#1A0A04;display:grid;place-items:center}
.air .tx{min-width:0}
.air .tx b{display:block;font-size:.8125rem;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bars{display:flex;align-items:flex-end;gap:2px;height:16px;margin-left:auto;flex:0 0 auto}
.bars i{width:3px;background:var(--amber);animation:bars 1.1s ease-in-out infinite}
.bars i:nth-child(2){animation-delay:.15s;background:var(--ember)}
.bars i:nth-child(3){animation-delay:.3s}
.bars i:nth-child(4){animation-delay:.45s;background:var(--ember)}
@keyframes bars{0%,100%{height:3px}50%{height:16px}}

.air{text-decoration:none}
.pip-off{background:var(--faint);animation:none}

/* ---------- persistent radio bar ---------- */
.radiobar{
  position:fixed;left:0;right:0;bottom:0;z-index:40;
  border-top:1px solid var(--line);
  background:rgba(12,14,19,.94);
  backdrop-filter:blur(14px);
}
.radiobar-in{
  max-width:var(--maxw);margin-inline:auto;
  padding:.5rem var(--gut);
  display:flex;align-items:center;gap:.85rem;
}
.radiobar-btn{
  position:relative;
  width:34px;height:34px;flex:0 0 auto;border:0;border-radius:50%;cursor:pointer;
  background:linear-gradient(160deg,var(--amber),var(--ember));color:#1A0A04;
  display:grid;place-items:center;transition:transform .14s,box-shadow .14s;
}
.radiobar-btn:hover{transform:scale(1.06)}
.radiobar-btn:disabled{cursor:wait}
.radiobar-btn:disabled:hover{transform:none}
/* One icon at a time, chosen by the button's own state. Stacking them in the
   same grid cell keeps the button from resizing as they swap. */
.radiobar-btn > svg{grid-area:1/1;display:none}
.radiobar-btn[data-state="playing"] .ico-stop{display:block}
.radiobar-btn:not([data-state="playing"]) .ico-play{display:block}

/* While connecting, a ring sweeps around the button and the play arrow stays
   where it is. The icon itself never rotates — a spinning play triangle reads
   as broken rather than busy.
   No transition on this element: it also carries the rotation, and a
   transition on opacity alongside an animation on transform kept restarting
   and never arrived, leaving the ring permanently invisible. Appearing at once
   is what a loading indicator should do anyway. */
.btn-spin{
  position:absolute;inset:-3px;border-radius:50%;
  border:2px solid rgba(255,255,255,.22);
  border-top-color:#fff;
  opacity:0;
  pointer-events:none;
}
.radiobar.loading .btn-spin{opacity:1;animation:radiobar-spin .7s linear infinite}
@keyframes radiobar-spin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){
  .radiobar.loading .btn-spin{animation:none;opacity:.6}
}

/* Кольцо вокруг кнопки дышит вместе с низкими частотами: --fm-level ставит
   скрипт анализатора на каждом кадре. Без звука переменной нет, и подставляется
   ноль — кольцо тогда ровно такое, каким было раньше. */
.radiobar.on .radiobar-btn{
  box-shadow:0 0 0 calc(2px + var(--fm-level,0) * 4px)
             rgba(255,138,31,calc(.16 + var(--fm-level,0) * .3));
}
.radiobar.loading .radiobar-btn{box-shadow:0 0 0 3px rgba(255,138,31,.12)}
/* Анализатор. Ширина маленькая намеренно: полоса висит поверх каждой страницы
   сайта, и много движения внизу экрана мешает читать. Четырнадцати столбиков
   хватает, чтобы услышанное было видно, и мало, чтобы отвлекать. */
.fmviz{
  width:64px;height:20px;flex:0 0 auto;display:none;
}
.radiobar.on .fmviz{display:block}
@media(max-width:620px){.fmviz{width:44px}}

/* Верхняя кромка полосы светится на громких местах. Тень, а не рамка: рамка
   сдвинула бы содержимое на пиксель при каждом ударе. */
.radiobar.on{
  box-shadow:0 -14px 26px -16px rgba(255,138,31,calc(var(--fm-level,0) * .55));
}

.radiobar-tx{flex:1 1 auto;min-width:0;display:grid;gap:.05rem;text-decoration:none}
.radiobar-tx b{font-size:.8125rem;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.radiobar-tx:hover b{color:var(--amber)}
.radiobar-vol{display:flex;align-items:center;gap:.5rem;flex:0 0 auto}
.radiobar-vol input{width:96px;accent-color:var(--amber)}
.radiobar-note{margin:0;padding:0 var(--gut) .4rem;color:var(--ember)}
.radiobar-note:empty{display:none}
.radiobar.offline .radiobar-btn{opacity:.4;pointer-events:none}
@media(max-width:620px){.radiobar-vol{display:none}}

@media(prefers-reduced-motion:reduce){
  /* анализатор при этой настройке вовсе не запускается — убираем и то, что
     от него зависит, чтобы не осталось половины эффекта */
  .fmviz{display:none!important}
  .radiobar.on{box-shadow:none}
  .radiobar.on .radiobar-btn{box-shadow:0 0 0 3px rgba(255,138,31,.2)}
}

/* the bar floats over the page, so the last content needs room beneath it */
body{padding-bottom:56px}

/* ---------- radio page ---------- */
.player{display:flex;align-items:center;gap:.9rem;flex-wrap:wrap}
.player-btn{
  width:48px;height:48px;flex:0 0 auto;border:0;border-radius:50%;cursor:pointer;
  background:linear-gradient(160deg,var(--amber),var(--ember));color:#1A0A04;
  display:grid;place-items:center;transition:transform .14s,box-shadow .14s;
}
.player-btn:hover{transform:scale(1.05)}
.player-btn.on{box-shadow:0 0 0 4px rgba(255,138,31,.18)}
.player-tx{flex:1 1 12rem;min-width:0;display:grid;gap:.15rem}
.player-tx b{font-size:.9375rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.player-vol{display:flex;align-items:center;gap:.5rem;flex:0 0 auto}
.player-vol input{width:110px;accent-color:var(--amber)}
.player-note{margin:.6rem 0 0;color:var(--ember)}
.player-note:empty{display:none}

.trow{display:flex;align-items:center;gap:.7rem;padding:.5rem .85rem;border-bottom:1px solid var(--line-soft)}
.trow:last-child{border-bottom:0}
.trow:hover{background:var(--surface-2)}
.trow .n{font-family:var(--mono);font-size:.75rem;color:var(--faint);width:1.75rem;flex:0 0 auto}
.trow-title{flex:1 1 auto;min-width:0;font-size:.8125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.trow-score{flex:0 0 auto;font-size:.75rem;color:var(--live)}

.ch{display:flex;align-items:center;gap:.6rem;padding:.55rem .85rem;border-bottom:1px solid var(--line-soft);text-decoration:none;transition:background .14s}
.ch:last-child{border-bottom:0}
.ch:hover{background:var(--surface-2)}
.ch .hash{font-family:var(--mono);color:var(--faint);flex:0 0 auto}
.ch .nm{flex:1 1 auto;font-size:.8125rem}
.ch .cnt{font-family:var(--mono);font-size:.6875rem;color:var(--faint)}
.ch .new{font-family:var(--mono);font-size:.625rem;background:var(--ember);color:#fff;border-radius:20px;padding:.05rem .35rem}

/* .prog went with the home page block; .track stays — the profile still
   draws a level bar, where there is room for one */
.track{height:5px;background:var(--surface-2);border-radius:3px;overflow:hidden}
.track>span{display:block;height:100%;background:linear-gradient(90deg,var(--amber),var(--ember))}

/* ---------- misc ---------- */
.tiles{display:grid;gap:.75rem;grid-template-columns:repeat(auto-fit,minmax(14rem,1fr))}
.tile{border:1px solid var(--line);border-radius:6px;background:var(--surface);padding:.85rem;display:grid;gap:.35rem}
.tile p{margin:0;color:var(--muted);font-size:.8125rem}

/* ---------- community chat ---------- */
/* Two columns and a fixed height: the channel list stays put and only the
   message stream scrolls, which is what makes a chat feel like a chat rather
   than a page you scroll past. */
.chat{
  display:grid;gap:1rem;grid-template-columns:15rem minmax(0,1fr);
  height:calc(100vh - 15rem);min-height:32rem;
}
@media(max-width:899px){
  .chat{grid-template-columns:1fr;height:auto;min-height:0}
}

.chat-rail{
  display:flex;flex-direction:column;min-height:0;overflow-y:auto;
  border:1px solid var(--line);border-radius:6px;background:var(--surface);padding:.5rem;
}
@media(max-width:899px){.chat-rail{max-height:14rem}}
.chat-rail-h{padding:.35rem .5rem .3rem}

.chan{
  display:flex;align-items:center;gap:.5rem;padding:.45rem .5rem;border-radius:5px;
  text-decoration:none;color:var(--muted);transition:background .12s,color .12s;
}
.chan:hover{background:var(--surface-2);color:var(--text)}
.chan.on{background:var(--surface-2);color:var(--text);box-shadow:inset 2px 0 0 var(--amber)}
.chan-hash{font-family:var(--mono);color:var(--faint);flex:0 0 auto}
.chan.on .chan-hash{color:var(--amber)}
.chan-tx{flex:1 1 auto;min-width:0;display:flex;align-items:baseline;gap:.35rem;flex-wrap:wrap}
.chan-tx b{font-size:.8125rem;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chan-flag{font-size:.5625rem;color:var(--faint);border:1px solid var(--line);border-radius:3px;padding:0 .25rem}
.chan-n{flex:0 0 auto;font-family:var(--mono);font-size:.625rem;color:var(--faint)}
/* replaces the message count when there is something new to read */
.chan-new{
  flex:0 0 auto;min-width:1.15rem;padding:0 .3rem;border-radius:999px;
  background:var(--amber);color:var(--bg);
  font-family:var(--mono);font-size:.625rem;line-height:1.15rem;text-align:center;
}

.whos{display:flex;flex-wrap:wrap;gap:.3rem;padding:.25rem .5rem}
.who{position:relative;display:block;line-height:0}
.who-dot{
  position:absolute;right:0;bottom:0;width:8px;height:8px;border-radius:50%;
  background:var(--live);border:2px solid var(--surface);
}
.who-dot.adm{background:var(--amber)}

.chat-main{
  display:flex;flex-direction:column;min-height:0;
  border:1px solid var(--line);border-radius:6px;background:var(--surface);overflow:hidden;
}
.chat-head{
  display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;
  padding:.75rem .9rem;border-bottom:1px solid var(--line);background:var(--surface-2);
}
.chat-head h1{font-size:1rem;text-transform:none}
.chat-head p{margin:.2rem 0 0;color:var(--muted);font-size:.75rem;max-width:60ch}
.chat-live{display:flex;align-items:center;gap:.35rem;flex:0 0 auto;font-size:.6875rem;color:var(--live)}
.chat-live-dot{
  width:7px;height:7px;border-radius:50%;background:var(--live);
  box-shadow:0 0 0 0 color-mix(in srgb,var(--live) 60%,transparent);
  animation:livepulse 2.4s ease-out infinite;
}
@keyframes livepulse{
  0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--live) 55%,transparent)}
  70%{box-shadow:0 0 0 7px transparent}
  100%{box-shadow:0 0 0 0 transparent}
}
@media(prefers-reduced-motion:reduce){.chat-live-dot{animation:none}}

.pinned{display:grid;gap:.25rem;padding:.5rem .9rem;border-bottom:1px solid var(--line-soft);background:rgba(255,138,31,.05)}
.pinned-i{display:flex;gap:.45rem;font-size:.75rem;color:var(--muted)}
.pinned-i b{color:var(--text)}
.pinned-mark{flex:0 0 auto;opacity:.8}

.stream{flex:1 1 auto;min-height:0;overflow-y:auto;padding:.5rem 0;scrollbar-width:thin}
.stream-blank{padding:1.5rem 1rem}

.msg{display:flex;gap:.6rem;padding:.2rem .9rem}
.msg:hover{background:rgba(255,255,255,.018)}
.msg-av{width:36px;flex:0 0 auto}
.msg-av img{width:36px;height:36px;border-radius:50%;object-fit:cover;display:block;background:var(--surface-2)}
.msg-av-none{
  display:grid;place-items:center;width:36px;height:36px;border-radius:50%;
  background:var(--surface-2);color:var(--muted);font-size:.875rem;
}
.msg-body{flex:1 1 auto;min-width:0}
.msg.grouped{padding-top:0;padding-bottom:.1rem}
.msg-top{display:flex;align-items:baseline;gap:.5rem;flex-wrap:wrap;margin-top:.35rem}
.msg-who{font-size:.8125rem;font-weight:600;color:var(--text);text-decoration:none}
a.msg-who:hover{color:var(--amber)}
.msg-who.game{color:var(--live)}
.msg-tag{
  font-size:.5625rem;color:var(--live);border:1px solid color-mix(in srgb,var(--live) 40%,transparent);
  border-radius:3px;padding:0 .25rem;
}
.msg-mark{font-size:.8125rem;line-height:1}
.msg-top time{font-family:var(--mono);font-size:.5625rem;color:var(--faint)}
.msg-tx{margin:.1rem 0 0;color:#C7CEDA;font-size:.875rem;line-height:1.5;overflow-wrap:anywhere;white-space:pre-wrap}
.msg.from-game .msg-tx{color:var(--muted)}
.msg-media{display:flex;flex-wrap:wrap;gap:.35rem;margin-top:.35rem}
.msg-media a{
  display:block;max-width:14rem;max-height:11rem;overflow:hidden;
  border:1px solid var(--line);border-radius:5px;background:var(--surface-2);
}
.msg-media a:hover{border-color:var(--amber)}
.msg-media img{width:100%;height:100%;object-fit:cover;display:block}

.msg-reply{
  display:block;margin-top:.2rem;padding-left:.5rem;border-left:2px solid var(--line);
  color:var(--faint);font-size:.75rem;text-decoration:none;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.msg-reply:hover{color:var(--muted)}
.msg-reply b{color:var(--muted)}

.msg-acts{display:flex;gap:.3rem;margin-top:.15rem;opacity:0;transition:opacity .12s}
.msg:hover .msg-acts,.msg:focus-within .msg-acts{opacity:1}
.msg-acts form{margin:0}
.react{
  border:1px solid var(--line);background:var(--surface-2);color:var(--faint);
  border-radius:4px;padding:.1rem .4rem;font-family:var(--ui);font-size:.625rem;cursor:pointer;
}
.react:hover{color:var(--text);border-color:var(--muted)}
.react.on{color:var(--live);border-color:color-mix(in srgb,var(--live) 45%,transparent)}

.composer{padding:.6rem .9rem .7rem;border-top:1px solid var(--line);background:var(--surface-2)}
.composer.locked{display:flex;align-items:center;justify-content:center;gap:.5rem;padding:.9rem}
.composer-row{display:flex;gap:.5rem;align-items:flex-end}
.composer textarea{
  flex:1 1 auto;min-width:0;resize:none;overflow-y:auto;max-height:10rem;
  background:var(--bg);color:var(--text);border:1px solid var(--line);border-radius:5px;
  padding:.55rem .7rem;font-family:var(--ui);font-size:.875rem;line-height:1.45;
}
.composer textarea:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}
.composer-note{margin:.35rem 0 0}
.composer-reply{
  display:flex;align-items:center;justify-content:space-between;gap:.5rem;
  margin-bottom:.4rem;padding:.3rem .5rem;border-left:2px solid var(--amber);
  background:var(--surface);border-radius:0 4px 4px 0;font-size:.75rem;color:var(--muted);
}
.composer-reply[hidden]{display:none}
.composer-reply button{background:none;border:0;color:var(--faint);cursor:pointer;font-size:1rem;line-height:1}

.note{margin-top:1.25rem;padding:.7rem .85rem;border:1px dashed var(--line);border-radius:6px;color:var(--faint);font-size:.75rem}
.note code{font-family:var(--mono);color:var(--muted)}

footer{border-top:1px solid var(--line);padding-block:1.25rem;color:var(--faint);font-size:.75rem}

a:focus-visible,button:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}

/* the cabinet's pointer at the shop that used to live inside it */
.cab-tolavka{display:flex;align-items:center;gap:1rem;flex-wrap:wrap}
.cab-tolavka>div{flex:1 1 14rem;min-width:0}

/* ---------- чат: свои справа, чужие слева ---------- */
/* Only in site channels. The bridge channel keeps the flat list it had: it is
   a feed from the server, none of it is "yours", and half of it has no site
   account behind it at all. */

.stream-chat .msg{gap:.5rem;padding:.1rem .9rem}
.stream-chat .msg.mine{flex-direction:row-reverse}
.stream-chat .msg.mine .msg-av{display:none}

.stream-chat .msg-body{
  display:flex;flex-direction:column;align-items:flex-start;
  /* a one-word reply should not stretch a bubble across the room, and a long
     one should still stop short of the far edge so the side stays readable */
  max-width:min(76%,42rem);flex:0 1 auto;
}
.stream-chat .msg.mine .msg-body{align-items:flex-end;margin-left:auto}

.stream-chat .msg-bubble{
  position:relative;padding:.4rem .6rem .3rem;
  border:1px solid var(--line);border-radius:12px;border-top-left-radius:4px;
  background:var(--surface-2);
}
.stream-chat .msg.mine .msg-bubble{
  border-top-left-radius:12px;border-top-right-radius:4px;
  background:rgba(255,138,31,.11);border-color:rgba(255,138,31,.26);
}
/* a run from the same person is one block, so only its first bubble is notched */
.stream-chat .msg.grouped .msg-bubble{border-top-left-radius:12px}
.stream-chat .msg.mine.grouped .msg-bubble{border-top-right-radius:12px}

.stream-chat .msg-tx{margin:0}
.stream-chat .msg-top{margin:.3rem 0 .15rem}
.stream-chat .msg.mine .msg-acts{align-self:flex-end}
.stream-chat .msg-media{margin-top:.3rem}
.stream-chat .msg-reply{margin-bottom:.2rem}

.msg-time{
  display:block;text-align:right;margin-top:.1rem;
  font-family:var(--mono);font-size:.5625rem;color:var(--faint);line-height:1;
}
/* the feed keeps its own timestamp in the name row; a second one is noise */
.stream-feed .msg-time{display:none}
.stream-chat .msg-top time{display:none}

@media(max-width:560px){
  .stream-chat .msg-body{max-width:86%}
}

/* ---------- модерация чата ---------- */

.msg-mod{display:inline-flex;align-items:center;gap:.35rem;flex-wrap:wrap}
.modbtn{
  background:none;border:0;padding:0;cursor:pointer;
  font-size:.6875rem;color:var(--faint);font-family:inherit;
}
.modbtn:hover{color:var(--text)}
.modbtn.danger:hover{color:var(--ember)}
summary.modbtn{list-style:none}
summary.modbtn::-webkit-details-marker{display:none}

.msg-flag{
  font-size:.625rem;padding:.05rem .35rem;border-radius:999px;
  background:rgba(232,69,42,.16);color:#FFC9BC;
}
.msg-flag.struck-mark{background:rgba(126,136,153,.18);color:var(--muted)}

/* a hidden message stays on screen for moderators, visibly struck out, so a
   wrong call can be found and undone instead of vanishing */
.msg.struck .msg-tx{opacity:.5;text-decoration:line-through}
.msg.flagged .msg-bubble{box-shadow:0 0 0 1px rgba(232,69,42,.4)}

.mutebox{position:relative;display:inline-block}
.muteform{
  position:absolute;right:0;bottom:1.4rem;z-index:5;
  display:grid;gap:.3rem;width:min(17rem,70vw);padding:.5rem;
  border:1px solid var(--line);border-radius:6px;background:var(--surface);
  box-shadow:0 8px 24px -12px #000;
}
.muteform select,.muteform input{font-size:.75rem}
.muteform .join{justify-content:center;font-size:.75rem;padding:.3rem .6rem}
/* near the top of the stream the popover would open off-screen upwards */
.msg:first-child .muteform,.msg:nth-child(2) .muteform{bottom:auto;top:1.4rem}

.mutelist{display:grid;gap:.2rem;padding:0 .5rem}
.mutelist-row{display:flex;align-items:baseline;gap:.4rem;font-size:.75rem;flex-wrap:wrap}
.mutelist-row a{color:var(--text);text-decoration:none}
.mutelist-row a:hover{color:var(--amber)}
.mutelist-row form{margin-left:auto}

.composer.locked.muted{border-top:1px solid rgba(232,69,42,.3);background:rgba(232,69,42,.06)}

/* ---------- друзья ---------- */
.friendform{margin:0;display:inline-block}
.fr-acts{margin-left:auto;display:flex;align-items:center;gap:.5rem;flex:0 0 auto}
.fr-acts form{margin:0}
.fr-btn{font-size:.75rem;padding:.3rem .6rem}

/* ---------- поиск друга ---------- */

.fr-find{border-bottom:1px solid var(--line-soft)}
.fr-open{font-size:.8125rem}

/* margin-top на самой коробке, а не gap у родителя: пока она скрыта, gap всё
   равно оставил бы под кнопкой пустую полосу */
.fr-find-box{margin-top:.7rem}

.fr-find-in{
  width:100%;padding:.5rem .7rem;
  font:inherit;font-size:.8125rem;color:var(--tx);
  background:var(--bg);border:1px solid var(--line);border-radius:6px;
  outline:none;
}
.fr-find-in:focus{border-color:var(--amber)}

/* Найденные строки отбиты от поля и подрезаны по высоте: дюжина игроков
   выталкивала бы вкладку вниз, и список друзей уезжал бы с экрана. */
.fr-find-out{margin-top:.5rem;max-height:19rem;overflow-y:auto}
.fr-find-out .ref-row{padding-left:0;padding-right:0}
.btn-steam-link.on{border-color:color-mix(in srgb,var(--live) 45%,var(--line));color:var(--live)}
.btn-steam-link.muted{color:var(--faint)}
button.btn-steam-link{cursor:pointer;background:none;font-family:inherit}
.whoson-friends{margin:0 0 .6rem;font-size:.8125rem;color:var(--muted)}
.whoson-friends b{color:var(--text)}
.whoson-friends a{text-decoration:none}

/* ---------- лента событий ---------- */

/* Вид события задаёт строке один цвет, и дальше он расходится по полосе слева,
   названию и бейджу. Три разных места, но глаз собирает их в одну метку и
   отличает достижение от уровня, не вчитываясь в слова.
   Аватар намеренно оставлен в покое: там своя косметика, купленная игроками,
   и подмешивать к ней служебный цвет — значит спорить с тем, за что заплачено. */
.feed-row{
  --k:var(--faint);
  position:relative;
  display:flex;align-items:center;gap:.6rem;padding:.45rem .85rem .45rem 1rem;
  border-bottom:1px solid var(--line-soft);
  transition:background-color .16s ease;
}
.feed-k-achievement{--k:var(--amber)}
.feed-k-level{--k:var(--live)}
.feed-k-base{--k:var(--shop)}
.feed-k-joined{--k:var(--faint)}

/* Полоса псевдоэлементом, а не border-left: рамка сдвинула бы содержимое всех
   строк, а так она гасится до трети и разгорается только под курсором. */
.feed-row::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:2px;
  background:var(--k);opacity:.32;
  transition:opacity .16s ease;
}
.feed-row:hover{background:color-mix(in srgb,var(--k) 7%,transparent)}
.feed-row:hover::before{opacity:1}
.feed-row:last-child{border-bottom:0}

.feed-av{flex:0 0 auto}

/* Перенос, а не многоточие.
   Колонка ленты — 199 px, и «выбил достижение «Постоялец сервера»» требует
   291: при nowrap многоточие съедало ровно название, то есть то единственное,
   ради чего строка написана. Клэмп на двух строках тоже не подошёл — он режет
   по три пикселя сверху тем, у кого косметический шрифт выше строки. Самое
   длинное имя достижения — 21 символ, так что перенос дальше второй строки
   не уходит и ограничивать его нечем. */
.feed-tx{flex:1 1 auto;min-width:0;font-size:.8125rem;line-height:1.55}

/* Имя игрока — то, ради чего ленту читают, поэтому оно единственное здесь
   идёт полным весом и полным цветом. У кого куплена косметика, тот перебьёт
   и вес, и цвет своими правилами из cosmetics.css — так и задумано. */
.feed-who{text-decoration:none;font-weight:600;color:var(--text)}
.feed-what{color:var(--muted);text-decoration:none}
a.feed-what[href]:hover{color:var(--k)}
.feed-when{flex:0 0 auto}

/* Название достижения или базы.
   Кегль мелкий, ширины в колонке мало, поэтому подсветка работает здесь одним
   светом: плашка или рамка разрезали бы строку на куски и отняли ту ширину,
   которой и так не хватает. Приём тот же, что у имён в косметике, — градиент
   по глифам, с запасным цветом на случай, если clip не поддержан.
   Движение отдельно глушить не нужно: prefers-reduced-motion снимает анимации
   со всего разом общим правилом выше по файлу — оно с !important, так что
   порядок в каскаде роли не играет. */
.feed-ach{
  font-weight:600;
  color:var(--k);
  background-image:linear-gradient(100deg,
    var(--k) 0%,var(--k) 40%,
    color-mix(in srgb,var(--k) 55%,#fff) 47%,
    color-mix(in srgb,var(--k) 20%,#fff) 50%,
    color-mix(in srgb,var(--k) 55%,#fff) 53%,
    var(--k) 60%,var(--k) 100%);
  background-size:300% 100%;
  -webkit-background-clip:text;background-clip:text;
  -webkit-text-fill-color:transparent;
  filter:drop-shadow(0 0 5px color-mix(in srgb,var(--k) 32%,transparent));
  animation:feed-sheen 6s linear infinite;
}
/* Медленнее, чем блик на именах: лента висит на главной постоянно, и то, что
   в профиле смотрится живым, здесь мельтешило бы на краю глаза. */
@keyframes feed-sheen{from{background-position:200% 0}to{background-position:-70% 0}}

/* Число рядом с событием: ступень достижения или взятый уровень. Приглушено
   намеренно — оно уточняет, а не сообщает, и спорить с названием ему незачем. */
.feed-tier{
  display:inline-block;
  margin-left:.3em;padding:0 .32em;
  border-radius:3px;
  font-family:var(--mono);font-size:.6875rem;font-weight:700;
  color:var(--k);background:color-mix(in srgb,var(--k) 15%,transparent);
}

/* ---------- «В чате» на главной ---------- */
.chatline{
  display:flex;gap:.5rem;padding:.5rem .85rem;text-decoration:none;color:var(--text);
  border-bottom:1px solid var(--line-soft);
}
.chatline:last-child{border-bottom:0}
.chatline:hover{background:var(--surface-2)}
.chatline-av{flex:0 0 auto;margin-top:.1rem}
.chatline-tx{flex:1 1 auto;min-width:0;display:grid;gap:.1rem}
.chatline-top{display:flex;align-items:baseline;gap:.4rem;min-width:0}
.chatline-who{font-size:.75rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chatline-top time{margin-left:auto;flex:0 0 auto}
.chatline-body{
  font-size:.8125rem;color:var(--muted);line-height:1.4;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}

/* Present for screen readers and for the document outline, absent on screen.
   clip-path rather than display:none — hidden elements are skipped by
   assistive technology entirely, which would defeat the point. */
.sr-only{
  position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0;
}

/* ---------- стол поддержки ---------- */
/* The same shape as the chat, under its own name: the community script binds
   to `.chat` by querySelector and would start polling a channel that is not
   there. Sub-classes are shared on purpose — it is the same kind of screen. */

.desk{
  display:grid;gap:1rem;grid-template-columns:19rem minmax(0,1fr);
  height:calc(100vh - 15rem);min-height:32rem;
}
@media(max-width:899px){
  .desk{grid-template-columns:1fr;height:auto;min-height:0}
}

.desk-badge{
  margin-left:auto;min-width:1.2rem;padding:0 .35rem;border-radius:999px;
  background:var(--ember);color:#fff;font-size:.6875rem;line-height:1.2rem;text-align:center;
}
.desk-filters{display:flex;gap:.3rem;padding:.4rem .5rem;border-bottom:1px solid var(--line-soft)}
.desk-filter{
  flex:1 1 0;text-align:center;padding:.25rem .3rem;border-radius:4px;
  font-size:.6875rem;color:var(--muted);text-decoration:none;
}
.desk-filter:hover{color:var(--text);background:var(--surface-2)}
.desk-filter.on{color:var(--text);background:var(--surface-2);box-shadow:inset 0 -2px 0 var(--amber)}

/* only the list scrolls; the rail must not, or the search box and the filters
   slide away with it and there is nothing left to steer by */
.chat-rail:has(.desk-list){overflow:hidden}
.desk-list{flex:1 1 auto;min-height:0;overflow-y:auto;scrollbar-width:thin}

.desk-find{display:block;padding:.35rem .5rem}
.desk-find input{
  width:100%;font-size:.8125rem;padding:.3rem .5rem;
  border:1px solid var(--line);border-radius:4px;
  background:var(--surface-2);color:var(--text);
}
.desk-find input:focus{outline:none;border-color:var(--muted)}
.desk-item{
  position:relative;display:flex;gap:.55rem;padding:.55rem .6rem;
  text-decoration:none;color:var(--text);border-bottom:1px solid var(--line-soft);
}
.desk-item:hover{background:var(--surface-2)}
.desk-item.on{background:var(--surface-2);box-shadow:inset 2px 0 0 var(--amber)}
.desk-av{flex:0 0 auto;margin-top:.1rem}
.desk-tx{flex:1 1 auto;min-width:0;display:grid;gap:.1rem}
.desk-top{display:flex;align-items:baseline;gap:.4rem;min-width:0}
.desk-who{font-size:.8125rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.desk-top time{margin-left:auto;flex:0 0 auto}
.desk-prev{
  font-size:.75rem;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.desk-you{font-style:normal;color:var(--faint)}
/* an unanswered conversation earns the one bright thing in the list */
.desk-dot{
  position:absolute;right:.5rem;bottom:.55rem;
  width:.4rem;height:.4rem;border-radius:50%;background:var(--ember);
}
.desk-item.wait .desk-prev{color:var(--text)}

.desk-head{align-items:flex-start}
.desk-head h1{font-size:1rem;text-transform:none}
.desk-acts{display:flex;align-items:center;gap:.4rem;margin-left:auto;flex:0 0 auto}
.desk-acts form{margin:0}
.me-desk{
  position:relative;flex:0 0 auto;display:grid;place-items:center;
  width:28px;height:28px;border-radius:5px;text-decoration:none;
  border:1px solid var(--line);color:var(--muted);font-size:.8125rem;
}
.me-desk:hover{border-color:var(--muted);color:var(--text)}
.me-desk i{
  position:absolute;top:-5px;right:-5px;font-style:normal;
  min-width:14px;padding:0 3px;border-radius:999px;
  background:var(--ember);color:#fff;font-family:var(--mono);font-size:.5625rem;line-height:14px;text-align:center;
}

/* счётчик неотвеченных у фильтра — отдельно от счётчика непрочитанных */
.desk-filter i{
  font-style:normal;margin-left:.25rem;font-family:var(--mono);font-size:.625rem;color:var(--amber);
}
.desk-back{display:none}

@media(max-width:899px){
  /* the two halves take turns instead of stacking: with both on screen the
     reply box sat below the entire list, every single time */
  .desk .chat-rail{max-height:none}
  .desk.desk-open .chat-rail{display:none}
  .desk:not(.desk-open) .chat-main{display:none}

  .desk-back{
    display:grid;place-items:center;flex:0 0 auto;
    width:30px;height:30px;margin-right:.5rem;border-radius:5px;
    border:1px solid var(--line);color:var(--muted);text-decoration:none;font-size:1rem;
  }
  .desk-back:hover{border-color:var(--muted);color:var(--text)}
}

/* ---------- заказ трека на странице радио ---------- */

.ord-price{flex:0 0 auto;font-family:var(--mono);font-size:.8125rem}
.ord-lead{margin:0 0 .7rem;color:var(--muted);font-size:.8125rem;line-height:1.5}
.ord-form{display:grid;gap:.5rem}
.ord-form select{width:100%;font-size:.8125rem}
.ord-btn{width:100%;justify-content:center}
.ord-note{display:flex;align-items:center;gap:.35rem;flex-wrap:wrap;margin:.6rem 0 0}

/* the queue reads as a running order, so the one that is next is marked as
   next rather than numbered like the rest */
.ord-queue{border-top:1px solid var(--line-soft);padding-top:.6rem}
.ord-queue-h{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:.4rem}
.ord-row{display:flex;align-items:baseline;gap:.6rem;padding:.35rem 0;border-bottom:1px solid var(--line-soft)}
.ord-row:last-child{border-bottom:0}
.ord-n{
  flex:0 0 auto;width:1.2rem;text-align:center;
  font-family:var(--mono);font-size:.75rem;color:var(--faint);
}
.ord-row.next .ord-n{color:var(--live)}
.ord-tx{display:grid;gap:.05rem;min-width:0}
.ord-tx b{font-size:.8125rem;line-height:1.25;overflow-wrap:anywhere}

/* Thirty track names stacked one per line made a 1156px column against a
   156px neighbour. They are names, not prose — two abreast reads the same and
   halves the page. */
@media(min-width:900px){
  .rot{columns:2;column-gap:0}
  .rot .trow{break-inside:avoid}
  .rot .trow:nth-child(n+2){border-top:0}
}
.ord-mine{display:grid;gap:.15rem;margin-bottom:.7rem}
.ord-mine .ord-row{justify-content:space-between}
.ord-mine form{margin:0}
.ord-form input[type=file]{font-size:.75rem;color:var(--muted)}
.ord-form input[type=text]{font-size:.8125rem}

/* ---------- плеер на странице радио ---------- */

.player{display:flex;align-items:center;gap:1rem;padding:1rem;overflow:hidden;position:relative}
.player.off{opacity:.75}

.player-stage{position:relative;flex:0 0 auto;display:grid;place-items:center;width:76px;height:76px}
/* a light behind the button that only breathes while sound is coming out */
.player-glow{
  position:absolute;inset:0;border-radius:50%;
  background:radial-gradient(circle,color-mix(in srgb,var(--amber) 45%,transparent),transparent 70%);
  opacity:0;transition:opacity .3s;
}
.player.live .player-glow{opacity:1;animation:player-breathe 2.6s ease-in-out infinite}
@keyframes player-breathe{0%,100%{transform:scale(.9);opacity:.55}50%{transform:scale(1.1);opacity:1}}

.player-btn{
  position:relative;z-index:2;width:56px;height:56px;border:0;border-radius:50%;cursor:pointer;
  display:grid;place-items:center;color:#1A0A04;
  background:linear-gradient(160deg,var(--amber),var(--ember));
  transition:transform .14s;
}
.player-btn:hover:not(:disabled){transform:scale(1.05)}
.player-btn:disabled{cursor:default;filter:grayscale(.6)}
.player-btn>svg{grid-area:1/1;display:none}
/* idle shows the arrow, playing shows the square — a stream has no timeline,
   so pause bars would promise a resume that cannot happen */
.player-btn[data-state="idle"] .ico-play{display:block}
.player-btn[data-state="loading"] .ico-play{display:block;opacity:.35}
.player-btn[data-state="playing"] .ico-stop{display:block}

.player-spin{
  position:absolute;inset:-4px;border-radius:50%;display:none;
  border:2px solid transparent;border-top-color:var(--amber);
}
.player-btn[data-state="loading"] .player-spin{display:block;animation:player-spin .8s linear infinite}
@keyframes player-spin{to{transform:rotate(360deg)}}

.player-eq{
  position:absolute;right:-2px;bottom:2px;z-index:3;
  display:none;align-items:flex-end;gap:2px;height:14px;
}
.player.live .player-eq{display:flex}
.player-eq i{width:2px;background:var(--amber);border-radius:1px;animation:bars 1.1s ease-in-out infinite}
.player-eq i:nth-child(2){animation-delay:.15s;background:var(--ember)}
.player-eq i:nth-child(3){animation-delay:.3s}
.player-eq i:nth-child(4){animation-delay:.45s;background:var(--ember)}
.player-eq i:nth-child(5){animation-delay:.6s}

.player-tx{min-width:0;display:grid;gap:.15rem}
.player-station{display:flex;align-items:center;gap:.4rem;font-size:.75rem;color:var(--muted);flex-wrap:wrap}
.player-track{font-size:1rem;line-height:1.25;overflow-wrap:anywhere}
.player-artist{font-size:.8125rem;color:var(--muted)}
.player-note{margin:.2rem 0 0}

@media(prefers-reduced-motion:reduce){
  .player.live .player-glow,.player-eq i,.player-btn[data-state="loading"] .player-spin{animation:none}
}

/* ---------- очередь заказов ---------- */

.que{border-top:1px solid var(--line-soft);padding-top:.6rem}
.que-h{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:.4rem}
.que-row{
  position:relative;display:flex;align-items:center;gap:.5rem;
  padding:.4rem .5rem;border-radius:6px;margin:0 -.5rem;
}
/* the one about to play is the only line that needs to stand out */
.que-row.next{background:color-mix(in srgb,var(--live) 8%,transparent)}
.que-row.mine{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--amber) 35%,transparent)}
.que-n{
  flex:0 0 auto;width:1.1rem;text-align:center;
  font-family:var(--mono);font-size:.75rem;color:var(--faint);
}
.que-row.next .que-n{color:var(--live)}
.que-av{flex:0 0 auto}
.que-tx{flex:1 1 auto;min-width:0;display:grid;gap:.05rem}
.que-tx b{font-size:.8125rem;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.que-who{display:flex;align-items:center;gap:.25rem;min-width:0}
.que-mine{
  flex:0 0 auto;font-size:.5625rem;letter-spacing:.06em;text-transform:uppercase;
  padding:.1rem .35rem;border-radius:999px;background:var(--amber-dim);color:var(--amber);
}
.que-soon{flex:0 0 auto;color:var(--live)}
@media(max-width:420px){.que-soon{display:none}}

/* ---------- другие игры ---------- */

.gamegrid{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(17rem,1fr))}
.gamecard{
  display:grid;grid-template-rows:auto 1fr;overflow:hidden;
  border:1px solid var(--line);border-radius:8px;background:var(--surface);
  transition:border-color .14s,transform .14s;
}
.gamecard:hover{border-color:var(--amber);transform:translateY(-2px)}

.gamecard-cover{
  position:relative;aspect-ratio:16/9;display:grid;place-items:center;overflow:hidden;
  background:linear-gradient(160deg,var(--surface-2),var(--bg));
  border-bottom:1px solid var(--line);
}
.gamecard-cover img{width:100%;height:100%;object-fit:cover;display:block}
/* буква проступает только там, где обложки нет или она не загрузилась */
.gamecard-letter{
  position:absolute;font-family:var(--ui);font-size:3.5rem;font-weight:700;
  color:var(--line);letter-spacing:.04em;opacity:0;
}
.gamecard-cover.none .gamecard-letter,
.gamecard-cover:not(:has(img)) .gamecard-letter{opacity:1}

.gamecard-flag{
  position:absolute;top:.5rem;right:.5rem;z-index:2;
  font-size:.625rem;letter-spacing:.08em;text-transform:uppercase;
  padding:.2rem .45rem;border-radius:4px;
  background:rgba(12,14,19,.82);color:var(--amber);border:1px solid var(--line);
}

.gamecard-body{display:grid;gap:.4rem;align-content:start;padding:.85rem}
.gamecard-body h3{margin:0;font-size:1rem}
.gamecard-body p{margin:0;color:var(--muted);font-size:.8125rem;line-height:1.45}
.gamecard-acts{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:.35rem}

/* ---------- поиск предмета в поддержке ---------- */

.desk-lookup{
  display:flex;gap:.5rem;padding:.6rem .8rem;
  border-bottom:1px solid var(--line-soft);background:var(--surface-2);
}
.desk-lookup input{
  flex:1 1 auto;min-width:0;background:var(--bg);color:var(--text);
  border:1px solid var(--line);border-radius:5px;padding:.4rem .65rem;
  font-family:var(--mono);font-size:.8125rem;
}
.desk-lookup input:focus{outline:2px solid var(--amber);outline-offset:1px;border-color:transparent}
.desk-lookup .join{flex:0 0 auto;padding:.4rem .9rem}

.desk-found{
  display:flex;align-items:center;gap:.7rem;margin:.6rem .8rem 0;padding:.6rem .7rem;
  border:1px solid var(--line);border-left:2px solid var(--live);border-radius:6px;
  background:var(--surface);
}
.desk-found-tx{display:grid;gap:.1rem;min-width:0;flex:1 1 auto}
.desk-found-tx b{font-size:.9375rem}
.desk-found code{font-family:var(--mono);font-size:.6875rem}
.desk-found.none{
  display:block;border-left-color:var(--faint);color:var(--muted);font-size:.8125rem;
}

/* ---------- сообщества ---------- */

.site-foot{
  display:flex;align-items:center;justify-content:space-between;
  gap:1rem;flex-wrap:wrap;
}
.site-foot-tx{margin:0}
.site-foot-tx a{color:inherit}

.soc{display:flex;list-style:none;margin:0;padding:0;flex-wrap:wrap;gap:.4rem}

.soc-a{
  display:inline-flex;align-items:center;gap:.4rem;
  text-decoration:none;color:var(--muted);
  border:1px solid var(--line);border-radius:5px;
  transition:color .14s,border-color .14s,background .14s;
}
.soc-i{display:grid;place-items:center;flex:0 0 auto}
.soc-i svg{width:100%;height:100%;display:block}

/* в подвале — только значки: подписи там повторяли бы очевидное */
.soc-small .soc-a{padding:.32rem;background:transparent}
.soc-small .soc-i{width:1rem;height:1rem}
.soc-small .soc-t{
  position:absolute;width:1px;height:1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;
}

/* отдельным блоком — с подписями, туда приходят читать */
.soc-big{gap:.5rem}
.soc-big .soc-a{padding:.5rem .8rem;font-size:.875rem;background:var(--surface-2)}
.soc-big .soc-i{width:1.125rem;height:1.125rem}

/* цвет площадки проступает только под указателем: ряд разноцветных значков
   спорит со всем вокруг, а один подсвеченный — отвечает на наведение */
.soc-a:hover,.soc-a:focus-visible{color:var(--brand,var(--amber));border-color:currentColor}
.soc-a.is-vk:hover,.soc-a.is-vk:focus-visible{--brand:#5181B8}
.soc-a.is-tg:hover,.soc-a.is-tg:focus-visible{--brand:#2AABEE}
.soc-a.is-discord:hover,.soc-a.is-discord:focus-visible{--brand:#5865F2}
.soc-a.is-steam:hover,.soc-a.is-steam:focus-visible{--brand:#66C0F4}
.soc-a.is-youtube:hover,.soc-a.is-youtube:focus-visible{--brand:#FF0033}
.soc-a.is-twitch:hover,.soc-a.is-twitch:focus-visible{--brand:#9146FF}
.soc-a:focus-visible{outline:2px solid var(--amber);outline-offset:2px}

@media(max-width:560px){
  .site-foot{justify-content:center;text-align:center}
}

.com-out{margin-bottom:.9rem}
.com-out-b{
  display:flex;align-items:center;justify-content:space-between;
  gap:1rem 1.5rem;flex-wrap:wrap;
}
.com-out-tx{display:grid;gap:.15rem;min-width:0}
.com-out-tx b{font-size:.9375rem}

/* ---------- награда за достижение ---------- */

.achcard-pay{
  display:grid;gap:.3rem;margin-top:.5rem;padding-top:.45rem;
  border-top:1px solid var(--line-soft);
}
.achcard-pay .pay-k{
  font-size:.625rem;letter-spacing:.05em;text-transform:uppercase;color:var(--faint);
}
.pay-list{display:flex;flex-wrap:wrap;gap:.25rem;list-style:none;margin:0;padding:0}
.pay-item{
  display:inline-flex;align-items:center;gap:.28rem;
  font-size:.6875rem;line-height:1.3;
  padding:.16rem .38rem;border-radius:4px;
  background:var(--surface-2);border:1px solid var(--line);color:var(--muted);
}
.pay-item img{display:block;flex:0 0 auto;object-fit:contain}
/* игровые награды и очки прогресса — разные вещи, и это видно без подписи */
.pay-item.t-server_command{color:var(--text);border-color:color-mix(in srgb,var(--amber) 35%,var(--line))}
.pay-item.t-xp{color:var(--live)}
.achcard.is-done .pay-item{opacity:.7}

/* ---------- знаки отличия ---------- */

/* Заслуженное не должно выглядеть как покупное. Гравированный уголок вместо
   ровной рамки: то же место, другой смысл. */
.item.is-earned .item-cell{
  border-style:double;
  border-width:3px;
  background:
    radial-gradient(120% 90% at 50% 100%,color-mix(in srgb,var(--rar) 30%,transparent),transparent 72%),
    var(--surface-2);
}
.item.is-earned .item-cell::after{
  border-width:.5rem;
  opacity:1;
}
.pop-earned{
  font-size:.625rem;letter-spacing:.04em;text-transform:uppercase;
  color:var(--rar);text-align:center;
  padding:.24rem .3rem;border:1px solid var(--rar);border-radius:3px;
  background:color-mix(in srgb,var(--rar) 12%,transparent);
}

/* ---------- промокод в кабинете ----------

   Приставка pcode-, а не promo-: класс .promo-tx уже занят подписью на слайдах
   главной, и она position:absolute. Мой заголовок унаследовал это и уехал в
   левый край страницы, за пределы кабинета. */

.pcode{border-bottom:1px solid var(--line-soft)}

/* Поле тянется, кнопка и подпись — нет: на узком экране строка сворачивается,
   и первым переносится именно поле, а не кнопка от него отдельно. */
.pcode-form{display:flex;align-items:center;gap:.7rem;flex-wrap:wrap}
.pcode-tx{flex:1 1 14rem;min-width:0}
.pcode-tx .cab-h{margin:0}

.pcode-in{
  flex:1 1 11rem;min-width:0;
  padding:.5rem .7rem;
  font-family:var(--mono);font-size:.8125rem;letter-spacing:.06em;
  text-transform:uppercase;color:var(--tx);
  background:var(--bg);border:1px solid var(--line);border-radius:6px;outline:none;
}
.pcode-in::placeholder{letter-spacing:normal;text-transform:none;color:var(--faint)}
.pcode-in:focus{border-color:var(--amber)}

/* ---------- голосование в кабинете ---------- */

/* Кнопка и объяснение в строку, но на узком экране объяснение уходит вниз
   целиком: разорванный по словам текст рядом с кнопкой читается хуже, чем
   под ней. */
.vote-call{display:flex;align-items:center;gap:1rem;flex-wrap:wrap}
.vote-call .lbl{flex:1 1 18rem;min-width:0;line-height:1.55}
.vote-btn{flex:0 0 auto}

.vote-nums{display:flex;gap:1.6rem;flex-wrap:wrap}
.vote-num{display:grid;gap:.1rem}
.vote-num b{font-size:1.5rem;line-height:1.1;color:var(--amber);font-variant-numeric:tabular-nums}

.vote-what{margin:0;padding:0;list-style:none;display:grid;gap:.55rem}
.vote-what li{display:grid;gap:.1rem}
.vote-what b{font-size:.875rem}

/* ---------- голосовой чат ---------- */

/* Первый экран. Решающее сказано здесь и больше нигде не повторяется:
   раньше кнопка стояла и сверху, и снизу, а объяснение занимало два абзаца. */
.lk-hero{
  position:relative;overflow:hidden;
  border:1px solid var(--line);border-radius:10px;
  padding:clamp(1.4rem,4vw,2.4rem);margin-bottom:1rem;text-align:center;
  background:
    radial-gradient(120% 130% at 50% -20%,rgba(255,138,31,.13),transparent 62%),
    linear-gradient(180deg,var(--surface),var(--bg));
}
.lk-hero h1{margin:0 0 .5rem;font-size:clamp(1.6rem,5vw,2.3rem);line-height:1.1}
.lk-lead{
  margin:0 auto;max-width:44ch;color:var(--muted);
  font-size:.9375rem;line-height:1.55;
}
.lk-lead b{color:var(--amber);font-weight:600}

/* Метки вместо абзацев. Зелёные — то, из-за чего соглашаются поставить
   незнакомую программу, и им же отдан единственный яркий цвет в ряду. */
.lk-badges{
  display:flex;flex-wrap:wrap;justify-content:center;gap:.4rem;
  list-style:none;margin:.9rem 0 1.2rem;padding:0;
}
.lk-badges li{
  font-size:.75rem;font-weight:600;letter-spacing:.02em;
  padding:.28rem .65rem;border-radius:999px;
  border:1px solid var(--line);background:var(--surface-2);color:var(--muted);
}
.lk-badges .is-key{
  color:var(--live);
  border-color:color-mix(in srgb,var(--live) 45%,transparent);
  background:color-mix(in srgb,var(--live) 12%,transparent);
}

/* Главная кнопка страницы: крупнее обычной и со стрелкой — на неё здесь
   приходят нажимать, и она должна выглядеть как единственное действие. */
.lk-big{
  display:inline-flex;align-items:center;gap:.5rem;
  font-size:.875rem;padding:.8rem 1.6rem;border-radius:6px;
  box-shadow:0 10px 26px -12px rgba(232,69,42,.95);
}
.lk-big svg{flex:0 0 auto;transition:transform .16s}
.lk-big:hover svg,.lk-big:focus-visible svg{transform:translateX(3px)}

.lk-sub{
  display:block;margin-top:.7rem;
  font-size:.75rem;color:var(--faint);
}

.lk-two{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(19rem,1fr));margin-top:1rem}

/* Шаги: номер рисуем сами, чтобы он был цветом акцента, а не серым. */
.lk-steps{list-style:none;counter-reset:lk;margin:0;padding:0;display:grid;gap:.55rem}
.lk-steps li{
  counter-increment:lk;position:relative;padding-left:1.9rem;
  font-size:.8125rem;color:var(--muted);line-height:1.5;
}
.lk-steps li::before{
  content:counter(lk);position:absolute;left:0;top:-.05rem;
  width:1.35rem;height:1.35rem;border-radius:50%;
  display:grid;place-items:center;
  font-family:var(--mono);font-size:.6875rem;font-weight:600;
  color:var(--amber);background:var(--amber-dim);
  border:1px solid color-mix(in srgb,var(--amber) 35%,transparent);
}
.lk-steps b{color:var(--text);font-weight:600}

/* Приложения плитками в строку: их пять, и выбирают одну, глядя на все сразу.
   Выглядят кнопками намеренно: раньше это были ровные серые прямоугольники с
   названиями систем, и по ним не понимали, что можно нажать и скачать. Стрелка
   вниз узнаётся без подписи, приподнятый фон говорит «сюда жмут». */
.lk-apps{margin:0;padding:0;list-style:none;display:flex;flex-wrap:wrap;gap:.5rem}
.lk-apps a{
  display:inline-flex;align-items:center;gap:.4rem;
  padding:.5rem .8rem;border:1px solid var(--line);border-radius:6px;
  background:var(--surface-2);color:var(--text);text-decoration:none;
  font-size:.8125rem;font-weight:600;
  transition:border-color .14s,background .14s,transform .14s,box-shadow .14s;
}
.lk-apps a svg{flex:0 0 auto;color:var(--amber);transition:transform .14s}
.lk-apps a:hover,.lk-apps a:focus-visible{
  border-color:var(--amber);background:var(--amber-dim);
  transform:translateY(-1px);box-shadow:0 6px 14px -8px rgba(232,69,42,.7);
}
/* стрелка ныряет вниз — маленький намёк на то, что сейчас произойдёт */
.lk-apps a:hover svg{transform:translateY(2px)}

/* «Без установки» — не скачивание, поэтому и выглядит иначе: пунктир,
   спокойный цвет и значок ухода на другой сайт вместо стрелки вниз. */
.lk-apps a.is-web{
  background:transparent;border-style:dashed;color:var(--muted);font-weight:500;
}
.lk-apps a.is-web svg{color:var(--muted)}
.lk-apps a.is-web:hover,.lk-apps a.is-web:focus-visible{
  color:var(--text);border-color:var(--muted);background:var(--surface);
  box-shadow:none;
}
.lk-apps a.is-web:hover svg{transform:none;color:var(--text)}

/* Пояснение под карточкой. Не .lbl: тот моноширинный и в верхнем регистре —
   для подписи «ШАГ 1» это годится, а предложение целиком в капсе превращается
   в крик и читается вдвое медленнее. */
.lk-note{margin:.7rem 0 0;font-size:.8125rem;color:var(--faint);line-height:1.5}

/* Цвет значка Lolka в подвале и в блоке сообществ. */
.soc-a.is-lolka:hover,.soc-a.is-lolka:focus-visible{--brand:#7C5CFF}

/* Приглашение на странице сообщества — тот же блок, что и «мы не только здесь». */
.lk-invite{margin-bottom:.9rem}
.lk-cta-b{display:flex;align-items:center;justify-content:space-between;gap:1rem 1.5rem;flex-wrap:wrap}
.lk-cta-b b{display:block;font-size:.9375rem}


/* Пояснение под заголовком карточки. Не .lbl: тот моноширинный и в верхнем
   регистре — для подписи «ШАГ 1» это годится, а предложение целиком в капсе
   превращается в крик и читается вдвое медленнее. */
.lk-note{font-size:.8125rem;color:var(--muted);max-width:70ch}

/* ---------- лестница ступеней достижения ---------- */

/* Ступени в ряд, числами. Точки под значком показывают, сколько ступеней
   всего, но не говорят, сколько до следующей и что будет дальше — а именно
   это решает, идти к достижению или нет. */
.achsteps{
  display:flex;flex-wrap:wrap;gap:.25rem;margin:.35rem 0 0;
  font-family:var(--mono);font-size:.625rem;letter-spacing:.02em;
  font-variant-numeric:tabular-nums;
}
.achstep{
  padding:.1rem .3rem;border-radius:3px;border:1px solid transparent;
  color:var(--faint);background:var(--surface-2);white-space:nowrap;
}
/* взятая ступень — цветом достижения, тем же, каким закрашены точки */
.achstep.is-done{color:var(--tier);border-color:color-mix(in srgb,var(--tier) 45%,transparent)}
/* та, к которой идут сейчас: единственная выделенная, чтобы взгляд цеплялся */
.achstep.is-now{color:var(--amber);border-color:var(--amber);background:var(--amber-dim)}

/* ---------- онлайн и адрес на карточке игры ---------- */

/* Живой сервер — зелёным с той же точкой, что в шапке сайта: один и тот же
   признак «здесь сейчас играют» не должен выглядеть по-разному в двух местах. */
.gamecard-flag.is-live{
  display:inline-flex;align-items:center;gap:.3rem;
  color:var(--live);border-color:color-mix(in srgb,var(--live) 40%,var(--line));
  font-variant-numeric:tabular-nums;
}
.gamecard-flag.is-off{color:var(--faint)}

/* Адрес и кнопка рядом: копируют его чаще, чем читают. */
.gamecard-addr{
  display:flex;align-items:center;gap:.4rem;margin-top:.5rem;
  border:1px solid var(--line);border-radius:5px;background:var(--bg);
  padding:.3rem .3rem .3rem .55rem;
}
.gamecard-addr code{
  flex:1 1 auto;min-width:0;overflow-x:auto;white-space:nowrap;
  font-family:var(--mono);font-size:.8125rem;color:var(--text);
  scrollbar-width:none;
}
.gamecard-addr code::-webkit-scrollbar{display:none}
.gamecard-copy{
  flex:0 0 auto;cursor:pointer;font-size:.6875rem;letter-spacing:.04em;
  text-transform:uppercase;font-weight:600;
  padding:.3rem .55rem;border-radius:4px;
  border:1px solid var(--line);background:var(--surface-2);color:var(--muted);
  transition:color .14s,border-color .14s;
}
.gamecard-copy:hover,.gamecard-copy:focus-visible{color:var(--amber);border-color:var(--amber)}

.gamecard-how{margin:.35rem 0 0;font-size:.75rem;color:var(--faint);line-height:1.4}

/* ---------- магазин в шапке ---------- */

/* Не пункт меню, а кнопка. Раньше он был четырнадцатым в прокручиваемой полосе
   и приглушённо-серым — то есть спрятан дважды: за краем экрана и цветом.
   Здесь он вне прокрутки и говорит корзиной, что это покупка.

   Цвет бирюзовый, а не янтарный, и это вынужденный выбор, а не вкус. Янтарь
   занят кнопкой подключения, которая стоит в той же шапке, — две одинаковые
   заливки рядом сливаются в одно пятно. Остальная палитра тоже занята: серый,
   зелёный, синий, фиолетовый и золотой — под редкости предметов, жёлтый — под
   отсчёт до вайпа, зелёный — под индикатор онлайна. Бирюза свободна и вдобавок
   противоположна янтарю на круге, то есть дальше от соседней кнопки уйти
   некуда. */
.shopbtn{
  flex:0 0 auto;display:inline-flex;align-items:center;gap:.4rem;
  font-size:.75rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  padding:.5rem .85rem;border-radius:5px;text-decoration:none;white-space:nowrap;
  color:#04231F;background:linear-gradient(160deg,var(--shop),var(--shop-deep));
  box-shadow:0 4px 14px -6px rgba(45,212,191,.75);
  transition:transform .14s,box-shadow .14s;
}
.shopbtn:hover,.shopbtn:focus-visible{
  transform:translateY(-1px);
  box-shadow:0 9px 22px -8px rgba(45,212,191,.95);
}
.shopbtn:focus-visible{outline:2px solid var(--amber);outline-offset:3px}
.shopbtn-i{flex:0 0 auto;display:block}

/* Уходим на другой сайт — помечаем, как и раньше помечался пункт меню. */
.shopbtn::after{content:"↗";font-size:.75em;opacity:.75;margin-left:.1rem}

/* Медленное дыхание подсветки: в неподвижной шапке взгляд цепляется за
   единственное, что шевелится. Ровно поэтому же оно медленное — быстрое
   мельтешение рядом с текстом мешает читать. */
@keyframes shopglow{
  0%,100%{box-shadow:0 4px 14px -6px rgba(45,212,191,.75)}
  50%{box-shadow:0 4px 20px -4px rgba(45,212,191,.95)}
}
.shopbtn{animation:shopglow 3.2s ease-in-out infinite}
.shopbtn:hover{animation:none}

@media(prefers-reduced-motion:reduce){
  .shopbtn{animation:none}
  .shopbtn:hover,.shopbtn:focus-visible{transform:none}
}

/* На узком экране слово прячем, корзина остаётся: кнопка должна быть видна
   всегда, а места в шапке телефона нет. */
@media(max-width:560px){
  .shopbtn{padding:.5rem .6rem}
  .shopbtn span{display:none}
  .shopbtn::after{margin-left:0}
}

/* ---------- листающийся топ игроков ---------- */

/* Слои лежат стопкой, но высоту контейнеру задаёт показанный: он остаётся в
   потоке, а спрятанные уходят в absolute. Фиксированная высота здесь врала бы —
   в редкой категории может оказаться не пять строк, а две. */
.topswap{position:relative}
.topslide{
  position:absolute;inset:0;opacity:0;visibility:hidden;
  transition:opacity .4s ease,visibility .4s;
}
.topslide.is-on{position:relative;opacity:1;visibility:visible}

/* Название категории — цветом своей категории, тем же, что в витрине наверху:
   один и тот же рейтинг не должен быть красным сверху и синим снизу. */
.topcat{
  display:flex;align-items:center;gap:.35rem;
  /* справа оставлено место под точки: они стоят на этой же строке */
  padding:.5rem 6.5rem .35rem .85rem;
  font-family:var(--mono);font-size:.625rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--top,var(--amber));
  border-bottom:1px solid var(--line-soft);
}
.topcat svg{flex:0 0 auto}

/* Точки — на строке с названием категории, у правого края. Внизу они падали бы
   на последнюю строку рейтинга, а в шапке карточки легли на ссылку «Весь
   рейтинг» и перехватывали нажатие по ней. Здесь справа пусто в любой из
   девяти категорий: названия у всех короткие. */
.topswap-dots{
  position:absolute;top:.6rem;right:.85rem;z-index:2;
  display:flex;align-items:center;gap:.25rem;
}
.topswap-dot{
  width:.35rem;height:.35rem;padding:0;border-radius:50%;cursor:pointer;
  border:1px solid var(--line);background:transparent;
  transition:background .2s,border-color .2s,transform .2s;
}
.topswap-dot:hover{border-color:var(--top)}
.topswap-dot.is-on{background:var(--top);border-color:var(--top);transform:scale(1.35)}
.topswap-dot:focus-visible{outline:2px solid var(--top);outline-offset:2px}

@media(prefers-reduced-motion:reduce){
  .topslide{transition:opacity .01s}
  .topswap-dot{transition:none}
}


/* ---------- страховка для вёрстки внутри статей ---------- */

/* Статьи приезжают со своим оформлением, и написано оно под широкую страницу:
   сетки на двенадцать колонок, ряды, которые не переносятся. На телефоне такой
   блок распирает колонку и его край просто срезается — читатель теряет текст.

   Правила ниже действуют только на узком экране и только внутри статьи. Они
   ничего не навязывают: если статья сама задала max-width или flex-wrap, её
   значение выигрывает по весу селектора и остаётся в силе. */
@media(max-width:700px){
  /* Колонка держит своё содержимое при себе.
     Одна статья с вёрсткой под широкую страницу растягивала весь документ на
     восемьсот пикселей: страница ехала вбок целиком, вместе с шапкой и полосой
     радио. Пусть уж прокручивается сама статья — это видно и понятно, и
     остальной сайт от этого не разъезжается. */
  /* position:relative обязателен вместе с overflow: без него блок, вынутый из
     потока, привязан не к статье, а ко всей странице — и обрезка статьи его не
     держит. Именно так одна статья и растягивала документ. */
  .article{overflow-x:auto;position:relative}

  /* Встроенные стили сборщик не переписывает — он работает с <style>, а тут
     правила написаны прямо в атрибуте элемента. Перебить их можно только так;
     !important здесь не небрежность, а единственный способ. Действует только на
     телефоне и только внутри статьи. */
  .article [style*="absolute"]{
    position:static!important;transform:none!important;width:auto!important;
  }

  .article *{min-width:0;max-width:100%}

  /* ряд, который на широком экране идёт в строку, здесь переносится вместо
     того, чтобы вылезти за край */
  .article *{flex-wrap:wrap}
}

/* Коробка вокруг таблицы, которую в статью кладёт App\Support\Html.
   Прокручивается она, а не страница: таблица уже колонки быть не может, но и
   вести за собой всю вёрстку ей нельзя. */
.article-scroll{max-width:100%;overflow-x:auto}
.article-scroll > table{max-width:none}
