/* ══════════════════════════════════════════════════════════════════════
   BASE — тема-независимая структура/анимации.
   Все цвета — через CSS-переменные, значения задаёт themes/<name>/theme.css.
   Атмосферный фон (body::before/::after) тоже определяется темой:
   у каждой темы свой "воздух" (ночной город / вокзальный туман / т.д.)
   ══════════════════════════════════════════════════════════════════════ */
:root{
  --bg:#0a0d14;
  --accent:#e8b33c;
  --ink:#f2ede3;
  --muted:#8a93a6;
  --line:rgba(232,179,60,.22);
  --card:rgba(255,255,255,.035);
  --card-on:rgba(232,179,60,.10);
  --stamp:#b04a3a;
  --perf:#c9bfa9;
  --ticket-bg-1:#fdfaf3;
  --ticket-bg-2:#f0e9db;
  --ticket-head-bg:#12182a;
  --ticket-ink:#1a1a1a;
  --ticket-muted:#8c8272;
  /* акцент в полупрозрачных подложках: своё значение у каждой темы,
     иначе на ярких темах проступает золото авиабилета */
  --glow:rgba(232,179,60,.06);
  --glow-hover:rgba(232,179,60,.05);
  --dash:rgba(232,179,60,.38);
  --final-ink:#d9d3c7;
  --radius:14px;
  --ticket-radius:16px;
  --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  --display:var(--sans);
}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
/* overflow-x и на html, не только на body: пока тема не применилась, текст
   набран запасной гарнитурой и бывает шире экрана — на 320px это давало
   короткий горизонтальный сдвиг на первом экране. Ни одного position:sticky
   в проекте нет, так что побочных эффектов у этого нет */
html{background:var(--bg);overflow-x:hidden}
body{
  background:var(--bg);
  color:var(--ink);font-family:var(--sans);min-height:100dvh;overflow-x:hidden;
}

/* minmax(0,1fr), а не 1fr по умолчанию: иначе колонка грида раздувается до
   min-content самого широкого содержимого (длинное слово в подписи карточки),
   .screen раздувается вместе с ней, и вся страница едет вбок на телефоне */
.stage{position:relative;z-index:1;min-height:100dvh;display:grid;grid-template-columns:minmax(0,1fr);place-items:start center;padding:0 20px 56px}
.screen{
  grid-area:1/1;width:100%;max-width:520px;padding-top:clamp(44px,9vh,88px);
  opacity:0;transform:translateY(28px);pointer-events:none;display:none;
  transition:opacity .5s ease,transform .55s cubic-bezier(.22,1,.36,1);
}
.screen.on,.screen.out{display:block}
.screen.on{opacity:1;transform:none;pointer-events:auto}
.screen.out{opacity:0;transform:translateY(-24px)}

.progress{display:flex;gap:6px;margin-bottom:32px}
.progress i{flex:1;height:2px;background:rgba(255,255,255,.10);border-radius:2px;transition:background .4s ease}
.progress i.done{background:var(--accent)}

.kicker{font-family:var(--mono);font-size:11px;letter-spacing:.26em;color:var(--accent);text-transform:uppercase;margin-bottom:14px}
h1{font-family:var(--display);font-size:clamp(27px,7vw,40px);line-height:1.1;font-weight:600;letter-spacing:-.02em;margin-bottom:12px}
h2{font-family:var(--display);font-size:clamp(23px,6vw,32px);line-height:1.15;font-weight:600;letter-spacing:-.02em;margin-bottom:8px}
.sub{color:var(--muted);font-size:15px;line-height:1.55;margin-bottom:26px}

.board{
  border:1px solid var(--line);border-radius:14px;padding:16px;margin-bottom:28px;
  background:linear-gradient(180deg,var(--glow),transparent);
}
.board-row{display:flex;justify-content:space-between;gap:12px;font-family:var(--mono);font-size:11.5px;padding:5px 0}
.board-row span:first-child{color:var(--muted);letter-spacing:.14em}
.board-row span:last-child{color:var(--accent);letter-spacing:.09em;text-align:right}

.pin input{
  width:100%;background:var(--card);border:1px solid rgba(255,255,255,.12);border-radius:12px;
  padding:16px 18px;color:var(--ink);font-family:var(--mono);font-size:17px;letter-spacing:.16em;
  outline:none;transition:border-color .25s ease,background .25s ease;text-align:center;
}
.pin input:focus{border-color:var(--accent);background:var(--card-on)}
.pin input::placeholder{color:#4d5566;letter-spacing:.16em}
.shake{animation:shake .4s}
@keyframes shake{20%,60%{transform:translateX(-7px)}40%,80%{transform:translateX(7px)}}
.hint{font-size:13.5px;color:var(--muted);line-height:1.55}
.hint b{color:var(--accent);font-weight:500}
.err{color:#e57373;font-size:13px;min-height:19px;margin:10px 0}

.grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:26px}
.opt{
  position:relative;background:var(--card);border:1px solid rgba(255,255,255,.09);
  border-radius:14px;padding:15px 14px;cursor:pointer;text-align:left;color:var(--ink);
  font-size:15px;font-family:inherit;line-height:1.35;overflow-wrap:break-word;
  transition:border-color .2s ease,background .2s ease,transform .12s ease;
  opacity:0;transform:translateY(14px);animation:pop .45s cubic-bezier(.22,1,.36,1) forwards;
}
@keyframes pop{to{opacity:1;transform:none}}
.opt:active{transform:scale(.975)}
.opt.sel{border-color:var(--accent);background:var(--card-on)}
.opt .emoji{display:block;font-size:22px;margin-bottom:7px;line-height:1}
.opt .ttl{display:block;padding-right:20px}
.opt .meta{display:block;font-size:12px;color:var(--muted);margin-top:4px}
.badge{
  position:absolute;top:10px;right:10px;width:22px;height:22px;border-radius:50%;
  background:var(--accent);color:var(--bg);font-family:var(--mono);font-size:11px;font-weight:700;
  display:grid;place-items:center;opacity:0;transform:scale(.5);transition:.22s cubic-bezier(.22,1,.36,1);
}
.opt.sel .badge{opacity:1;transform:none}

.btn{
  width:100%;padding:17px;border:none;border-radius:13px;background:var(--accent);color:var(--bg);
  font-family:var(--mono);font-size:13px;font-weight:700;letter-spacing:.15em;text-transform:uppercase;
  cursor:pointer;transition:opacity .25s ease,transform .12s ease;
}
.btn:active{transform:scale(.985)}
.btn[disabled]{opacity:.28;cursor:not-allowed}
.btn.ghost{background:transparent;border:1px solid var(--line);color:var(--accent)}
.back{
  display:block;width:100%;margin-top:10px;padding:15px 14px;cursor:pointer;
  background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.13);border-radius:13px;
  color:var(--muted);font-family:var(--mono);font-size:12px;font-weight:600;
  letter-spacing:.13em;text-transform:uppercase;text-align:center;
  transition:border-color .2s ease,color .2s ease,background .2s ease,transform .12s ease;
}
.back:active{transform:scale(.985)}
.back:hover{border-color:var(--line);color:var(--accent);background:var(--glow-hover)}

/* ---------- дни ---------- */
.days{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:10px}
.opendate{
  display:block;width:100%;margin:0 0 26px;padding:14px 16px;text-align:left;cursor:pointer;
  background:transparent;border:1.5px dashed var(--dash);border-radius:var(--radius);
  color:var(--ink);font-family:inherit;transition:border-color .2s ease,background .2s ease,transform .12s ease;
}
.opendate:active{transform:scale(.985)}
.opendate.sel{border-style:solid;border-color:var(--accent);background:var(--card-on)}
.od-t{display:block;font-family:var(--mono);font-size:11.5px;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:var(--accent);margin-bottom:5px}
.od-m{display:block;font-size:13.5px;line-height:1.45;color:var(--muted);transition:color .2s ease}
.opendate.sel .od-m{color:var(--ink)}
.day{
  background:var(--card);border:1px solid rgba(255,255,255,.09);border-radius:12px;
  padding:12px 6px;text-align:center;cursor:pointer;color:var(--ink);font-family:inherit;
  transition:border-color .2s ease,background .2s ease,transform .12s ease;
  opacity:0;transform:translateY(14px);animation:pop .45s cubic-bezier(.22,1,.36,1) forwards;
}
.day:active{transform:scale(.97)}
.day.sel{border-color:var(--accent);background:var(--card-on)}
.day .w{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.14em;color:var(--muted);transition:color .2s}
.day .n{display:block;font-size:23px;font-weight:600;line-height:1.15;margin:3px 0}
.day .mo{display:block;font-family:var(--mono);font-size:9.5px;letter-spacing:.14em;color:var(--muted);transition:color .2s}
.day.sel .w,.day.sel .mo{color:var(--accent)}

/* ---------- билет ---------- */
/* forces a proper compositing layer — иначе в части браузеров overflow:hidden
   не обрезает повёрнутый (transform) дочерний элемент типа .stamp */
.ticket{position:relative;transform:translateZ(0)}
.stamp{
  /* поворот вокруг правого верхнего угла, а не центра: при повороте от
     центра этот угол поднимался на ~19px выше своей строки (110px ширины
     под 10°) и наезжал на тёмную шапку бланка. С этой точкой отсчёта штамп
     целиком остаётся ниже отведённого ему top и не выходит за правое поле */
  position:absolute;right:14px;top:68px;z-index:2;
  transform:rotate(-10deg);transform-origin:100% 0;
  /* фиксированная ширина + перенос строк — штамп не может стать шире карточки,
     сколько бы символов ни было в тексте темы ("AT YOUR LEISURE" и т.п.) */
  width:110px;max-width:calc(100% - 28px);box-sizing:border-box;
  border:1.5px solid var(--stamp);border-radius:4px;padding:4px 6px;color:var(--stamp);
  font-family:var(--mono);font-size:8.5px;font-weight:700;letter-spacing:.09em;
  text-align:center;line-height:1.3;opacity:.72;pointer-events:none;
}
.stamp small{display:block;margin-top:2px;font-size:6.5px;letter-spacing:.05em}
.ticket{
  background:linear-gradient(160deg,var(--ticket-bg-1),var(--ticket-bg-2));color:var(--ticket-ink);border-radius:var(--ticket-radius);
  overflow:hidden;box-shadow:0 24px 60px rgba(0,0,0,.55);margin-bottom:20px;
  animation:issue .85s cubic-bezier(.22,1,.36,1) both;
}
@keyframes issue{from{opacity:0;transform:translateY(40px) rotate(-1.5deg)}to{opacity:1;transform:none}}
.t-head{background:var(--ticket-head-bg);color:var(--accent);padding:14px 18px;display:flex;justify-content:space-between;align-items:baseline;font-family:var(--mono)}
/* выравнивание шапки выбирает тема */
.t-head.head-center{flex-direction:column;align-items:center;gap:5px;text-align:center;padding:16px 18px}
.t-head.head-center span{text-align:center}
.t-head.head-stacked{flex-direction:column;align-items:flex-start;gap:4px}
.t-head.head-stacked span{text-align:left}
.t-head b{font-size:15px;letter-spacing:.2em;font-weight:700}
.t-head span{font-size:8.5px;letter-spacing:.2em;opacity:.85;text-align:right;line-height:1.5}
.t-body{padding:18px}
.t-row{display:grid;grid-template-columns:1fr 1fr;grid-template-rows:auto auto;gap:14px;margin-bottom:13px}
/* подписи и значения двух соседних ячеек лежат в общих строках грида:
   иначе значение выравнивается по своей ячейке, и стоит одной подписи
   (или одному значению) занять две строки — соседнее уезжает по вертикали.
   Только прямые потомки: у инлайновых тем .f переопределён на flex, а в
   строке с фотографией поля лежат внутри своей колонки, не в этом гриде */
.t-row > .f{display:grid;grid-template-rows:subgrid;grid-row:span 2}
/* iOS Safari < 16 не знает subgrid — правило выше там игнорируется, и
   значения соседних полей снова разъезжаются по вертикали (это чинили).
   Фолбэк без subgrid: возвращаем колоночный флекс и резервируем под подпись
   высоту двух строк, чтобы значения вставали на одном уровне независимо от
   того, в одну строку подпись или в две. На современных браузерах блок не
   применяется вовсе. */
@supports not (grid-template-rows: subgrid){
  .t-row > .f{display:flex}
  .t-row > .f > label{min-height:2.4em}
}
.t-row[hidden]{display:none}
/* место под штамп «дата открыта» в правом верхнем углу первой строки */
.t-row--stamp-gutter{padding-right:118px}
/* фото пары: круглый портрет слева, как на пропуске */
.t-row--photo{grid-template-columns:auto 1fr;margin-bottom:15px}
.t-photo{width:74px;height:74px;border-radius:50%;overflow:hidden;border:2px solid var(--accent)}
.t-photo img{width:100%;height:100%;object-fit:cover;display:block}
/* Подписи полей двуязычные («SHOWTIME · НАЧАЛО») и в узкой колонке
   переносятся на две строки — а соседняя может уместиться в одну. Значения
   из-за этого вставали на разной высоте. Ячейка растягивается на всю высоту
   строки (грид), поэтому прижимаем подпись к верху, а значение к низу:
   значения выравниваются между собой независимо от длины подписей. */
/* подпись сверху, значение сразу под ней. Было space-between — значения
   прижимались к низу ячейки и совпадали, только пока оба однострочные:
   стоило городу перенестись на две строки, как соседнее значение в той же
   двухколоночной строке уезжало на строку ниже. Канва всегда рисовала обе
   колонки от общей базовой линии — теперь экран делает то же самое */
.f{min-width:0;display:flex;flex-direction:column;justify-content:flex-start}
.f label{display:block;font-family:var(--mono);font-size:8.5px;letter-spacing:.19em;color:var(--ticket-muted);margin-bottom:3px}
.f div{font-family:var(--mono);font-size:13.5px;font-weight:600;word-break:break-word;line-height:1.4}
/* значение уходит на свою строку, когда рядом с подписью ему не хватает
   места ни при каком кегле (см. fitFieldValues в engine/engine.js).
   Класс ставит движок по факту замера, а не тема заранее: зависит от
   длины конкретного слова и ширины экрана */
.f.f--own-line{flex-wrap:wrap}
.f.f--own-line > div{flex:1 1 100%}
.f.big div{font-size:clamp(15px,4.6vw,19px);letter-spacing:.05em}
.t-perf{border-top:1.5px dashed var(--perf);position:relative;margin:3px -18px 0}
.t-perf::before,.t-perf::after{content:"";position:absolute;top:-11px;width:22px;height:22px;border-radius:50%;background:var(--bg)}
.t-perf::before{left:-11px}.t-perf::after{right:-11px}
.t-foot{padding:16px 18px 18px;display:flex;flex-direction:column;gap:10px;align-items:center}

/* ---------- форма бланка ---------- */
.ticket{display:flex}                    /* корешок встаёт рядом с основным полем */
.t-sheet{flex:1;min-width:0;position:relative}
/* корешок: то, что остаётся на руках после отрыва */
.t-stub{
  /* корешок декоративный, а на 320px (iPhone SE первого поколения) его
     84px — это четверть ширины бланка: строка полей становится настолько
     узкой, что самое длинное слово библиотеки не влезает даже на
     минимальном кегле. Сужаем корешок, а не текст */
  flex:0 0 84px;border-left:2px dashed var(--perf);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;
  padding:18px 0;color:var(--ticket-ink);
}
.t-stub[hidden]{display:none}
@media (max-width:360px){.t-stub{flex-basis:56px}}
/* корешок обычно справа; тема может попросить левый (ticket.stubSide:"left")
   — тогда порядок во флексе просто разворачивается, а пунктир переезжает
   на противоположный край корешка (он всегда со стороны основного поля) */
.ticket.stub-left{flex-direction:row-reverse}
.ticket.stub-left .t-stub{border-left:none;border-right:2px dashed var(--perf)}
.t-stub span{writing-mode:vertical-rl;transform:rotate(180deg);font-family:var(--mono);white-space:nowrap}
.stub-brand{font-size:15px;font-weight:700;letter-spacing:.3em}
.stub-code{font-size:10px;letter-spacing:.22em;color:var(--ticket-muted)}
/* у бланка с корешком круглые вырезы не нужны — край и так рваный */
.ticket.shape-stub .t-perf::before,.ticket.shape-stub .t-perf::after{display:none}
.bars{display:flex;gap:2px;height:44px;align-items:stretch}
.bars i{background:var(--ticket-ink);border-radius:.5px}
.t-code{font-family:var(--mono);font-size:10px;letter-spacing:.3em;color:var(--ticket-muted);text-align:center}

.final{border-left:2px solid var(--accent);padding:2px 0 2px 16px;margin:24px 0 18px;font-size:16px;line-height:1.6;color:var(--final-ink);white-space:pre-line}
.ps{font-size:13.5px;line-height:1.55;color:var(--muted);font-style:italic;margin:0 0 24px 18px}
.actions{display:flex;flex-direction:column;gap:10px}

.conf{position:fixed;inset:0;pointer-events:none;z-index:5;overflow:hidden}
.conf i{position:absolute;width:8px;height:13px;border-radius:1px;animation:fall linear forwards}
@keyframes fall{to{transform:translateY(105vh) rotate(720deg);opacity:0}}

/* Штамп «дата открыта» стоит в правом верхнем углу бланка, и первая строка
   резервирует под него полосу справа (.t-row--stamp-gutter). На узком экране
   это съедало больше половины строки — 118px из 217px, — и одно длинное
   слово вроде «ПЛАНЕТАРИЙ» ломалось посередине. Здесь строка получает всю
   ширину, а от штампа уходит вниз: смещение меньше вредит, чем разорванное
   пополам слово. */
@media (max-width:520px){
  .t-row--stamp-gutter{padding-right:0;padding-top:44px}
}
@media (max-width:335px){.grid{grid-template-columns:1fr}}
@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;transition-duration:.01ms!important}}

/* ---------- подвалы: чем заканчивается бланк ---------- */
.qr{
  display:grid;grid-template-columns:repeat(11,1fr);gap:1px;
  width:104px;height:104px;
}
.qr i{background:transparent;border-radius:0}
.qr i.on{background:var(--ticket-ink)}

.seal{
  width:104px;height:104px;border-radius:50%;
  border:3px solid var(--stamp);box-shadow:inset 0 0 0 4px var(--ticket-bg-1),inset 0 0 0 5px var(--stamp);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  color:var(--stamp);opacity:.85;text-align:center;padding:6px;
}
.seal span{font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.16em;line-height:1.2}
.seal small{font-family:var(--mono);font-size:6.5px;letter-spacing:.1em;opacity:.9}

.stars{display:flex;gap:12px;font-size:20px;line-height:1;color:var(--ticket-muted);opacity:.85}

.suits{display:flex;gap:14px;font-size:26px;line-height:1;color:var(--ticket-ink)}
.suits .red{color:var(--stamp)}
