/* ─── THE BLACK LIST ─────────────────────────────────────────────────────── */

@font-face { font-family:"Etude Noire"; src:url("fonts/EtudeNoireLight.woff2") format("woff2");   font-weight:300; font-display:swap; }
@font-face { font-family:"Etude Noire"; src:url("fonts/EtudeNoireRegular.woff2") format("woff2"); font-weight:400; font-display:swap; }
@font-face { font-family:"Etude Noire"; src:url("fonts/EtudeNoireMedium.woff2") format("woff2");  font-weight:500; font-display:swap; }
@font-face { font-family:"Etude Noire"; src:url("fonts/EtudeNoireBold.woff2") format("woff2");    font-weight:700; font-display:swap; }

:root{
  --ink:#000;
  --paper:#fff;
  --muted:rgba(255,255,255,.45);
  --line:rgba(255,255,255,.14);
  --field:rgba(255,255,255,.05);
  --danger:#ff4d4d;
  --warm:#e4d9c6;
  --ok:#4ade80;
  --pad:24px;
  /* Отступы от зон, куда нельзя ставить текст. В полноэкранном режиме
     Telegram это статус-бар и плавающие кнопки «Закрыть» и «⋯» — их высоту
     присылает сам Telegram (--tg-top, см. app.js). Вне Telegram и в обычном
     режиме остаются системные отступы устройства. */
  --top-inset:var(--tg-top, env(safe-area-inset-top, 0px));
  --bottom-inset:var(--tg-bottom, env(safe-area-inset-bottom, 0px));
  /* Доступная высота окна: внутри Telegram её сообщает клиент, в браузере
     остаётся 100dvh. От неё считаются размеры на экране участника. */
  --app-h:100dvh;
  --gap-v:clamp(14px,calc(var(--app-h) * .024),24px);
  --qr:calc(var(--app-h) * .30);
  --font:"Etude Noire",-apple-system,BlinkMacSystemFont,"Helvetica Neue",sans-serif;
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}

html,body{height:100%}
body{
  margin:0;
  background:var(--ink);
  color:var(--paper);
  font-family:var(--font);
  font-weight:300;
  font-size:16px;
  line-height:1.45;
  -webkit-font-smoothing:antialiased;
  overscroll-behavior:none;
}

/* ─── каркас экрана ──────────────────────────────────────────────────────── */

.screen{
  display:none;
  min-height:100dvh;
  padding:var(--pad);
  padding-top:calc(var(--pad) + var(--top-inset));
  padding-bottom:calc(var(--pad) + var(--bottom-inset));
  flex-direction:column;
  animation:rise .45s cubic-bezier(.16,1,.3,1) both;
}
.screen.active{display:flex}

@keyframes rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

.spacer{flex:1;min-height:16px}

/* ─── логотип ────────────────────────────────────────────────────────────── */

.logo{
  font-weight:700;
  text-transform:uppercase;
  letter-spacing:-.03em;
  line-height:.82;
  font-size:clamp(46px,15vw,76px);
}
.logo--sm{font-size:22px;letter-spacing:-.02em;line-height:1}

/* ─── типографика ────────────────────────────────────────────────────────── */

.eyebrow{
  font-size:11px;
  font-weight:500;
  letter-spacing:.22em;
  text-transform:uppercase;
  color:var(--muted);
  margin-bottom:28px;
}
h1{
  font-size:30px;
  font-weight:500;
  letter-spacing:-.02em;
  line-height:1.08;
  margin:0 0 14px;
}
p{margin:0 0 14px;color:rgba(255,255,255,.72)}
p.lead{font-size:17px;color:rgba(255,255,255,.86)}
.dim{color:var(--muted);font-size:13px;line-height:1.5}

/* ─── кнопки ─────────────────────────────────────────────────────────────── */

.btn{
  display:flex;align-items:center;justify-content:center;
  width:100%;min-height:54px;
  border:0;
  /* Скругление как у иконок Apple: радиус около 22% от высоты. corner-shape
     даёт настоящую непрерывную кривую там, где браузер её умеет; где нет —
     остаётся обычная дуга того же радиуса, и разница почти незаметна. */
  border-radius:13px;
  corner-shape:squircle;
  background:var(--paper);color:var(--ink);text-decoration:none;
  font-family:var(--font);font-weight:500;font-size:13px;
  letter-spacing:.16em;text-transform:uppercase;
  cursor:pointer;
  transition:opacity .18s,transform .18s;
}
.btn:active{transform:scale(.985)}
.btn[disabled]{opacity:.28;pointer-events:none}
.btn--ghost{background:transparent;color:var(--paper);border:1px solid var(--line)}
.btn + .btn{margin-top:10px}

/* ─── поля ───────────────────────────────────────────────────────────────── */

.field{margin-bottom:22px}
.field label{
  display:block;font-size:11px;font-weight:500;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted);margin-bottom:9px;
}
.field input{
  width:100%;padding:14px 0;
  background:transparent;border:0;border-bottom:1px solid var(--line);
  color:var(--paper);font-family:var(--font);font-weight:300;font-size:19px;
  border-radius:0;
}
.field input:focus{outline:0;border-bottom-color:var(--paper)}
.field input::placeholder{color:rgba(255,255,255,.22)}

/* ─── загрузка фото ──────────────────────────────────────────────────────── */

.photo{
  position:relative;width:100%;aspect-ratio:3/4;max-height:32dvh;flex:none;
  border:1px dashed var(--line);border-radius:2px;
  display:flex;align-items:center;justify-content:center;flex-direction:column;
  gap:10px;overflow:hidden;cursor:pointer;background:var(--field);
}
.photo img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
/* Фраза длинная: капс с широкой разрядкой её бы разорвал, поэтому
   обычный набор по центру. */
.photo .hint{
  font-size:13px;line-height:1.5;color:var(--muted);
  text-align:center;padding:0 20px;z-index:1;
}
.photo.filled{border-style:solid}
.photo.filled .hint,.photo.filled .plus{display:none}
.plus{font-size:30px;font-weight:300;color:var(--muted);line-height:1}
.photo input{display:none}

/* Анкета: всё по центру, а рамка под фото — узкая и вертикальная, чтобы было
   видно, что снимок не обрежут */
#s-form{text-align:center}
#s-form .field input{text-align:center}
/* Рамка тянется на всё свободное место между фамилией и кнопкой */
#s-form .photo{
  flex:1 1 0;min-height:min(200px,26dvh);max-height:none;width:auto;max-width:100%;
  align-self:center;margin:0 auto 22px;
}
#s-form .spacer{display:none}
#s-form .btn{margin-inline:auto}

/* ─── согласие ───────────────────────────────────────────────────────────── */

.consent-box{
  flex:1 1 auto;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:18px 0;margin-bottom:20px;font-size:14px;line-height:1.6;
  color:rgba(255,255,255,.62);
}
.consent-box b{color:rgba(255,255,255,.9);font-weight:500}
.consent-box ul{margin:8px 0 14px;padding-left:18px}
.consent-box li{margin-bottom:5px}

.check{display:flex;gap:12px;align-items:flex-start;cursor:pointer;margin-bottom:20px}
.check input{position:absolute;opacity:0;pointer-events:none}
.check .box{
  flex:none;width:20px;height:20px;margin-top:1px;
  border:1px solid var(--muted);border-radius:2px;
  display:flex;align-items:center;justify-content:center;
  transition:.18s;
}
.check .box::after{content:"";width:9px;height:9px;background:var(--ink);transform:scale(0);transition:.18s}
.check input:checked + .box{background:var(--paper);border-color:var(--paper)}
.check input:checked + .box::after{transform:scale(1)}
.check span{font-size:14px;color:rgba(255,255,255,.78);line-height:1.4}

/* ─── карточка участника ─────────────────────────────────────────────────── */

/* Белый фон рамки появляется вместе с самим кодом: пустой белый квадрат на
   чёрном экране читается как вспышка, пока код едет с сервера. Место под него
   зарезервировано заранее, поэтому ничего не прыгает. */
.qr-wrap{
  background:transparent;border-radius:3px;padding:20px;
  transition:background-color .18s ease;
  display:flex;align-items:center;justify-content:center;
  aspect-ratio:1;width:100%;max-width:300px;margin:0 auto;
}
.qr-wrap svg,.qr-wrap img{width:100%;height:100%;display:block;opacity:0;transition:opacity .18s ease}
.qr-wrap.is-ready{background:var(--paper)}
.qr-wrap.is-ready svg,.qr-wrap.is-ready img{opacity:1}

.member-name{
  font-size:27px;font-weight:500;letter-spacing:-.02em;
  text-transform:uppercase;text-align:center;margin-top:26px;
}
.member-meta{text-align:center;color:var(--muted);font-size:12px;
  letter-spacing:.16em;text-transform:uppercase;margin-top:8px}

.countdown{
  text-align:center;font-size:11px;letter-spacing:.18em;text-transform:uppercase;
  color:var(--muted);margin-top:22px;
}
.countdown b{color:var(--paper);font-weight:500}

/* ─── статусы ────────────────────────────────────────────────────────────── */

.status-dot{
  width:9px;height:9px;border-radius:50%;background:var(--paper);
  margin-bottom:26px;animation:pulse 2s ease-in-out infinite;
}
.status-dot--ok{background:var(--paper);animation:none}
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.32;transform:scale(.8)}}

/* Не красный: это не поломка, а объяснение правила. Тёплый оттенок
   говорит «так устроено», а не «что-то сломалось». */
/* Полоска про связь: поверх всего, но не перекрывает экран целиком. Тон —
   приглушённый: это сообщение о временной помехе, а не ошибка человека. */
.offline{
  position:fixed;left:0;right:0;top:0;z-index:200;
  display:flex;align-items:center;justify-content:center;gap:10px;
  padding:calc(8px + env(safe-area-inset-top)) 14px 8px;
  background:rgba(40,40,44,.96);color:rgba(255,255,255,.92);
  font-size:13px;line-height:1.3;
}
.offline[hidden]{display:none}
.offline button{
  border:1px solid rgba(255,255,255,.45);background:transparent;
  color:inherit;font:inherit;padding:3px 10px;border-radius:2px;cursor:pointer;
}
.offline button:active{opacity:.6}

.error{
  color:var(--warm);font-size:13px;margin-top:12px;min-height:18px;
  text-align:center;
}

.legal{font-size:11px;color:rgba(255,255,255,.3);line-height:1.5;margin-top:16px}

/* Экран согласия — единственный с фиксированной высотой: так длинный текст
   прокручивается внутри рамки, а чекбокс и кнопка всегда остаются на виду. */
#s-consent{height:100dvh;max-height:100dvh}


/* ─── ближайшее мероприятие ──────────────────────────────────────────────── */

/* ─── экран участника ─────────────────────────────────────────────────────
   Помещается в одно окно без прокрутки на любом телефоне. Размеры считаются
   от доступной высоты (--app-h): внутри Telegram она меньше экрана, поэтому
   значение приходит из JS, а 100dvh — только запасной вариант. */

#s-member{
  position:relative;
  align-items:center;text-align:center;
  /* min-height из базового правила задан в dvh и перебивал бы заданную
     высоту: dvh в части браузеров больше реального окна. */
  min-height:0;
  height:var(--app-h,100dvh);max-height:var(--app-h,100dvh);
  overflow:hidden;
  padding-top:calc(var(--gap-v) + var(--top-inset));
  padding-bottom:calc(var(--gap-v) + var(--bottom-inset));
}
#s-member .spacer{min-height:0}

#s-member .qr-wrap{
  width:min(236px,var(--qr));
  max-width:none;padding:clamp(10px,calc(var(--app-h) * .018),20px);
}

#s-member .btn{
  max-width:340px;margin-left:auto;margin-right:auto;
  min-height:clamp(42px,calc(var(--app-h) * .062),54px);
}
#s-member .upcoming,#s-member .invite-box{text-align:center;width:100%}

/* Обложка мероприятия — во всю ширину и до самого верха окна, вплотную
   к шапке Telegram. Отрицательные отступы гасят поля экрана, а внутренние
   возвращают их тексту, чтобы он стоял на одной линии с остальным.
   Снизу фото растворяется в чёрном фоне, без жёсткой границы. */
#s-member .upcoming.has-cover{
  position:relative;overflow:hidden;
  align-self:stretch;width:auto;
  /* Блок забирает свободное место над таймером, а содержимое прижимается
     к низу: кнопка «Подробнее» оказывается рядом с «Код обновится через». */
  flex:1 1 auto;display:flex;flex-direction:column;justify-content:flex-end;
  margin:calc(-1 * (var(--gap-v) + var(--top-inset))) calc(-1 * var(--pad)) 0;
  padding:
    calc(var(--gap-v) + var(--top-inset) + clamp(22px,calc(var(--app-h) * .04),40px))
    var(--pad)
    clamp(12px,calc(var(--app-h) * .02),20px);
  background:var(--ink);
}
/* Фотография мероприятия лежит отдельным слоем и проявляется, когда файл
   действительно загрузился: иначе на экране сначала пустой тёмный блок,
   а потом резко картинка — глаз читает это как вспышку. Затемнение сверху
   вторым слоем, текст поверх обоих. */
#s-member .upcoming.has-cover::before{
  content:"";position:absolute;inset:0;z-index:0;
  background:var(--cover, none) 62% 42% / cover no-repeat;
  opacity:0;transition:opacity .28s ease;
}
#s-member .upcoming.has-cover.cover-ready::before{opacity:1}
#s-member .upcoming.has-cover::after{
  content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(to bottom,
    rgba(0,0,0,.22) 0%, rgba(0,0,0,.36) 50%, rgba(0,0,0,.78) 84%, #000 100%);
}
#s-member .upcoming.has-cover > *{position:relative;z-index:2}
#s-member .upcoming.has-cover .eyebrow{color:rgba(255,255,255,.72)}
#s-member .upcoming.has-cover .upcoming__when{color:rgba(255,255,255,.82)}
#s-member .upcoming.has-cover .upcoming__title{
  text-shadow:0 1px 14px rgba(0,0,0,.55);
  font-size:min(clamp(19px,calc(var(--app-h) * .036),29px), calc((100vw - 56px) / 11.5));
}
/* Мелкий текст теряется, когда ложится на неон — подкладываем тень */
#s-member .upcoming.has-cover .eyebrow,
#s-member .upcoming.has-cover .upcoming__when{text-shadow:0 1px 8px rgba(0,0,0,.75)}
/* Кнопка на фото — тёмное стекло: прозрачная рамка на снимке теряется */
#s-member .upcoming.has-cover .btn--ghost{
  background:rgba(0,0,0,.42);border-color:rgba(255,255,255,.32);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
}

#s-member .eyebrow{margin-bottom:clamp(4px,calc(var(--app-h) * .01),10px)}

.upcoming__title{
  /* «TOKYO AFTER DARK» длиннее прежнего названия и ломалось на две строки.
     Размер берём меньший из двух: от высоты экрана и от доступной ширины. */
  font-size:min(clamp(19px,calc(var(--app-h) * .036),29px), calc((100vw - 56px) / 11.5));
  text-wrap:balance;
  font-weight:700;letter-spacing:-.03em;text-transform:uppercase;line-height:1;
}
.upcoming__when{
  color:var(--muted);
  font-size:clamp(12px,calc(var(--app-h) * .018),14px);
  margin-top:clamp(4px,calc(var(--app-h) * .009),8px);
}
#s-member .upcoming .btn{margin-top:clamp(8px,calc(var(--app-h) * .02),16px)}

/* Имя гостя — всегда в одну строку и всегда целиком, какой бы длины оно ни
   было. Размер отсюда — потолок: длинное имя app.js уменьшает ровно настолько,
   чтобы оно поместилось. Ни переноса, ни обрезки многоточием. */
#s-member .member-name{
  width:100%;white-space:nowrap;
  font-size:clamp(16px,calc(var(--app-h) * .027),22px);
  margin-top:clamp(8px,calc(var(--app-h) * .018),14px);
}
#s-member .member-meta{
  color:var(--paper);
  font-size:clamp(10px,calc(var(--app-h) * .015),12px);
  margin-top:clamp(4px,calc(var(--app-h) * .01),8px);
}
/* Таймер стоит над кодом и набран мельче: это служебная строка,
   она не должна спорить с именем. */
#s-member .countdown{
  font-size:clamp(8px,calc(var(--app-h) * .0115),10px);
  margin-top:0;
  margin-bottom:clamp(5px,calc(var(--app-h) * .011),9px);
}

.invite-box{
  width:100%;border-top:1px solid var(--line);
  padding-top:clamp(12px,calc(var(--app-h) * .027),22px);
}
#s-member .invite-box p{
  font-size:clamp(11px,calc(var(--app-h) * .016),13px);
  margin-bottom:clamp(8px,calc(var(--app-h) * .02),16px);
}
#s-member .invite-box .btn{margin-top:0}

.qr-wrap.inverted{background:var(--ink);padding:14px}

.next-event{border-top:1px solid var(--line);padding-top:20px}
.next-event__date{
  font-size:26px;font-weight:500;letter-spacing:-.02em;
  text-transform:uppercase;margin-bottom:10px;
}
.next-event p{margin:0}


/* ─── страница мероприятия ───────────────────────────────────────────────── */

.back{
  background:transparent;border:0;color:var(--muted);cursor:pointer;padding:0;
  font-family:var(--font);font-size:11px;letter-spacing:.2em;text-transform:uppercase;
  margin-bottom:26px;align-self:flex-start;
}
.event-title{
  font-size:38px;font-weight:700;letter-spacing:-.03em;line-height:.95;
  text-transform:uppercase;margin-bottom:22px;
}
.event-block{border-top:1px solid var(--line);padding-top:16px;margin-bottom:22px}
.event-block__label{
  font-size:10px;font-weight:500;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);margin-bottom:8px;
}
.event-block p{margin:0;white-space:pre-line}

/* ─── «Проходи» — экран гостя в момент, когда его пропустили ─────────────── */

.passed{
  position:fixed;inset:0;z-index:100;
  background:var(--ok);color:var(--ink);
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  text-align:center;padding:var(--pad);
  animation:flash .4s cubic-bezier(.16,1,.3,1) both;
}
.passed[hidden]{display:none !important}
.passed--no{background:var(--danger);color:var(--paper)}
.passed__msg{
  /* Размер под самую длинную фразу — «QR-код уже использован». Крупнее
     она вылезала за край на узких экранах. */
  font-size:clamp(26px,7.5vw,42px);font-weight:700;
  letter-spacing:-.02em;line-height:1.02;text-transform:uppercase;
  max-width:14ch;overflow-wrap:break-word;
}
.passed__sub{
  font-size:13px;letter-spacing:.14em;text-transform:uppercase;
  margin-top:16px;opacity:.7;max-width:22ch;
}
@keyframes flash{from{opacity:0;transform:scale(.94)}to{opacity:1;transform:none}}


/* Экран «по рекомендации»: текст на кегль мельче — фразы длинные,
   и в крупном наборе они распирают экран. На маленьком телефоне кегль
   считается от высоты окна, иначе объяснение про приглашение не помещается. */
#s-noinvite .lead{font-size:clamp(13px,calc(var(--app-h) * .021),16px)}

/* Экраны фиксированной высоты появляются без сдвига. Общая анимация въезда
   стартует со смещения на 14 px, и на время появления страница становилась
   выше окна — отсюда прокрутка, которой на этих экранах быть не должно. */
@keyframes fade{from{opacity:0}to{opacity:1}}
#s-member,#s-consent{animation-name:fade}

/* Между блоком мероприятия и таймером — небольшой постоянный зазор вместо
   растягивающегося пустого места. */
#s-member .upcoming.has-cover + .spacer{flex:0 0 clamp(8px,calc(var(--app-h) * .014),14px)}

/* Галочки согласий на первом экране — мелко, под кнопкой входа */
.consents{margin-bottom:16px}
.consents .check{margin-bottom:12px;gap:10px}
.consents .check .box{width:18px;height:18px}
.consents .check span:not(.box){font-size:12px;line-height:1.45;color:rgba(255,255,255,.62)}

/* Ссылки на документы в подписи галочки — видно, что на них можно нажать */
.doc-link{color:rgba(255,255,255,.92);text-decoration:underline;text-underline-offset:2px}
/* Документ внутри приложения. Весь текст одного тона: серыми были только абзацы,
   а списки и жирное оставались белыми — в юридическом тексте такой пестроты быть
   не должно. Длинные адреса переносим, иначе экран едет вбок. */
.doc-body{color:rgba(255,255,255,.88);font-size:15px;line-height:1.5;overflow-wrap:anywhere}
.doc-body h2{margin:26px 0 10px;font-size:17px;font-weight:500;letter-spacing:-.01em}
.doc-body p{margin:0 0 12px}
.doc-body b{font-weight:500}
.doc-body ul{margin:6px 0 14px;padding-left:20px}
.doc-body li{margin-bottom:6px}
/* Таблица целей обработки прокручивается вбок внутри своей рамки */
.doc-body a{color:inherit;text-decoration:underline;text-underline-offset:2px}
.doc-body .doc-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:0 0 16px}
.doc-body .doc-table{
  border-collapse:collapse;table-layout:auto;width:max-content;min-width:100%;
  font-size:11px;line-height:1.45;
}
.doc-body .doc-table th,.doc-body .doc-table td{
  border:1px solid var(--line);padding:10px 12px;text-align:left;vertical-align:top;
  overflow-wrap:normal;word-break:normal;hyphens:none;
}
.doc-body .doc-table th{font-weight:500}
.doc-body .doc-table :is(th,td){min-width:10em;max-width:20em}

/* Первый экран: строка про соглашение под кнопкой */
.terms-line{
  font-size:11px;line-height:1.5;color:rgba(255,255,255,.45);
  margin-top:14px;text-align:center;
}
.terms-line .doc-link{color:rgba(255,255,255,.75)}
/* Значок 18+ — в правом верхнем углу первого экрана, ниже кнопок Telegram */
#s-intro{position:relative}
.age-badge{
  position:absolute;top:calc(var(--pad) + var(--top-inset));right:var(--pad);
  font-size:18px;line-height:1;color:rgba(255,255,255,.45);letter-spacing:.04em;
  border:1.5px solid rgba(255,255,255,.3);border-radius:6px;padding:4.5px 9px;
}

/* Кнопка с атрибутом hidden: без !important её display перебивает браузерное правило */
.btn[hidden]{display:none !important}

/* Карандаш настроек — в правом верхнем углу экрана участника, ниже кнопок
   Telegram. Та же форма, что у значка 18+, но на тёмном стекле: лежит на фото. */
.profile-btn{
  position:absolute;z-index:2;top:calc(var(--gap-v) + var(--top-inset));right:var(--pad);
  display:flex;align-items:center;justify-content:center;
  padding:4.5px 9px;line-height:1;cursor:pointer;
  color:rgba(255,255,255,.85);background:rgba(0,0,0,.42);
  border:1.5px solid rgba(255,255,255,.32);border-radius:6px;
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
}
.profile-btn:active{opacity:.6}
.profile-btn:focus-visible{outline:2px solid var(--paper);outline-offset:2px}

/* Настройки профиля: тумблер */
.switch-row{
  position:relative;display:flex;align-items:center;justify-content:space-between;gap:16px;
  margin-top:24px;padding:16px 0;cursor:pointer;
  border-top:1px solid rgba(255,255,255,.12);border-bottom:1px solid rgba(255,255,255,.12);
}
.switch-row__text{font-size:15px;line-height:1.4;color:rgba(255,255,255,.86)}
.switch-row input{position:absolute;opacity:0;pointer-events:none}
.switch{
  flex:none;position:relative;width:48px;height:28px;border-radius:14px;
  background:rgba(255,255,255,.18);transition:background .2s;
}
.switch::after{
  content:"";position:absolute;top:3px;left:3px;width:22px;height:22px;border-radius:50%;
  background:var(--paper);transition:transform .2s,background .2s;
}
.switch-row input:checked + .switch{background:var(--paper)}
.switch-row input:checked + .switch::after{transform:translateX(20px);background:var(--ink)}
.switch-row input:disabled + .switch{opacity:.5}
.switch-row input:focus-visible + .switch{outline:2px solid var(--paper);outline-offset:3px}
.settings-note{margin-top:12px}

/* Необратимое действие — красная рамка, без заливки */
.btn--danger{background:transparent;color:var(--danger,#e5484d);border:1px solid var(--danger,#e5484d)}

/* Обёртки экрана приветствия нужны только большому экрану — на телефоне их нет */
.intro__logo,.intro__column,.intro__signin,.member__side{display:contents}
/* Длинная строка над кодом — только в большом окне */
.countdown__long{display:none}

/* ─── большое окно: как десктопная версия сайта ───────────────────────────── */

/* На компьютере Telegram открывает приложение окном в ширину телефона, а в
   полноэкранном режиме — во весь монитор. Узкое окно остаётся телефонной
   вёрсткой; широкое собирается так же, как главная страница сайта: логотип
   слева, колонка с текстом справа, и всё — доля от размера окна, поэтому
   вёрстка тянется вместе с ним. Числа те же, что в site.css. */
@media (min-width:700px){
  /* Отступ половин от низа окна. Один на всех: по нему стоят и «Подробнее»
     слева, и «Пригласить друга» справа, и нижние кнопки в настройках */
  :root{--half-bottom:clamp(36px,10dvh,110px)}

  #s-intro.active,#s-noinvite.active{
    display:grid;
    --px:min(100vw / 1440, 100vh / 640, 1.35px);
    --col:calc(var(--px) * .9);
    grid-template-columns:minmax(0,1fr) calc(512 * var(--col));
    grid-template-rows:1fr auto 1fr;
    grid-template-areas:
      ".     badge"
      "logo  column"
      ".     .";
    column-gap:calc(56 * var(--px));
    row-gap:clamp(28px,6vh,64px);
    padding-inline:calc(84 * var(--px));
    padding-block:calc(var(--pad) + var(--top-inset)) calc(var(--pad) + var(--bottom-inset));
  }
  /* Въезд снизу на весь экран не годится: пока идёт анимация, страница выше
     окна — и появляется полоса прокрутки. Появляемся проявлением */
  #s-intro.active,#s-noinvite.active{animation-name:fade}
  #s-intro .spacer,#s-noinvite .spacer{display:none}
  #s-intro .age-badge{position:static;grid-area:badge;justify-self:end;align-self:start}

  /* Высоту ряда задаёт колонка: обёртка логотипа в размер ряда не вмешивается
     (container-type) и растягивается на него, а кегль считается от её высоты */
  #s-intro .intro__logo,#s-noinvite .intro__logo{grid-area:logo;display:block;container-type:size}
  #s-intro .logo,#s-noinvite .logo{font-size:min(100cqh / 2.46, 100cqw / 4.13)}

  #s-intro .intro__column,#s-noinvite .intro__column{
    grid-area:column;align-self:start;
    display:flex;flex-direction:column;gap:calc(48 * var(--col));
  }
  #s-noinvite .intro__column{gap:calc(24 * var(--col))}
  #s-intro .intro__signin{display:flex;flex-direction:column;gap:calc(18 * var(--col))}

  #s-intro .lead,#s-noinvite .lead{font-size:calc(22 * var(--col));margin:0}
  #s-intro .consents{margin:0;gap:calc(16 * var(--col))}
  #s-intro .consents .check{margin:0;gap:calc(12 * var(--col))}
  #s-intro .consents .check .box{
    width:calc(20 * var(--col));height:calc(20 * var(--col));margin-top:calc(1 * var(--col));
  }
  #s-intro .consents .check .box::after{width:calc(9 * var(--col));height:calc(9 * var(--col))}
  #s-intro .consents .check span:not(.box){font-size:calc(12.4 * var(--col))}
  #s-intro .terms-line{margin:0;text-align:left;font-size:calc(12 * var(--col))}
  #s-noinvite .legal{margin:0;font-size:calc(12 * var(--col))}
  #s-intro .btn{
    max-width:none;min-height:calc(54 * var(--col));padding-inline:calc(24 * var(--col));
    border-radius:calc(13 * var(--col));font-size:calc(13 * var(--col));
  }

  @supports (text-box:trim-both cap alphabetic){
    /* Края — по верху заглавных и по базовой линии: так верх логотипа
       и верх колонки стоят на одной линии, как на сайте */
    #s-intro .logo,#s-noinvite .logo{
      font-size:min(100cqh / 2.34, 100cqw / 4.13);text-box:trim-both cap alphabetic;
    }
    #s-intro .lead,#s-noinvite .lead{text-box:trim-start cap alphabetic}
    #s-intro .terms-line,#s-noinvite .legal{text-box:trim-end cap alphabetic}
  }

  /* Экран участника — как кабинет на сайте: слева обложка во всю высоту,
     справа на чёрном код, имя и приглашения */
  #s-member.active,#s-member.under{
    display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
    /* align-items от телефонной раскладки центрировал бы половины вместо того,
       чтобы растянуть их во всю высоту */
    align-items:stretch;
    padding:0;text-align:left;
  }
  #s-member .upcoming{
    width:auto;min-height:0;margin:0;padding:var(--pad);text-align:left;
    display:flex;flex-direction:column;justify-content:flex-end;
  }
  /* Обложка держит всю левую половину, текст стоит внизу — как на сайте */
  #s-member .upcoming.has-cover{
    flex:none;
    /* Телефонные отрицательные поля здесь не нужны: половина и так во всю высоту */
    margin:0;
    /* Нижнее поле — как у правой половины: тогда «Подробнее» и «Пригласить друга»
       стоят на одной линии, как в кабинете на сайте */
    padding:calc(84px + var(--top-inset)) var(--pad)
            calc(var(--half-bottom) + var(--bottom-inset));
    background:
      linear-gradient(to bottom,
        rgba(0,0,0,.42) 0%, rgba(0,0,0,0) 24%, rgba(0,0,0,0) 50%, #000 100%),
      var(--cover) 50% 50% / cover no-repeat,
      var(--ink);
  }
  #s-member .upcoming .upcoming__title,
  #s-member .upcoming.has-cover .upcoming__title{
    font-size:min(clamp(22px,calc(100vw / 38),46px), calc((50vw - 96px) / 8.2));
  }
  #s-member .upcoming__when{font-size:clamp(13px,calc(100vw / 95),18px);margin-top:12px}
  /* Высоту кнопке оставляем общую (#s-member .btn): вторая кнопка справа такая же,
     и вместе с общим нижним полем они встают вровень */
  #s-member .upcoming .btn{margin:22px 0 0;max-width:260px}

  /* Правая половина — на чёрном и поверх обложки */
  #s-member .member__side{
    position:relative;z-index:1;background:var(--ink);overflow:hidden;
    display:flex;flex-direction:column;align-items:center;justify-content:center;
    min-height:0;text-align:center;
    padding:calc(var(--pad) + var(--top-inset)) var(--pad)
            calc(var(--half-bottom) + var(--bottom-inset));
  }
  #s-member .countdown{
    max-width:26em;margin-bottom:14px;
    font-size:clamp(11px,calc(var(--app-h) * .016),13px);
    letter-spacing:normal;text-transform:none;line-height:1.45;
  }
  #s-member .countdown__short{display:none}
  #s-member .countdown__long{display:inline}
  #s-member .qr-wrap{width:min(280px,calc(var(--app-h) * .34));padding:16px}
  #s-member .member-name{font-size:clamp(18px,calc(var(--app-h) * .032),26px)}
  #s-member .member-meta{font-size:clamp(11px,calc(var(--app-h) * .017),13px)}
  #s-member .invite-box{max-width:420px}
  #s-member .invite-box p{font-size:clamp(12px,calc(var(--app-h) * .018),14px)}

  /* Подробности о вечеринке ложатся на левую половину, настройки — на правую,
     поверх кода. Карточка при этом остаётся на месте, как в кабинете на сайте */
  #s-event.active,#s-settings.active{
    position:fixed;z-index:5;
    max-width:none;width:auto;margin:0;overflow-y:auto;
    background:var(--ink);
    padding:calc(var(--pad) + var(--top-inset)) var(--pad)
            calc(var(--half-bottom) + var(--bottom-inset));
  }
  #s-event.active{inset:0 50% 0 0}
  #s-settings.active{inset:0 0 0 50%}
  /* Обе панели занимают половину окна, и содержимое в них не должно расползаться
     от края до края: поля по бокам растут вместе с окном */
  #s-event.active,#s-settings.active{padding-inline:clamp(28px,7vw,110px)}
  /* Кнопки в настройках — той же ширины, что «Пригласить друга» под кодом:
     на половину окна они растянулись бы через весь экран */
  #s-settings .btn{max-width:340px;margin-inline:auto}

  /* Остальные экраны пока держим колонкой по центру окна: растянутые на весь
     монитор поля и кнопки выглядели бы случайно */
  .screen:not(#s-intro):not(#s-noinvite):not(#s-member):not(#s-event):not(#s-settings){
    max-width:520px;margin-inline:auto;width:100%;
  }
}
