/* campus look: technical solid rail on grey, glass pills over the town, one token set for day and night. */
:root {
  --paper: #f7f7f8;
  --ground: #ededef;
  --ink: #1d1d1f;
  --muted: #6e6e73;
  --smoke: #86868b;
  --pale: #b0b0b5;
  --line: rgba(96, 96, 102, .16);
  --gold: #f2cf00;
  --goldink: #9a7f00;
  --ok: #2f9e63;
  --bad: #e0513c;
  --warn: #d9822b;
  --blue: #1180fa;
  --surface: #c2c5c9;
  --surfaceglass: rgba(255, 255, 255, .62);
  --surfacesolid: rgba(249, 249, 251, .97);
  --surfacetint: rgba(102, 102, 102, .55);
  --surfacetintink: #fff;
  --hover: rgba(0, 0, 0, .05);
  --input: rgba(255, 255, 255, .72);
  --glass: rgba(255, 255, 255, .62);
  --railwidth: 320px;
  --float: 10px;
  --curve: cubic-bezier(.2, .9, .28, 1);
  --shadow: 0 14px 38px rgba(0, 0, 0, .18), 0 2px 8px rgba(0, 0, 0, .08);
  --mono: 11px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
  /* алиасы под имена резерва (ui.css :root, строки 78-165) — те же значения, что campus уже
     держит без дефиса, badges.js их ждёт под этими именами буквально. */
  --surface-ink: var(--ink);
  --surface-muted: var(--muted);
  --surface-grey: var(--smoke);
  --surface-pale: var(--pale);
  --surface-line: var(--line);
  --surface-glass: var(--surfaceglass);
  --surface-solid: var(--surfacesolid);
  --surface-tint: var(--surfacetint);
  --surface-tint-ink: var(--surfacetintink);
  --rail-action: #325cc8;
  --rail-hilite: rgba(0, 0, 0, .075);
  --gc-font: -apple-system, system-ui, "Inter", sans-serif;
}

:root.night {
  --paper: #2e3238;
  --ground: #2f3238;
  --ink: #e6e8ea;
  --muted: #9ba1a8;
  --smoke: #878d94;
  --pale: #5d646c;
  --line: rgba(230, 232, 235, .13);
  --goldink: #e5c400;
  --surface: #363a41;
  --surfaceglass: rgba(45, 49, 55, .6);
  --surfacesolid: rgba(46, 50, 56, .96);
  --surfacetint: rgba(39, 43, 49, .72);
  --surfacetintink: #e6e8ea;
  --rail-action: #8ab0ff;
  --rail-hilite: rgba(255, 255, 255, .09);
  --hover: rgba(255, 255, 255, .06);
  --input: rgba(255, 255, 255, .08);
  --glass: rgba(45, 49, 55, .6);
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--ground);
  color: var(--ink);
  font: 13px/1.4 -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", sans-serif;
  -webkit-font-smoothing: antialiased;
  transition: background .4s ease;
}

[hidden] { display: none !important; }

button {
  font: inherit;
  color: inherit;
  background: var(--input);
  border: .5px solid var(--line);
  border-radius: 999px;
  padding: 5px 11px;
  cursor: pointer;
}
button:hover { background: var(--hover); }
button:disabled { opacity: .45; cursor: default; }
button.primary { background: var(--ink); color: var(--surface); border-color: var(--ink); }
button.primary:hover { opacity: .9; background: var(--ink); }
button.danger { color: var(--bad); border-color: rgba(224, 81, 60, .35); }
button.quiet { background: transparent; border-color: transparent; }
button.wide { width: 100%; }

input, select, textarea {
  font: inherit;
  color: inherit;
  width: 100%;
  background: var(--input);
  border: .5px solid var(--line);
  border-radius: 8px;
  padding: 7px 9px;
  outline: none;
}
input:focus, select:focus, textarea:focus { border-color: rgba(17, 128, 250, .5); box-shadow: 0 0 0 3px rgba(17, 128, 250, .12); }
textarea { resize: vertical; min-height: 40px; }

#stage, #labels { position: fixed; inset: 0; }
#labels { pointer-events: none; z-index: 5; }

/* ── БИРКИ: дословный порт резерва (~/GorskyBackup/campusold20260915/campus/web/badges.js, строки
   64-146, плюс .gc-dossier-close/-head/-name из ui.css — крестик и содержимое карточки-бирки там
   брали вид оттуда). Классы gc-*, размеры, радиусы, тени, letter-spacing — те же; ENTITY_PX/
   TITLE_PX/NOTE_PX старого файла (18/22/14) подставлены как обычные px — там это были литералы
   шаблонной строки, тут те же числа просто написаны. --surface-*/--rail-action/--rail-hilite —
   алиасы на уже читаемые кампусом значения (:root ниже), тем же значением, что в ui.css. */
.gc-badge-layer { position: fixed; inset: 0; z-index: 20; pointer-events: none; contain: layout style; }
.gc-badge {
  position: absolute;
  left: 0;
  top: 0;
  white-space: nowrap;
  display: flex;
  align-items: center;
  pointer-events: none;
  font-family: "SF Pro Display", -apple-system, system-ui, sans-serif;
  font-weight: 500;
  letter-spacing: -.2px;
  will-change: transform;
  line-height: 1;
}
.gc-badge--entity > span:first-of-type { position: relative; top: -1px; }
.gc-badge--entity {
  height: 18px;
  padding: 0 11px;
  border-radius: 9px;
  gap: 5px;
  background: var(--surface-glass, rgba(255, 255, 255, .62));
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  backdrop-filter: blur(8px) saturate(140%);
  color: var(--surface-ink, #1d1d1f);
  font-size: 11px;
  z-index: 1;
  transition: background .4s ease, color .4s ease;
}
.gc-badge--entity.gc-badge--greedy { background: rgba(122, 95, 70, .68); color: #fff; }
.gc-badge--entity.gc-badge--greedy .gc-badge-dot { box-shadow: 0 0 0 1px rgba(255, 255, 255, .4); }
.gc-badge--title {
  height: 22px;
  padding: 0 14px;
  border-radius: 11px;
  background: var(--surface-tint, rgba(102, 102, 102, .55));
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  backdrop-filter: blur(8px) saturate(140%);
  color: var(--surface-tint-ink, #fff);
  font-size: 12.5px;
  z-index: 2;
  transition: background .4s ease, color .4s ease;
}
.gc-badge--note {
  height: 14px;
  padding: 0 10px;
  border-radius: 7px;
  background: var(--surface-tint, rgba(102, 102, 102, .55));
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  backdrop-filter: blur(8px) saturate(140%);
  color: var(--surface-tint-ink, #fff);
  font-size: 10px;
  z-index: 2;
  transition: background .4s ease, color .4s ease;
}
.gc-badge-dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }

/* новый язык поверх старого: подсветка выбранного дома и остров синим — этого в резерве не было
   (кликабельность там жила в раскасте three.js, не в CSS), но кампус умеет и то, и другое; клик
   сам по себе даёт точечный pointer-events на узле в JS (см. clickable() в scene.js), не здесь —
   .gc-badge у резерва специально ловит pointer-events:none, менять это правило незачем. */
.gc-badge--title.on { background: var(--ink); color: var(--surface); box-shadow: 0 0 0 2px var(--gold); }
.gc-badge--title.island { background: rgba(17, 128, 250, .72); color: #fff; }
.pillcount {
  margin-left: 2px;
  padding: 0 5px;
  border-radius: 7px;
  line-height: 14px;
  font-size: 10px;
  font-weight: 700;
  background: var(--bad);
  color: #fff;
}

/* ── КАРТОЧКА-БИРКА: дословный порт .gc-badge-card/-card-in резерва, включая карточную анимацию
   gc-card-in. Содержимое — только .gc-dossier-head/-name (fillCardFallback резерва: без worker'а,
   которого у новых жителей нет, старый код тоже рисовал только имя) плюс .gc-dossier-close с её
   же видом из ui.css. */
.gc-badge-card {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 25;
  width: 312px;
  max-width: calc(100vw - 24px);
  pointer-events: auto;
  cursor: default;
  font-family: var(--gc-font, -apple-system, system-ui, sans-serif);
  color: var(--surface-ink, #1d1d1f);
  font-size: 16px;
  will-change: transform;
  --gc-pad: 16.5px;
  --gc-ink: var(--surface-ink, #1d1d1f);
  --gc-muted: var(--surface-muted, #6e6e73);
  --gc-grey: var(--surface-grey, #86868b);
  --gc-pale: var(--surface-pale, #b0b0b5);
  --gc-line: var(--surface-line, rgba(96, 96, 102, .16));
  --gc-action: var(--rail-action, #325cc8);
  --gc-hilite: var(--rail-hilite, rgba(0, 0, 0, .075));
}
.gc-badge-card * { box-sizing: border-box; }
.gc-badge-card button { font-family: inherit; }
.gc-badge-card-in {
  position: relative;
  max-height: min(62vh, 520px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: var(--surface-solid, rgba(249, 249, 251, .97));
  border-radius: 18px;
  padding: 15px 16.5px 13px;
  box-shadow: 0 14px 38px rgba(0, 0, 0, .18), 0 2px 8px rgba(0, 0, 0, .08);
  scrollbar-width: none;
  transform-origin: 0 50%;
  animation: gc-card-in .24s cubic-bezier(.2, .9, .28, 1);
  transition: background .4s ease;
}
.gc-badge-card-in::-webkit-scrollbar { width: 0; }
@keyframes gc-card-in {
  from { opacity: 0; transform: scale(.55) translateX(-12px); }
  to { opacity: 1; transform: scale(1) translateX(0); }
}
.gc-badge-card .gc-dossier-close { z-index: 2; }
.gc-dossier-close {
  position: absolute;
  top: 10px;
  right: 10px;
  border: none;
  cursor: pointer;
  width: 29px;
  height: 29px;
  border-radius: 9999px;
  background: rgba(120, 120, 128, .12);
  color: var(--gc-ink);
  font-size: 13px;
  font-weight: 400;
  line-height: 1;
  transition: background .16s ease;
}
.gc-dossier-close:hover { background: rgba(120, 120, 128, .20); }
.gc-dossier-head { display: flex; align-items: center; gap: 13px; }
.gc-dossier-name { font-size: 14px; font-weight: 600; letter-spacing: -.24px; line-height: 16px; }
.gc-dossier-path { font-size: 11px; font-weight: 500; letter-spacing: -.1px; line-height: 16px; color: var(--gc-muted); margin-top: 3px; word-break: break-all; font-variant-numeric: tabular-nums; }
/* .gc-tags/.gc-tag/.gc-sec — дословно ui.css (родные классы досье резерва): пастельные ярлыки
   статуса и дома сверху, ниже — секции с заголовком h4 и абзацем. Досье честное: сервер отдаёт
   имя точки входа, куда она достучалась (appeals) и какие файлы за ней стоят (files) — это и есть
   «что делает» и «работает с» нового жителя, ролей/характеров/вердиктов из старого data.js тут нет. */
.gc-tags { display: flex; flex-wrap: wrap; gap: 5px; margin: 12px 0 2px; }
.gc-tag { font-size: 11px; font-weight: 500; letter-spacing: -.1px; border-radius: 9999px; padding: 4px 10px; background: rgba(120, 120, 128, .1); color: var(--gc-ink); }
.gc-tag--gold { background: rgba(240, 201, 106, .32); color: #6f5716; }
.gc-tag--ok { background: rgba(15, 158, 124, .14); color: #0b6f57; }
.gc-tag--bad { background: rgba(255, 111, 94, .15); color: #a4402e; }
.gc-tag--sleep { background: rgba(120, 120, 128, .14); color: var(--gc-muted); }
:root.night .gc-tag--gold { background: rgba(240, 201, 106, .17); color: #ecd08a; }
:root.night .gc-tag--ok { background: rgba(15, 158, 124, .26); color: #3fe0b8; }
:root.night .gc-tag--bad { background: rgba(255, 111, 94, .2); color: #ffa294; }
.gc-sec { margin-top: 12px; padding-top: 11px; border-top: .5px solid var(--gc-line); }
.gc-sec h4 { margin: 0 0 4px; font-size: 13px; font-weight: 500; letter-spacing: -.18px; color: var(--gc-ink); }
.gc-sec p { margin: 0; font-size: 13px; font-weight: 400; letter-spacing: -.224px; line-height: 1.45; color: var(--gc-muted); }
/* words first, code on demand (owner 23.09.2026): principles the resident carries, the code button */
.secnone p { font-style: italic; }
.principleopen { display: block; width: calc(100% + 16px); margin: 0 -8px; padding: 5px 8px; border: 0; border-radius: 8px; background: transparent; text-align: left; font-size: 13px; letter-spacing: -.224px; line-height: 1.35; color: inherit; cursor: pointer; }
.principleopen::before { content: "\265B  "; color: #d9a514; }
.principleopen:hover { background: var(--hover); }
.codefold { margin-top: 14px; }
.codetoggle { padding: 3px 10px; border: 1px solid rgba(120, 120, 128, .25); border-radius: 999px; background: transparent; font-size: 12px; color: var(--smoke); cursor: pointer; }
.codebody { margin-top: 4px; }
.codebody p, .codebody .itemmono { font: var(--mono); word-break: break-all; }
.cardline { padding: 6px 0; border-top: 1px solid var(--line); }
.principle + .principle { margin-top: 22px; padding-top: 4px; border-top: 1px solid var(--line); }
.principletitle { margin: 12px 0 4px; font-size: 16px; }

#rail {
  position: fixed;
  top: max(var(--float), env(safe-area-inset-top, 0px));
  left: max(var(--float), env(safe-area-inset-left, 0px));
  bottom: max(var(--float), env(safe-area-inset-bottom, 0px));
  width: var(--railwidth);
  z-index: 20;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: 14px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
  transition: transform .55s var(--curve), background .4s ease;
}
#rail::-webkit-scrollbar { width: 0; }
#rail > * { flex-shrink: 0; }
body.railaway #rail { transform: translateX(calc(-100% - var(--float) * 2)); }
.railbrand { display: flex; align-items: center; gap: 12px; padding: 22px 18px 6px; }
.brandmark {
  width: 62px;
  height: 27px;
  background: var(--smoke);
  -webkit-mask: url("brand.svg") no-repeat left center / contain;
  mask: url("brand.svg") no-repeat left center / contain;
}
#brand { font-size: 11px; font-weight: 600; letter-spacing: .3px; text-transform: uppercase; color: var(--smoke); }
.railhead {
  padding: 20px 18px 8px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .3px;
  text-transform: uppercase;
  color: var(--smoke);
}
.railspacer { flex: 1 1 auto; min-height: 12px; }

#stats { display: flex; flex-direction: column; padding: 0 18px 0 20px; }
.stat { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; height: 26px; line-height: 26px; color: var(--ink); white-space: nowrap; }
.statlabel { overflow: hidden; text-overflow: ellipsis; color: var(--muted); }
.stat b { font-weight: 600; font-variant-numeric: tabular-nums; }
.stat.alert b { color: var(--bad); }
.stat.gold b { color: var(--goldink); }
.stat.clickable { cursor: pointer; }
.stat.clickable:hover .statlabel { color: var(--ink); }

#dock { display: flex; flex-direction: column; }
.fold { display: flex; flex-direction: column; }
.foldhead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  height: 34px;
  padding: 0 18px 0 20px;
  border: 0;
  border-radius: 0;
  background: transparent;
  font-size: 13px;
  letter-spacing: -.224px;
  text-align: left;
}
.foldhead:hover { background: var(--hover); }
.fold.open .foldhead { box-shadow: inset 2px 0 0 var(--ink); font-weight: 600; }
.foldbadge {
  min-width: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--surface);
  font-size: 11px;
  line-height: 18px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.foldbadge.alert { background: var(--bad); color: #fff; }
.foldbody { padding: 2px 18px 14px 20px; border-bottom: .5px solid var(--line); }

#chronicle { display: flex; flex-direction: column; gap: 4px; padding: 0 10px; }
.chronicleempty { padding: 0 8px; color: var(--pale); }
.chronicleitem { padding: 8px 10px; border-radius: 10px; background: var(--hover); }
.chronicleitem.gold { box-shadow: inset 2px 0 0 var(--gold); }
.chronicleitem.bad { box-shadow: inset 2px 0 0 var(--bad); }
.chronicleline { display: flex; align-items: flex-start; gap: 8px; }
.chronicletext { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.chronicletime { flex: none; color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.chroniclesource { margin-top: 2px; color: var(--pale); font-size: 11px; }

#legend { display: flex; flex-direction: column; gap: 4px; padding: 12px 18px; color: var(--muted); font-size: 11px; border-top: .5px solid var(--line); }
.swatch { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 7px; vertical-align: -1px; box-shadow: inset 0 0 0 .5px rgba(0, 0, 0, .25); }
.swatch.diamond { transform: rotate(45deg) scale(.8); }
.swatch.dot { border-radius: 50%; }
.swatch.line { height: 3px; vertical-align: 2px; box-shadow: none; }
.swatch.none { box-shadow: none; }

.railuser { display: flex; align-items: center; gap: 10px; padding: 10px 18px; border-top: .5px solid var(--line); }
.useravatar { position: relative; width: 26px; height: 26px; border-radius: 50%; background: var(--hover); flex: none; }
.userlive { position: absolute; right: -1px; bottom: -1px; width: 8px; height: 8px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 0 2px var(--surface); }
.username { flex: 1; min-width: 0; font-size: 12px; font-weight: 500; }

#railtab {
  position: fixed;
  left: calc(var(--railwidth) + var(--float));
  top: 50%;
  z-index: 19;
  width: 22px;
  height: 64px;
  padding: 0;
  border: 0;
  border-radius: 0 8px 8px 0;
  background: var(--surface);
  color: var(--smoke);
  display: flex;
  align-items: center;
  justify-content: center;
  transform: translateY(-50%);
  transition: left .55s var(--curve), background .4s ease;
}
#railtab:hover { color: var(--ink); }
#railtab svg { width: 15px; height: 15px; transition: transform .55s var(--curve); }
body.railaway #railtab { left: 0; }
body.railaway #railtab svg { transform: rotate(180deg); }

#tools { position: fixed; top: 12px; right: 12px; z-index: 18; display: flex; gap: 6px; }
.segment {
  display: flex;
  gap: 2px;
  padding: 3px;
  border-radius: 999px;
  background: var(--surfaceglass);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  backdrop-filter: blur(8px) saturate(140%);
  transition: background .4s ease;
}
.segment button {
  height: 27px;
  min-width: 27px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  color: var(--muted);
}
.segment button:hover { background: rgba(120, 120, 128, .14); }
.segment button svg { width: 16px; height: 16px; }
.segment button.on, .segment button.on:hover { background: var(--ink); color: var(--surface); }
.segment button.auto { padding: 0 9px; font-size: 9px; font-weight: 600; letter-spacing: .3px; text-transform: uppercase; }

#card, #sheet, #loginform {
  background: var(--surfacesolid);
  box-shadow: var(--shadow);
  transition: background .4s ease;
}
#card, #sheet {
  position: fixed;
  top: 52px;
  bottom: 12px;
  right: 12px;
  z-index: 21;
  overflow: auto;
  padding: 16px 18px;
  border-radius: 18px;
  scrollbar-width: none;
}
#card { width: min(360px, calc(100vw - 24px)); animation: cardin .24s var(--curve); }
#sheet { width: min(600px, calc(100vw - var(--railwidth) - 44px)); display: flex; flex-direction: column; overflow: hidden; }
@keyframes cardin { from { opacity: 0; transform: translateX(14px) scale(.98); } to { opacity: 1; transform: none; } }
#sheetbody { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; overflow: auto; margin-right: -8px; padding-right: 8px; }
.closer { position: absolute; top: 10px; right: 10px; width: 26px; height: 26px; padding: 0; z-index: 1; border: 0; background: var(--hover); color: var(--muted); }
.sheethead { padding-right: 34px; }

.cardtitle { font-size: 20px; font-weight: 700; margin: 0 0 2px; word-break: break-word; }
.cardkind { color: var(--smoke); margin-bottom: 14px; }
.cardrow { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; border-top: 1px solid var(--line); }
.cardrow span:first-child { color: var(--smoke); }
.cardrow span:last-child { text-align: right; word-break: break-word; }
.cardsection { margin: 16px 0 6px; font-weight: 600; }
.foldbody > .cardsection:first-child, .foldbody > .muted:first-child { margin-top: 4px; }
.subsection { margin: 10px 0 4px; color: var(--smoke); font-weight: 600; }
.alerttext { color: var(--bad); }
.chips { display: flex; flex-wrap: wrap; gap: 5px; }
.chip { padding: 2px 8px; border-radius: 999px; border: 1px solid var(--line); background: #fff; font-size: 12px; white-space: nowrap; }
.chip.yes { border-color: rgba(47, 158, 99, .35); color: var(--ok); }
.chip.no { color: var(--smoke); }
.chip.bad { border-color: rgba(224, 81, 60, .35); color: var(--bad); }
.chip.warn { border-color: rgba(217, 130, 43, .4); color: var(--warn); }
.chip.blue { border-color: rgba(17, 128, 250, .35); color: var(--blue); }
.chip.gold { border-color: rgba(242, 207, 0, .7); color: var(--goldink); background: #fffbe0; }
.violation { font: var(--mono); word-break: break-all; padding: 3px 0; border-top: 1px solid var(--line); }
.violation em { color: var(--bad); font-style: normal; }
.muted { color: var(--smoke); }
.empty { padding: 6px 0; }
.lead { margin: 4px 0 8px; }
.failure { color: var(--bad); padding: 6px 0; word-break: break-word; }
.namesrow { display: flex; justify-content: space-between; padding: 6px 0; border-top: 1px solid var(--line); cursor: pointer; }
.namesrow:hover { color: var(--blue); }

.item, .episode { padding: 8px 0; border-top: 1px solid var(--line); }
.item.clickable, .itemlist .item { cursor: pointer; }
.item.clickable:hover .itemtitle, .itemlist .item:hover .itemtitle { color: var(--blue); }
.itemtop { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.itemtitle { font-weight: 600; word-break: break-word; }
.itemmeta { color: var(--smoke); font-size: 12px; margin-top: 2px; }
.itemtext { margin-top: 3px; color: #3a3a3c; word-break: break-word; }
.itemmono { font: var(--mono); word-break: break-all; }
.itemerror { margin-top: 3px; color: var(--bad); font-size: 12px; word-break: break-word; }
.episode.stalled .itemmono { color: var(--bad); }

.buttons { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: 8px; }
.buttons.spaced { margin-top: 12px; }
.formbox { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; padding: 10px; border-radius: 12px; background: rgba(255, 255, 255, .55); border: 1px solid var(--line); }
.formslot { margin-top: 4px; }
.formnote { min-height: 0; font-size: 12px; }
.pickers { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.field { display: flex; flex-direction: column; gap: 3px; }
.fieldlabel { color: var(--smoke); font-size: 12px; }
.consent { display: flex; align-items: flex-start; gap: 7px; font-size: 12px; cursor: pointer; }
.consent input { width: auto; margin: 2px 0 0; }
.banner { margin: 10px 0 4px; padding: 7px 10px; border-radius: 10px; font-weight: 600; }
.banner.good { background: rgba(47, 158, 99, .12); color: var(--ok); }
.banner.bad { background: rgba(224, 81, 60, .1); color: var(--bad); }

.markdown { word-break: break-word; }
.markdown .mdheading { margin: 14px 0 4px; }
.markdown h3.mdheading { font-size: 16px; }
.markdown h4.mdheading { font-size: 14px; }
.markdown h5.mdheading, .markdown h6.mdheading { font-size: 13px; }
.mdtext { margin: 6px 0; }
.mdlist { margin: 6px 0; padding-left: 20px; }
.mdlist li { margin: 2px 0; }
.mdcode, .tooltext { font: var(--mono); background: rgba(0, 0, 0, .04); border-radius: 8px; padding: 8px 10px; overflow-x: auto; white-space: pre; margin: 6px 0; }
.mdtable { font: var(--mono); white-space: pre; overflow-x: auto; }
.mdquote { margin: 6px 0; padding-left: 10px; border-left: 3px solid var(--line); color: #3a3a3c; }
.markdown code { font: var(--mono); background: rgba(0, 0, 0, .05); border-radius: 4px; padding: 0 3px; }
.objectrows { display: flex; flex-direction: column; gap: 2px; }
.objectrow { display: flex; gap: 8px; }
.objectkey { color: var(--smoke); min-width: 70px; }

.task { margin-top: 10px; }
.task summary { cursor: pointer; color: var(--smoke); }
.messages { flex: 1 1 auto; min-height: 120px; overflow: auto; margin: 10px -4px 0; padding: 4px; display: flex; flex-direction: column; gap: 8px; }
.message { max-width: 92%; padding: 8px 11px; border-radius: 12px; background: #fff; border: 1px solid var(--line); word-break: break-word; }
.message.user { align-self: flex-end; background: #e8f1fe; border-color: rgba(17, 128, 250, .2); }
.message.agent { align-self: flex-start; }
.message.tool { align-self: stretch; max-width: none; background: transparent; padding: 4px 8px; }
.message.tool summary { cursor: pointer; color: var(--smoke); font: var(--mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.message .markdown > :first-child { margin-top: 0; }
.message .markdown > :last-child { margin-bottom: 0; }
.messagerole { color: var(--smoke); font-size: 11px; margin-bottom: 2px; }
.messagetext { white-space: pre-wrap; }
.compose { display: flex; gap: 8px; align-items: flex-end; margin-top: 10px; }
.compose textarea { flex: 1 1 auto; }

#status {
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  color: var(--smoke);
  font-size: 15px;
  pointer-events: none;
}

/* ── ВХОД: дословный порт ФИНАЛЬНОГО резерва (~/GorskyBackup/campusold20260915/campus/web/
   index.html, стили строк 86-291 + разметка #gateov 453-505) — облако ПОВЕРХ настоящего города,
   не отдельная страница (тот двухстраничный «бесшовный вход» умер, см. engine.js:320-324). Классы
   gv-*, размеры, цвета, тайминги — те же; z-index подобран под уже занятые кампусом (#rail:20,
   #card/#sheet:21) — у резерва своего стека там не было. НЕ ПЕРЕНЕСЕНО: мобильная раскладка
   @media(pointer:coarse) карточки и полей — кампус десктоп-only (campus/CLAUDE.md). */

/* html.gate: единственная метка правит и до входа, и во время него. Ставится синхронно в <head>
   index.html — до первой отрисовки, поэтому ничего из перечисленного тут не мелькает ни на один
   кадр. Пилюли прячутся ПРАВИЛОМ (не таймингом JS) — ровно как в резерве. Рельеф прячется тем же
   способом (visibility, не display) — сам слайд «рельеф выезжает после кино» делает JS отдельно,
   через уже существующий body.railaway (см. main.js), а не через html.gate. */
html.gate .gc-badge-layer { display: none !important; }
html.gate #tools, html.gate #rail, html.gate #railtab, html.gate #card, html.gate #sheet { visibility: hidden; }

/* #boot: логотип и полоса поверх настоящего мира — своей подложки нет вовсе (владелец: «серую
   подложку не возвращать ни под каким предлогом»), город виден с первого кадра. Собралось — уходит
   ТОЛЬКО полоса (.ready); логотип остаётся висеть, снимает его main.js классом .gone — по клику
   фона либо сразу, если кука уже отвечает за вход. */
#boot {
  position: fixed;
  inset: 0;
  z-index: 31;
  pointer-events: none;
  background: none;
  color: #1d1d1f; /* the logo is inline svg painted with currentColor, as in the backup: brand.svg carries its own grey and rendered lighter */
}
#boot svg { width: 96px; height: auto; display: block; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
#boot .track {
  position: absolute;
  top: calc(50% + 52px);
  left: 50%;
  transform: translateX(-50%);
  width: 150px;
  height: 4.5px;
  border-radius: 9999px;
  background: rgba(0, 0, 0, .1);
  box-shadow: inset 0 0 0 .5px rgba(0, 0, 0, .14);
  overflow: hidden;
}
#boot .fill { position: absolute; inset: 0; border-radius: 9999px; transform-origin: left; transform: scaleX(0); background: #1d1d1f; }
#boot .berr {
  position: absolute;
  top: calc(50% + 72px);
  left: 50%;
  transform: translateX(-50%);
  min-height: 16px;
  font-size: 12px;
  color: #86868b;
  letter-spacing: -.2px;
  max-width: 70vw;
  text-align: center;
}
#boot.ready .track, #boot.ready .berr { opacity: 0; transition: opacity .45s ease; }
#boot.gone { opacity: 0; transition: opacity .3s ease; }

/* #gateov: облако входа — форма стоит статично в разметке (как и в резерве), gate.js только
   вешает поведение и переключает классы. */
#gateov { position: fixed; inset: 0; z-index: 30; display: none; }
#gateov.on { display: flex; align-items: center; justify-content: center; }
#gateov .gv-card {
  position: relative;
  width: min(520px, calc(100vw - 44px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)));
  box-sizing: border-box;
  border-radius: 32px;
  padding: 36px;
  overflow: hidden;
  opacity: 0;
  transition: opacity .5s ease;
  pointer-events: none;
}
#gateov .gv-card.on { opacity: 1; pointer-events: auto; }
#gateov .gv-base { position: absolute; inset: 0; border-radius: inherit; background: #e6e6ea; }
#gateov .gv-veil { position: absolute; inset: 0; border-radius: inherit; background: rgba(255, 255, 255, 1); opacity: .7; }
#gateov .gv-card > *:not(.gv-base):not(.gv-veil) { position: relative; z-index: 1; }
#gateov .gv-title { display: block; line-height: 20px; font-size: 15px; font-weight: 600; letter-spacing: -.3px; color: #1d1d1f; }
/* Рассказ владельца: в покое ровно ДВЕ строки (line-height 16, max-height 32 — целые px нарочно,
   дробные ложились бы между пикселями и подрагивали на переходе), хвост тает градиентом ::after;
   под курсором разворачивается до фактической высоты текста (см. gate.js wirehint — считает
   scrollHeight, не едет вслепую к фиксированным 52vh). */
#gateov .gv-hintwrap { position: relative; margin-top: 3px; }
#gateov .gv-hint {
  overflow: hidden;
  font-size: 11px;
  letter-spacing: -.09px;
  line-height: 16px;
  color: #98989e;
  max-height: 32px;
  transition: max-height .55s cubic-bezier(.2, .9, .28, 1), color .35s ease;
  cursor: default;
}
#gateov .gv-hintwrap.gv-open .gv-hint { color: #6e6e73; }
#gateov .gv-hint::-webkit-scrollbar { width: 0; }
#gateov .gv-hintwrap::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 18px;
  pointer-events: none;
  background: linear-gradient(180deg, rgba(247, 247, 249, 0), #f7f7f9);
  opacity: 1;
  transition: opacity .4s ease;
}
#gateov .gv-hintwrap.gv-open::after { opacity: 0; }
#gateov .gv-hint p { margin: 0 0 8px; }
#gateov .gv-hint p:last-child { margin-bottom: 0; }
#gateov .gv-rule { height: .5px; background: rgba(96, 96, 102, .16); margin-top: 26px; }
/* Строка — целиком поле ввода: клик до черты обязан ставить курсор (gate.js wirerows). */
#gateov .gv-row { display: flex; align-items: stretch; gap: 12px; padding: 0; cursor: text; }
#gateov .gv-row + .gv-row { border-top: .5px solid rgba(96, 96, 102, .16); }
#gateov .gv-row label { flex: none; width: 64px; padding: 14px 0; font-size: 11px; letter-spacing: -.09px; color: #9a9a9f; cursor: text; display: flex; align-items: center; }
/* the row's 14px belong to the field itself: the input box spans the whole row after the rule, not a 15px strip in the middle */
#gateov .gv-row input { flex: 1; min-width: 0; border: none; background: none; height: auto; align-self: stretch; outline: none; padding: 14px 0; line-height: 15px; font-family: inherit; font-size: 13px; font-weight: 500; letter-spacing: -.09px; color: #1d1d1f; border-radius: 0; }
/* the campus-wide blue focus ring (input:focus above) must not reach the gate: the backup had no ring at all */
#gateov input:focus, #gateov input:focus-visible { border: none; box-shadow: none; outline: none; }
#gateov .gv-row input::placeholder { color: #c6c6cb; font-weight: 400; font-size: 11px; letter-spacing: -.09px; }
/* НИКАКИХ ПОДЛОЖЕК АВТОЗАПОЛНЕНИЯ — ни жёлтой, ни белой заплаты вместо неё: заливку WebKit
   откладываем практически бесконечным переходом, поле остаётся прозрачным. Это и снимает
   «предложения из ключа» браузера, которые били по глазам поверх листа. */
#gateov .gv-row input:-webkit-autofill,
#gateov .gv-row input:-webkit-autofill:hover,
#gateov .gv-row input:-webkit-autofill:focus,
#gateov .gv-row input:autofill {
  transition: background-color 100000s ease-in-out 0s;
  -webkit-text-fill-color: #1d1d1f;
  caret-color: #1d1d1f;
}
#gateov .gv-action { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-top: 34.5px; }
#gateov .gv-go { padding: 0; border: none; background: none; cursor: pointer; font-family: inherit; font-size: 13.5px; font-weight: 600; letter-spacing: -.2px; color: #1d1d1f; }
#gateov .gv-side { font-size: 11px; letter-spacing: -.09px; color: #98989e; min-height: 15px; text-align: right; }
#gateov .gv-err { color: #e0513c; opacity: 0; transition: opacity .2s; }
#gateov .gv-err.on { opacity: 1; }
/* шаг кода: 6 ячеек без каретки, скрытый input поверх, ввод сам — кнопки на этом шаге нет. */
#gateov .gv-otp { position: relative; display: none; justify-content: center; gap: 10px; margin-top: 26px; }
#gateov .gv-otp.on { display: flex; }
#gateov .gv-otp input {
  position: absolute;
  inset: 0;
  opacity: .011;
  border: none;
  outline: none;
  background: none;
  color: transparent;
  caret-color: transparent;
  -webkit-text-fill-color: transparent;
  font-size: 16px;
  letter-spacing: 32px;
}
#gateov .gv-cell {
  width: 44px;
  height: 52px;
  border-radius: 12px;
  background: rgba(255, 255, 255, .9);
  box-shadow: inset 0 0 0 .5px rgba(96, 96, 102, .22);
  display: grid;
  place-items: center;
  font-size: 21px;
  font-weight: 600;
  color: #1d1d1f;
  font-variant-numeric: tabular-nums;
}
#gateov .gv-cell.hot { box-shadow: inset 0 0 0 1.5px rgba(29, 29, 31, .55); }
#gateov .gv-otp.bad .gv-cell { color: #e0513c; box-shadow: inset 0 0 0 1px rgba(224, 81, 60, .6); }
#gateov .gv-otp.busy .gv-cell { opacity: .55; }
/* gv-shake: облако флекс-центровано родителем (#gateov.on), не translate(-50%,-50%) само по
   себе — поэтому дрожь простым translateX, без сдвига центровки (резервный keyframe дрожал именно
   вокруг такого центрирования, у нас его на самой .gv-card нет). */
#gateov .gv-card.gv-shake { animation: gvshake .4s; }
@keyframes gvshake { 20%, 60% { transform: translateX(-7px); } 40%, 80% { transform: translateX(7px); } }
@media (prefers-reduced-motion: reduce) {
  #boot, #gateov, #gateov * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}


.chip { background: var(--input); }
.message { background: var(--input); }
:root.night .message.user { background: rgba(17, 128, 250, .16); }
:root.night .chip.gold { background: rgba(242, 207, 0, .12); }
.formbox { background: var(--hover); }

@media (max-width: 1100px) {
  #sheet { width: min(600px, calc(100vw - 24px)); }
  body.sheeton #rail { visibility: hidden; }
}

@media (max-width: 640px) {
  :root { --railwidth: calc(100vw - 42px); }
  #card, #sheet { top: auto; bottom: 12px; left: 12px; right: 12px; width: auto; height: 72vh; }
  body.cardon #rail, body.sheeton #rail { visibility: hidden; }
  .pickers { grid-template-columns: 1fr; }
}
#cardbody > .chips { margin: 8px 0 2px; }
#card .closer { position: sticky; top: 0; float: right; margin: -6px -8px 0 0; }

/* Превью снимков, стоящих в дверях дома: плитки по 320 px с часом под каждой (владелец
   21.09.2026). Картинку отдаёт сам кампус уменьшенной, поэтому тут только раскладка. */
.shotgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: 8px;
  margin: 8px 0 4px;
}
.shot {
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-solid, rgba(249, 249, 251, .97));
  box-shadow: 0 1px 4px rgba(0, 0, 0, .12);
}
.shot img {
  display: block;
  width: 100%;
  height: 104px;
  object-fit: cover;
}
.shot .shotat {
  font-size: 12px;
  text-align: center;
  padding: 3px 0 4px;
  opacity: .75;
}
.shotblank {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 104px;
  text-align: center;
}

/* Действия над снимком в коробке: варианты приёма и стирание копии. */
.shotacts { display: flex; flex-wrap: wrap; gap: 4px; padding: 0 4px 5px; }
.shotact {
  font: inherit;
  font-size: 11px;
  line-height: 1.25;
  padding: 3px 7px;
  border: 0;
  border-radius: 7px;
  background: var(--rail-action, rgba(0, 0, 0, .06));
  color: inherit;
  cursor: pointer;
  text-align: left;
}
.shotact:hover { background: var(--rail-hilite, rgba(0, 0, 0, .1)); }
.shotact[disabled] { opacity: .5; cursor: default; }
.shotact--warn { background: rgba(214, 69, 65, .18); }
.shotchoices { display: flex; flex-direction: column; gap: 3px; width: 100%; }
