/* Стиль веб-версии. Тот же визуальный язык, что у витрины vtochkucv.ru:
   человек приходит с лендинга и попадает «на наш сайт», а не в служебную
   форму. Поэтому палитра, рамки, тени, кнопки и шрифты здесь не свои, а
   те же самые — отличается только то, что у приложения своя работа.

   Язык в двух словах: тёплое серое поле, карточка на тон светлее,
   жёсткая обводка в 2px и короткая тень своего цвета, углы не
   скруглены. Цвет — точками: бирюза у главного действия, жёлтый у
   пометок, коралл у необратимого. Заголовки моноширинные и в верхнем
   регистре, текст — Onest.

   Объявлений @font-face тут нет намеренно. Они собираются формулой
   `web.font_css()` и инлайнятся в `base.html`: формула имён файлов
   живёт в `web._FACES`, и второй её копии быть не должно. Своя копия
   здесь уже была и уже отстала — в ней остались гугловские подмножества
   по 14 и 32 КБ, тяжелее предела соединения. */

:root{
  --ink:#23211d;        /* текст */
  --edge:#4b463e;       /* рамки */
  --bg:#e9e6de;         /* поле страницы */
  --panel:#f1efe8;      /* карточка: на тон светлее поля */
  --sunk:#e2ded4;       /* утопленное: на тон темнее поля */
  --grey:#dcd7cb;
  --muted:#655f56;
  --shadow:#cec8ba;     /* тень: жёсткая, короткая, мягкая по цвету */
  --teal:#13a091;
  --yellow:#e6ac2e;
  --coral:#d9705d;
  --blue:#4f6cb5;
  --px:2px;                            /* толщина обводки */
  --rule:transparent;                      /* линия под шапкой и над подвалом */
  /* Мера страницы. Раньше 62rem, а содержимое внутри стояло по 46rem и
     жалось к левому краю: на широком экране справа оставалась пустая
     четверть. Теперь полоса равна мере содержимого, и вся колонка стоит
     по центру окна сама, без `margin:auto` в полутора десятках правил. */
  --w:49rem;            /* 46rem содержимого плюс поля .wrap */
}
*{box-sizing:border-box}
html{font-size:16px;-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--ink);
  font-family:'Onest',system-ui,-apple-system,sans-serif;
  font-size:16px;line-height:1.5;
  display:flex;flex-direction:column;min-height:100vh}
p{margin:0}
a{color:inherit}

/* Моноширинный — заголовкам, меткам и числам: ровно как на витрине. */
h1,h2,.label,.tag,.when,.price,.mono{font-family:'JBMono',ui-monospace,Menlo,monospace}
h1{margin:0 0 1rem;font-size:clamp(22px,4.4vw,34px);font-weight:500;
  letter-spacing:-.02em;text-transform:uppercase;line-height:1.15}
h2{margin:2.5rem 0 .75rem;font-size:clamp(16px,2.4vw,20px);font-weight:500;
  letter-spacing:-.01em;text-transform:uppercase}
h3{margin:0;font-size:17px;font-weight:600;letter-spacing:-.01em}
/* Надстрока раздела — как `.label` на витрине. */
.label{font-size:11px;font-weight:500;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted);margin:0 0 .4rem}

/* ── шапка и подвал ─────────────────────────────────────────────────── */
/* Линии под шапкой и над подвалом НЕТ. Решение владельца 9 октября:
   2px цветом рамки читались как жёсткая обводка страницы. Отделяет их
   теперь только своя подложка, `--panel` против `--bg`, и этого хватает.
   Токен оставлен: вернуть линию стоит одной строки, поставить ему
   `#dcd7cb`.

   Тени при прокрутке тут нет намеренно, и это не упущение: шапка
   кабинета НЕ липкая (`position:sticky` у неё нет), она уезжает вместе
   со страницей, и наезжать на текст ей нечем. Липкая шапка есть только
   у страницы резюме, и у неё своя CSS в `web.py` со своей подложкой,
   этим токеном она не управляется и не тронута.

   Рамки карточек этим токеном НЕ управляются и остаются как были. */
header.top{border-bottom:1px solid var(--rule);background:var(--panel)}
.top>.inner{max-width:var(--w);margin:0 auto;padding:12px 22px;
  display:flex;align-items:center;justify-content:space-between;gap:14px}
.brand{display:inline-flex;align-items:center;gap:10px;text-decoration:none;
  color:var(--ink);font-weight:600;font-size:16px}
/* Метка бренда: жёлтый квадрат с роботом внутри. На витрине в этом
   квадрате стоят буквы CV, здесь — сам робот: в кабинете он лицо, а не
   подпись. */
.brand .sq{width:30px;height:30px;border:var(--px) solid var(--edge);
  background:var(--yellow);display:grid;place-items:center;flex:0 0 auto;
  padding:3px 0 0}
.brand .sq .bot-svg{height:22px;width:auto;display:block}

/* Робот крупно — на входе и в пустых состояниях. Размер задаёт класс
   снаружи: сам спрайт не знает, куда его поставили. */
.bot{display:grid;place-items:center;width:84px;height:84px;flex:0 0 auto;
  border:var(--px) solid var(--edge);background:var(--panel);
  box-shadow:3px 3px 0 var(--shadow)}
.bot .bot-svg{height:58px;width:auto;display:block}
.bot-lg{width:112px;height:112px}
.bot-lg .bot-svg{height:78px}
/* Робот рядом с текстом: на входе и в пустом списке. На телефоне
   становится в колонку — иначе текст сжимается до четырёх слов в
   строку. */
.greet{display:flex;gap:18px;align-items:flex-start;flex-wrap:wrap;
  margin:0 0 1.5rem}
.greet .said{flex:1 1 18rem;min-width:0}
.top nav{display:flex;align-items:center;gap:14px}
.top nav a,.top .link{font-size:13px;color:var(--muted);text-decoration:none;
  font-family:'JBMono',monospace}
.top nav a:hover,.top .link:hover{color:var(--ink)}
.who{font-size:13px;color:var(--muted);font-family:'JBMono',monospace;
  max-width:14ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.wrap{max-width:var(--w);width:100%;margin:0 auto;padding:28px 22px 56px;flex:1}

.foot{border-top:1px solid var(--rule);background:var(--panel);
  font-size:14px;color:var(--muted);margin-top:auto}
.foot>.inner{max-width:var(--w);margin:0 auto;padding:20px 22px 28px;
  display:flex;flex-wrap:wrap;gap:8px 20px;align-items:center}
.foot a{color:var(--ink);text-decoration:none;
  border-bottom:2px solid var(--teal)}
.foot a:hover{background:var(--yellow)}

/* ── текст ──────────────────────────────────────────────────────────── */
/* Мера строки: длиннее 75 знаков глаз теряет начало следующей. */
.lead{max-width:60ch;color:var(--muted);font-size:16px}
.small{color:var(--muted);font-size:13.5px}
.dim{color:var(--muted)}
code{font-family:'JBMono',ui-monospace,monospace;font-size:.9em}

/* Плашка «что произошло»: утопленная, без тени — это не карточка, а
   отметка на полях. Жёлтая черта слева, потому что это не ошибка. */
.upd{max-width:60ch;margin:1rem 0;padding:.7rem 1rem;background:var(--sunk);
  border:var(--px) solid var(--edge);border-left:10px solid var(--yellow)}
/* То же, но про помеху: коралл. Цветом, а не только словом. */
.warn{max-width:60ch;margin:1rem 0;padding:.7rem 1rem;background:var(--panel);
  border:var(--px) solid var(--edge);border-left:10px solid var(--coral);
  color:var(--ink)}
.warn-link{color:var(--coral)}
.terms{max-width:60ch;margin:.75rem 0;padding-left:0;list-style:none}
.terms li{position:relative;padding-left:18px;margin:.5rem 0;color:var(--muted)}
.terms li::before{content:"";position:absolute;left:0;top:9px;width:7px;
  height:7px;background:var(--edge)}

/* ── то, что мы не рисовали ─────────────────────────────────────────── */
/* Выделение текста, курсор ввода и кольцо фокуса приходят от браузера и
   не принадлежат никакому оформлению: на нашей тёплой бумаге синее
   системное выделение видно сразу. Клавиатурный фокус к тому же нужен
   не для красоты — без него человек, который ходит табом, не понимает,
   где он. Кольцо тёмное, а не жёлтое: жёлтый на светлом поле даёт 1.9
   и как указатель не работает. */
::selection{background:var(--yellow);color:var(--ink)}
:focus-visible{outline:3px solid var(--edge);outline-offset:2px}
textarea,input{caret-color:var(--coral)}

/* ── кнопки ─────────────────────────────────────────────────────────── */
/* Один в один с витриной: жёсткая тень, ступенчатый сдвиг при нажатии.
   `steps(2)` — не украшение: движение тут пиксельное, плавное
   выбивалось бы из языка. */
.btn{display:inline-flex;align-items:center;gap:8px;text-decoration:none;
  padding:12px 22px;font:500 15px/1 'Onest',system-ui,sans-serif;
  color:var(--ink);cursor:pointer;
  border:var(--px) solid var(--edge);background:var(--panel);
  box-shadow:3px 3px 0 var(--shadow);
  transition:transform .08s steps(2),box-shadow .08s steps(2)}
.btn:hover{transform:translate(1px,1px);box-shadow:2px 2px 0 var(--shadow)}
.btn:active{transform:translate(3px,3px);box-shadow:0 0 0 var(--shadow)}
.btn[disabled]{opacity:.55;box-shadow:none;transform:none;cursor:default}
/* Главное действие — бирюзовое, как «Открыть бота» на витрине. */
.btn.go{background:var(--teal)}
.btn.ghost{background:var(--panel)}
/* Необратимое — коралловое. Рядом с обычной кнопкой «Удалить всё»
   читалось бы как обычная кнопка. */
.btn.danger{background:var(--coral)}
.row{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-top:1.5rem}
/* Кнопка-ссылка: для действий внутри строки, где рамка была бы шумом. */
.link{background:none;border:0;padding:0;color:var(--muted);font:inherit;
  text-decoration:none;border-bottom:2px solid var(--teal);cursor:pointer}
.link:hover{color:var(--ink);background:var(--yellow)}

/* ── формы ──────────────────────────────────────────────────────────── */
.q{margin:1.5rem 0;max-width:46rem}
.q label{display:block;font-weight:500;margin-bottom:.4rem}
.q .small{margin:.2rem 0 .5rem}
fieldset.q{border:var(--px) solid var(--edge);background:var(--panel);
  padding:1rem 1.1rem;box-shadow:3px 3px 0 var(--shadow)}
legend{padding:0 .4rem;font-weight:500;font-family:'JBMono',monospace;
  font-size:12px;letter-spacing:.1em;text-transform:uppercase}
textarea,input[type=text]{width:100%;max-width:46rem;font:inherit;
  padding:.65rem .7rem;border:var(--px) solid var(--edge);
  background:var(--panel);color:var(--ink)}
textarea:focus,input[type=text]:focus{outline:none;
  box-shadow:3px 3px 0 var(--shadow)}
textarea{resize:vertical}
input[type=file]{font:inherit;max-width:100%}
input[type=radio],input[type=checkbox]{accent-color:var(--teal);
  width:1rem;height:1rem;margin-right:.2rem}
.opts{margin-top:.5rem}
.opt{display:block;font-weight:400;margin:.5rem 0}
.step{margin:1.5rem 0}

/* ── карточки действий ──────────────────────────────────────────────── */
.menu{display:grid;gap:14px;max-width:46rem;margin:1.5rem 0 0}
.act{display:block;padding:16px 18px;text-decoration:none;color:var(--ink);
  border:var(--px) solid var(--edge);background:var(--panel);
  box-shadow:3px 3px 0 var(--shadow);
  transition:transform .08s steps(2),box-shadow .08s steps(2)}
.act:hover{transform:translate(1px,1px);box-shadow:2px 2px 0 var(--shadow)}
.act b{display:block;font-weight:600;font-size:16px}
.act span{display:block;margin-top:3px;color:var(--muted);font-size:14px}
/* Главное действие — бирюзовой полосой слева, а не заливкой: заливка
   съела бы описание, а оно тут и объясняет, зачем нажимать. */
.act-main{border-left:10px solid var(--teal)}
.act-main b{font-size:17px}

/* ── список резюме ──────────────────────────────────────────────────── */
/* Сначала телефон: всё в одну колонку, действия отдельной строкой под
   названием. В один ряд с названием они на 320 px не встают, а перенос
   рвёт их по случайному месту — проверено стендом на самой узкой
   ширине. Разрыв ниже только уплотняет то, что уже работает. */
.pages{list-style:none;padding:0;margin:1rem 0 0;max-width:46rem;
  display:grid;gap:12px}
.pages li{display:block;padding:14px 16px;border:var(--px) solid var(--edge);
  background:var(--panel);box-shadow:3px 3px 0 var(--shadow);
  border-left:10px solid var(--blue)}
/* Общее резюме — не отклик, а витрина: другая полоса. */
.pages li.base{border-left-color:var(--yellow)}
.pline{display:flex;gap:.6rem;align-items:baseline;flex-wrap:wrap}
.pline a{font-weight:500;text-decoration:none;
  border-bottom:2px solid var(--teal)}
.pline a:hover{background:var(--yellow)}
/* Дату к правому краю прижимаем только там, где строка одна. На узком
   экране название занимает всю ширину, дата переносится и уезжает
   направо отдельной строкой — читается как потерянная. */
.when{margin-left:0;color:var(--muted);font-size:12px;white-space:nowrap;
  letter-spacing:.06em;text-transform:uppercase}
.tag{font-size:10px;letter-spacing:.1em;text-transform:uppercase;
  border:var(--px) solid var(--edge);background:var(--yellow);
  padding:2px 7px;line-height:1.4}
.pacts{display:flex;gap:14px;align-items:baseline;flex-wrap:wrap;
  margin-top:.6rem;font-size:13.5px}
.pacts a,.pacts .link{color:var(--muted);text-decoration:none;
  font-size:inherit;border-bottom:2px solid var(--grey)}
.pacts a:hover,.pacts .link:hover{color:var(--ink);background:var(--yellow);
  border-bottom-color:var(--edge)}
.pacts .warn-link{border-bottom-color:var(--coral)}
/* Форма внутри строки действий не должна ломать поток: у неё свои
   отступы по умолчанию, и «Собрать PDF» уезжал на отдельную строку. */
.pacts form{display:inline;margin:0}

/* Второстепенное — цвет и удаление. Внизу и мельче: это не то, зачем
   человек пришёл, но и прятать за меню нечего — страниц всего две. */
/* Разделитель тем же токеном, что шапка и подвал: при `transparent`
   строку действий отделяет отступ, а не линия. Жирная линия цветом рамки
   читалась тут так же, как читались те две. */
.minor{display:flex;gap:20px;flex-wrap:wrap;margin-top:2.5rem;
  padding-top:1rem;border-top:1px solid var(--rule);max-width:46rem;
  font-size:13.5px}
.minor a{color:var(--muted);text-decoration:none;
  border-bottom:2px solid var(--grey)}
.minor a:hover{color:var(--ink);background:var(--yellow)}

/* ── палитра ────────────────────────────────────────────────────────── */
/* Образец — два квадрата теми же цветами, какими красится страница
   резюме. Не картинка: ещё один запрос стоит дороже двух квадратов, а
   предел у VPN на соединение. */
.pals{display:grid;gap:10px;max-width:46rem;margin-top:1rem}
.pals .pal{display:flex;gap:12px;align-items:center;margin:0;
  padding:12px 14px;border:var(--px) solid var(--edge);
  background:var(--panel);box-shadow:3px 3px 0 var(--shadow);cursor:pointer}
.pals .pal:hover{transform:translate(1px,1px);box-shadow:2px 2px 0 var(--shadow)}
.sw{display:inline-flex;gap:3px;flex:0 0 auto}
.sw i{width:20px;height:20px;border:var(--px) solid var(--edge)}
.pal-name{line-height:1.2;font-weight:500}

/* ── сводка профиля и длинные тексты ────────────────────────────────── */
.summary{max-width:46rem;background:var(--panel);padding:18px 20px;
  border:var(--px) solid var(--edge);box-shadow:3px 3px 0 var(--shadow)}
.summary b{font-weight:600}
.letter{max-width:46rem;background:var(--panel);padding:18px 20px;
  border:var(--px) solid var(--edge);box-shadow:3px 3px 0 var(--shadow);
  white-space:pre-wrap}
.more{max-width:46rem;margin:.5rem 0 1.5rem}
.more summary{cursor:pointer;color:var(--muted);font-size:13.5px;
  font-family:'JBMono',monospace;letter-spacing:.06em;text-transform:uppercase}
.more pre{white-space:pre-wrap;font:inherit;font-size:14px;color:var(--ink);
  margin:.6rem 0 0;padding:14px 16px;background:var(--sunk);
  border:var(--px) solid var(--edge)}
.quiz{margin:2rem 0;max-width:46rem}
.quiz summary{cursor:pointer;font-weight:500;padding:.5rem 0}
.tips{list-style:none;padding:0;max-width:46rem;display:grid;gap:12px;
  margin:1rem 0 0}
.tips li{padding:14px 16px;border:var(--px) solid var(--edge);
  background:var(--panel);box-shadow:3px 3px 0 var(--shadow)}
.tips p{margin:0 0 .4rem}
.crop{width:200px;height:200px;display:block;margin:.75rem 0;
  border:var(--px) solid var(--edge);box-shadow:3px 3px 0 var(--shadow)}
.drop{border:var(--px) dashed var(--edge);background:var(--sunk);
  padding:18px 20px;max-width:46rem}

/* Список добавленных файлов. Своя сетка, а не `.pages`: там карточка с
   полосой слева под резюме, а здесь строка «имя — убрать».
   Кнопка «убрать» живёт в своей форме: без скриптов убрать иначе нечем, а
   у формы свои отступы, и строка от них разъезжалась. Класс именно `rm`:
   прежний `drop` сталкивался с зоной загрузки выше, кнопка получала от неё
   пунктирную рамку и отступ в 18 пикселей и выглядела съехавшей. Приёмка
   6 октября, жалоба «кнопки убрать съехали». */
.files{list-style:none;padding:0;margin:1rem 0 0;max-width:46rem;
  display:grid;gap:8px}
.files li{display:flex;gap:16px;align-items:baseline;
  padding:12px 16px;border:var(--px) solid var(--edge);
  background:var(--panel);box-shadow:3px 3px 0 var(--shadow)}
.files .fname{flex:1 1 auto;min-width:0;overflow-wrap:anywhere}
.files form{margin:0;flex:0 0 auto}
.files .rm{border-bottom:2px solid var(--grey)}
.files .rm:hover{border-bottom-color:var(--edge)}
hr{border:0;border-top:var(--px) solid var(--edge);margin:2rem 0;
  max-width:46rem}

@media(min-width:40rem){
  /* На ширине от 640 px действия встают в ту же строку, что название:
     места хватает, и список становится короче вдвое. */
  .pages li{display:flex;gap:16px;align-items:baseline}
  .pline{flex:1 1 auto}
  .pline .when{margin-left:auto}
  .pacts{margin-top:0;flex:0 0 auto}
  .menu{grid-template-columns:1fr 1fr}
  .act-main{grid-column:1 / -1}
  .pals{grid-template-columns:1fr 1fr}
}

/* Движение — только сдвиг и только у наведения. Прозрачность на наших
   страницах не анимируется нигде: остановленная анимация держит первый
   кадр, и человек видит пустоту. Правило написано по белому экрану на
   айфоне и действует и здесь. */
@media(prefers-reduced-motion:reduce){
  .btn,.act,.pals .pal{transition:none}
  .btn:hover,.act:hover,.pals .pal:hover{transform:none}
}

/* Загрузка файла вакансии: своя форма со своим адресом, поэтому
   работает без JavaScript. Утопленная плашка, а не карточка: это не
   главное действие на странице, главное — поле с текстом ниже. */
.filebox{background:var(--sunk);border:var(--px) solid var(--edge);
  padding:14px 16px}
.filebox label{font-weight:500}
.filebox input[type=file]{margin:.4rem 0 .2rem}
.filebox .btn{margin-top:.4rem}

/* ── вход: два способа, QR, код ──────────────────────────────────────
   Две колонки от 40rem, одна ниже: на телефоне способы читаются
   подряд, и «по почте» не прячется под сгиб. */
/* Вход занимает ширину осмысленно: сам блок по центру полосы, внутри
   вступление во всю ширину и два способа рядом. Прежде всё жалось к
   левому краю на 46rem, и справа оставалась пустая треть экрана. */
.login{margin:0 auto}
.ways{display:grid;gap:18px;margin-top:1.4rem}
/* Карточки вровень по высоте, действие прижато к низу: иначе кнопки
   стоят на разной высоте и пара читается как две разные вещи. */
.way{background:var(--panel);border:var(--px) solid var(--edge);
  box-shadow:3px 3px 0 var(--shadow);padding:18px 20px;margin:0;
  display:flex;flex-direction:column}
/* Своё имя, не `.act`: тот занят карточками действий кабинета, у них
   рамка и подложка, и кнопка входа получала вокруг себя вторую рамку. */
.way .go-row{margin-top:auto;padding-top:.4rem;margin-bottom:0}
.way h2{margin:0 0 .3rem;font-size:19px}
.way p{margin:.4rem 0}
input.mail{width:100%;max-width:22rem;padding:10px 12px;font:inherit;
  border:var(--px) solid var(--edge);background:var(--bg);color:var(--ink)}
/* Код набирают с цифровой клавиатуры и читают глазами: моноширинный,
   крупный, с разрядкой, чтобы шесть цифр не слипались. */
input.code{font-family:'JBMono',ui-monospace,monospace;font-size:30px;
  letter-spacing:.32em;width:7.5em;padding:10px 12px;text-align:center;
  border:var(--px) solid var(--edge);background:var(--bg);color:var(--ink)}
/* Подтверждение входа: слева робот, текст и кнопка, справа квадрат.
   На телефоне квадрата нет вовсе, и это не экономия места: человек уже
   держит телефон в руках, наводить камеру ему не на что. */
.waitgrid{display:grid;gap:26px;align-items:start;margin:0 auto}
.qrbox{margin:0}
.qrcard{display:inline-block;background:#fff;padding:14px;
  border:var(--px) solid var(--edge);box-shadow:3px 3px 0 var(--shadow)}
/* Квадрат рисуется по сетке модулей: без crispEdges браузер сгладит их
   и телефон перестанет его читать. */
.qrcard svg{display:block;width:200px;height:200px;
  shape-rendering:crispEdges;image-rendering:pixelated}

@media(min-width:40rem){
  /* Две колонки только когда способов правда два. `has` поддержан не
     везде, поэтому по умолчанию колонка одна и широкая, а вторая
     добавляется: так страница с одним способом нигде не окажется
     половинчатой. */
  .ways:has(.way + .way){grid-template-columns:1fr 1fr}
  /* Один способ не должен занимать всю меру: карточка в 46rem выглядит
     пустой. Но и жаться к левому краю ей незачем, поэтому по центру.
     Два способа занимают меру целиком, им есть чем. */
  .ways{max-width:30rem;margin-inline:auto}
  .ways:has(.way + .way){max-width:none;margin-inline:0}
}
/* Квадрат появляется только там, где рядом есть второе устройство.
   Порог выше, чем у карточек: двум колонкам с квадратом нужно больше
   места, чем двум колонкам текста. */
.qrbox{display:none}
@media(min-width:56rem){
  .waitgrid{grid-template-columns:1fr auto}
  .qrbox{display:block}
}
