/* Комментарии тестеров — визуальный стаб.
   Всё из наших источников, ничего не выдумано:
   · цвета/радиусы/типографика — mobile/lib/core/theme/tokens.dart (SoT), сверено построчно
   · композер — mobile/lib/features/assistant/widgets/assistant_composer.dart (геометрия 1:1, без микрофона)
   · аккордеон — backend/app/landing/ea-admin.css (.dt-panel grid-template-rows 0fr↔1fr)
   · пустое состояние — mobile/lib/core/widgets/app_feedback_hero.dart
   · шторка подтверждения — mobile/lib/core/widgets/app_confirm_sheet.dart (confirm КОРАЛЛОВЫЙ, не красный)
   · шрифты — mobile/assets/fonts (рецепт @font-face — landing-pages/assets/styles.css:9-13)
   · иконки — mobile/assets/icons + спрайт админки */

/* ── шрифты (как на лендинге: ttf + font-display swap; woff2 в проекте нет) ── */
@font-face{font-family:'Onest';src:url('fonts/Onest-Regular.ttf') format('truetype');font-weight:400;font-display:swap}
@font-face{font-family:'Onest';src:url('fonts/Onest-Medium.ttf') format('truetype');font-weight:500;font-display:swap}
@font-face{font-family:'Sansation';src:url('fonts/Sansation-Bold.ttf') format('truetype');font-weight:700;font-display:swap}

:root{
  /* AppColors.light — tokens.dart:103-119 */
  --bg:#EFEEE9;              /* background */
  --surface:#FFFFFF;         /* surface */
  --surface-muted:#E8E6E3;   /* surfaceMuted */
  --surface-hover:#E5E2DE;   /* surfaceHoverHalo */
  --outline:#DBD8D2;         /* outline */
  --ink:#1C1B1F;             /* onSurface */
  --ink-muted:#717178;       /* onSurfaceMutedPressed */
  --ink-faint:#9E9DA5;       /* onSurfaceMuted */
  --accent:#BD3E0F;          /* accent */
  --accent-pressed:#AA350A;  /* accentPressed */
  --accent-halo:rgba(189,62,15,.12);  /* accentPressedHalo — 12% */
  --navy:#2B2938;            /* surfaceDark */
  --navy-hover:#3B3948;      /* surfaceDarkHover */
  --on-accent:#FFFFFF;       /* onAccent */
  /* AppStatusColors — tokens.dart:481-490 */
  --pos:#81B52C; --pos-light:#ECF5DA;
  --neg:#D85464; --neg-light:#FFCECF;
  /* AppRadii — tokens.dart:463-507 (+ кнопки 14 / шторка 24 — mobile/CLAUDE.md) */
  --r-card:20px;      /* cardLg */
  --r-btn:14px;
  --r-tile:12px;      /* md */
  --r-composer:26px;  /* композер — жёстко 26 */
  --r-sheet:24px;     /* xl, только верх */
  --pill:100px;
  /* AppSpacing — сетка 4px */
  --sp-xxs:4px; --sp-xs:6px; --sp-sm:8px; --sp-md:12px; --sp-lg:16px; --sp-xl:24px;
  /* AppShadows.fab — Color(0x1F252530) */
  --shadow-fab:0 4px 12px rgba(37,37,48,.12);
  --ease:cubic-bezier(.2,.8,.2,1);
}

*,*::before,*::after{box-sizing:border-box}
*{margin:0}
[hidden]{display:none!important}   /* class display rules must not override */

html{
  -webkit-text-size-adjust:100%;
  overscroll-behavior:none;        /* нет pull-to-refresh и резинового отскока */
}
body{
  background:var(--bg);
  color:var(--ink);
  /* bodyRegular15 — Onest 400 15/24 ls -0.0225 */
  font:400 15px/24px 'Onest',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;
  letter-spacing:-.0225px;
  -webkit-font-smoothing:antialiased;
  overflow-x:clip;                 /* clip, НЕ hidden — hidden делает body скролл-контейнером */
  overscroll-behavior:none;
  touch-action:manipulation;       /* нет double-tap zoom и задержки 300мс */
  -webkit-tap-highlight-color:transparent;
  /* колонка на всю высоту → композер прижат к низу даже когда список короткий,
     и остаётся прилипшим при скролле длинного списка */
  min-height:100svh;
  display:flex;flex-direction:column;
  padding-left:env(safe-area-inset-left);
  padding-right:env(safe-area-inset-right);
}
img{max-width:100%;display:block}
button{font:inherit;cursor:pointer;border:0;background:none;color:inherit}
.sprite{position:absolute;width:0;height:0}
.ic{width:20px;height:20px;flex:none;display:inline-block;vertical-align:middle;fill:currentColor}

/* ── вход ────────────────────────────────────────────────────────────
   AppInput (app_input.dart): h56, r16, padding-x 12, заливка #E8E6E3,
   фокус — заливка #E8E4DA + бордер 2px accent, ошибка — бордер 2px negative.
   AppButton primary·filled·big (app_button.dart): h44, r16, padding-x 16.
   Композиция экрана входа (auth_screen.dart): заголовок →32→ email →12→ пароль
   →(ошибка: 16)→ 24 → CTA. Лейблов над полями нет — только плейсхолдеры. */
.gate{
  flex:1 1 auto;display:flex;align-items:center;justify-content:center;
  padding:24px calc(24px + env(safe-area-inset-left)) 24px calc(24px + env(safe-area-inset-right));
}
.gate-form{width:100%;max-width:380px;display:flex;flex-direction:column}
.gate-title{
  /* h1 — Sansation 700 26/32 ls 0.13, onSurface */
  font:700 26px/32px 'Sansation',sans-serif;letter-spacing:.13px;color:var(--ink);text-align:center;
}
.gate-hint{
  margin-top:var(--sp-sm);text-align:center;
  font:400 14px/20px 'Onest',sans-serif;letter-spacing:.035px;color:var(--ink-muted);
  margin-bottom:32px;   /* заголовочный блок → поля = 32 (auth_screen) */
}
.fieldwrap{position:relative;display:flex}
.fieldwrap + .fieldwrap{margin-top:var(--sp-md)}   /* между полями 12 */
.app-input{
  width:100%;height:56px;border-radius:16px;padding:0 12px;border:0;outline:none;
  background:#E8E6E3;color:var(--navy);   /* _kNormalFill / _kValue */
  /* bodyRegular15 — но 16px: iOS зумит поле <16px (см. композер) */
  font:400 16px/24px 'Onest',sans-serif;letter-spacing:-.0225px;
  transition:background .12s ease-out,box-shadow .12s ease-out;
  caret-color:var(--accent);
}
.app-input::placeholder{color:#717078}   /* _kPlaceholder — НЕ #717178, это разные цвета */
.app-input:hover{background:#E5E2DD}     /* _kHoveredFill */
.app-input:focus{background:#E8E4DA;box-shadow:inset 0 0 0 2px var(--accent)}   /* _kFocusedFill + stroke */
.fieldwrap.bad .app-input{background:#E8E6E3;box-shadow:inset 0 0 0 2px var(--neg)}
.app-input.has-trailing{padding-right:44px}
.input-trailing{
  position:absolute;right:12px;top:50%;transform:translateY(-50%);
  width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;
  color:#717078;
}
.input-trailing .ic{width:24px;height:24px}
/* ошибка — под ОБОИМИ полями, по центру: caption12 в negative */
.gate-err{
  margin-top:var(--sp-lg);text-align:center;
  font:400 12px/16px 'Onest',sans-serif;color:var(--neg);
}
.app-btn{
  margin-top:var(--sp-xl);height:44px;border-radius:16px;padding:0 16px;
  background:var(--accent);color:var(--on-accent);
  /* bodyMedium15 — Onest 500 15/20 ls 0.075 */
  font:500 15px/20px 'Onest',sans-serif;letter-spacing:.075px;
  display:inline-flex;align-items:center;justify-content:center;
  transition:background .12s ease-out;
}
.app-btn:hover{background:#B13B10}          /* _kAccentHovered */
.app-btn:active{background:var(--accent-pressed)}
/* загрузка: кнопка целиком подменяется плашкой со спиннером (как в auth_screen) */
.app-btn.loading{color:transparent;position:relative;pointer-events:none}
.app-btn.loading::after{
  content:'';position:absolute;width:20px;height:20px;border-radius:50%;
  border:2px solid rgba(255,255,255,.35);border-top-color:#fff;
  animation:spin .7s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}
/* затухающая тряска полей при ошибке — канон auth_screen (420ms, амплитуда 8px, 2 периода) */
.shake{animation:shake .42s ease-out}
@keyframes shake{
  0%{transform:translateX(0)}    12.5%{transform:translateX(7px)}
  25%{transform:translateX(0)}   37.5%{transform:translateX(-5px)}
  50%{transform:translateX(0)}   62.5%{transform:translateX(3px)}
  75%{transform:translateX(0)}   87.5%{transform:translateX(-1px)}
  100%{transform:translateX(0)}
}

/* ── каркас ── */
.wrap{
  flex:1 1 auto;width:100%;max-width:720px;margin:0 auto;
  padding:calc(env(safe-area-inset-top) + 22px) 20px 8px;
}
/* пустое состояние центрируется в свободной высоте, а не липнет к заголовку */
.wrap:has(#empty:not([hidden])){display:flex;flex-direction:column}
.wrap:has(#empty:not([hidden])) .empty{flex:1 1 auto;justify-content:center}
.head{margin-bottom:var(--sp-lg)}
.title{
  /* h1 — Sansation 700 26/32 ls 0.13 (канон крупного заголовка, AppScreenTitle) */
  font:700 26px/32px 'Sansation',sans-serif;letter-spacing:.13px;color:var(--navy);
}
.sub{
  /* bodyRegular14 — Onest 400 14/20 ls 0.035 */
  margin-top:var(--sp-sm);font:400 14px/20px 'Onest',sans-serif;letter-spacing:.035px;color:var(--ink-muted);
}

/* ── пустое состояние (AppFeedbackHero: визуал →18px→ h4 →8px→ подзаголовок) ── */
.empty{display:flex;flex-direction:column;align-items:center;text-align:center;padding:40px 32px}
.empty-badge{
  width:80px;height:80px;border-radius:50%;background:var(--surface-muted);
  display:flex;align-items:center;justify-content:center;margin-bottom:18px;
}
.empty-badge .ic{width:44px;height:44px;color:var(--ink-faint)}
.empty-title{font:700 18px/26px 'Sansation',sans-serif;letter-spacing:.09px;color:var(--navy)}
.empty-sub{margin-top:var(--sp-sm);font:400 14px/1.45 'Onest',sans-serif;letter-spacing:.035px;color:var(--ink-muted)}

/* ── лента плашек ── */
.list{display:flex;flex-direction:column;gap:var(--sp-sm);padding-bottom:8px}
.item{
  background:var(--surface);border:1px solid var(--outline);border-radius:var(--r-card);
  overflow:hidden;transition:background .15s var(--ease);
}
.item.open{background:#FBFAF7}

/* свёрнутая строка: [№] первая строка … [фото] [Исправлено] [⌄] */
.item-row{
  display:flex;align-items:center;gap:var(--sp-sm);padding:15px 14px;
  cursor:pointer;user-select:none;-webkit-touch-callout:none;
  transition:background .15s var(--ease);
}
.item-row:hover{background:#FBFAF7}
.item-row:active{background:var(--surface-hover)}
.i-num{flex:none;color:var(--ink-faint);font:400 12px/16px 'Onest',sans-serif}
/* Текст плашки один — свёрнутый обрезан по заполнению, при раскрытии
   разворачивается на месте (дубля «первая строка + тот же текст ниже» нет).
   line-clamp:1 даёт многоточие; max-height анимирует разворот. */
.i-text{
  flex:1 1 auto;min-width:0;
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;
  overflow:hidden;max-height:24px;transition:max-height .3s var(--ease);
  font:400 15px/24px 'Onest',sans-serif;letter-spacing:-.0225px;color:var(--ink);
}
.item.open .i-text{-webkit-line-clamp:unset;max-height:60vh}
/* раскрыто → номер/иконки держатся у верхней строки, а не уезжают в центр */
.item.open .item-row{align-items:flex-start}
.item.open .i-num,.item.open .i-photo,.item.open .i-chip,.item.open .i-exp{margin-top:2px}
.i-photo{flex:none;color:var(--ink-faint)}
.i-photo .ic{width:16px;height:16px}
/* чип «Исправлено» — только терминальный статус; по умолчанию чипа нет */
.i-chip{
  flex:none;display:inline-flex;align-items:center;gap:4px;
  background:var(--pos-light);color:var(--pos);border-radius:var(--pill);padding:4px 10px;
  font:500 12px/16px 'Onest',sans-serif;white-space:nowrap;
}
.i-chip .ic{width:13px;height:13px}
.i-exp{flex:none;display:inline-flex;color:var(--ink-faint);transition:transform .28s var(--ease)}
.i-exp .ic{width:18px;height:18px}
.item.open .i-exp{transform:rotate(180deg);color:var(--ink-muted)}

/* аккордеон — копия механики админки (ea-admin.css:234-238) */
.panel{display:grid;grid-template-rows:0fr;transition:grid-template-rows .3s var(--ease)}
.panel-inner{
  overflow:hidden;min-height:0;opacity:0;transform:translateY(-4px);
  transition:opacity .2s var(--ease),transform .28s var(--ease);
}
.item.open .panel{grid-template-rows:1fr}
.item.open .panel-inner{opacity:1;transform:none}

/* содержимое раскрывашки */
.ed{display:flex;flex-direction:column;gap:14px;padding:2px 14px 14px}
.ed-photos{display:flex;flex-wrap:wrap;gap:var(--sp-sm)}
.ed-photo{
  width:96px;height:96px;border-radius:var(--r-tile);border:1px solid var(--outline);
  overflow:hidden;background:var(--surface-muted);cursor:pointer;padding:0;
}
.ed-photo img{width:100%;height:100%;object-fit:cover;aspect-ratio:1;background:var(--surface-muted)}
.ed-foot{
  display:flex;align-items:center;gap:10px;padding-top:var(--sp-md);border-top:1px solid var(--outline);
}
.ed-meta{font:400 12px/16px 'Onest',sans-serif;color:var(--ink-faint)}
.ed-foot .grow{flex:1}
.ed-del{
  width:36px;height:36px;border-radius:var(--r-tile);color:var(--ink-faint);
  display:inline-flex;align-items:center;justify-content:center;
  transition:background .15s var(--ease),color .15s var(--ease);
}
.ed-del .ic{width:18px;height:18px}
.ed-del:hover{background:var(--neg-light);color:var(--neg)}

/* ── композер (assistant_composer.dart: внешний 16/4/16/10, r26, внутренний T12 R8 B8 L16) ── */
.composer{
  position:sticky;bottom:0;background:var(--bg);
  width:100%;max-width:720px;margin:0 auto;   /* та же колонка, что и лента */
  /* по горизонтали 20, а не 16 из композера ассистента: у нас padding экрана = 20
     (правило дизайн-системы), иначе рамка не совпадает с карточками ленты */
  padding:4px 20px calc(10px + env(safe-area-inset-bottom));
}
.composer-box{background:var(--surface-muted);border-radius:var(--r-composer);padding:12px 8px 8px 16px}
/* Над композером тащат картинку — показываем, что бросать надо сюда.
   Рамка внутренняя (inset), чтобы поле не «прыгало» на пиксель. */
.composer-box.drop-over{box-shadow:inset 0 0 0 2px var(--accent);background:var(--accent-halo)}
.thumbs{display:flex;flex-wrap:wrap;gap:var(--sp-sm);margin:0 8px 10px 0}
.thumb{position:relative;width:64px;height:64px;border-radius:var(--r-tile);overflow:hidden;border:1px solid var(--outline)}
.thumb img{width:100%;height:100%;object-fit:cover;aspect-ratio:1}
.thumb-x{
  position:absolute;top:2px;right:2px;width:20px;height:20px;border-radius:50%;
  background:rgba(43,41,56,.55);color:#fff;display:inline-flex;align-items:center;justify-content:center;
}
.thumb-x .ic{width:12px;height:12px}
.composer-text{
  display:block;width:100%;border:0;background:transparent;outline:none;resize:none;
  margin:0 8px 6px 0;padding:0;color:var(--ink);
  /* ⚠️ 16px, НЕ 15 из токена: iOS зумит страницу при фокусе в поле <16px,
     а maximum-scale/user-scalable Safari игнорирует с iOS 10. Осознанное отступление. */
  font:400 16px/24px 'Onest',sans-serif;letter-spacing:-.0225px;
  max-height:144px;overflow-y:auto;   /* 6 строк × 24 = maxLines: 6 */
}
.composer-text::placeholder{color:var(--ink-faint)}
.composer-row{display:flex;align-items:center}
.composer-row .grow{flex:1}
.c-circle{
  width:44px;height:44px;border-radius:50%;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--surface);color:var(--ink-muted);
  transition:background .15s var(--ease),color .15s var(--ease),transform .12s var(--ease);
}
.c-circle:active{transform:scale(.97)}          /* AppPressable — scale 0.97 */
.c-circle:disabled{color:var(--ink-faint);cursor:default;transform:none}
.c-send.on{background:var(--accent);color:var(--on-accent)}
.c-send.on:active{background:var(--accent-pressed)}

/* ── шторка подтверждения (showAppConfirmSheet) ── */
.scrim{position:fixed;inset:0;background:rgba(43,41,56,.30);z-index:50;opacity:0;transition:opacity .2s var(--ease)}
.scrim.in{opacity:1}
.sheet{
  position:fixed;left:0;right:0;bottom:0;z-index:60;
  background:var(--surface);border-radius:var(--r-sheet) var(--r-sheet) 0 0;
  padding:var(--sp-sm) 20px calc(20px + env(safe-area-inset-bottom));
  transform:translateY(100%);transition:transform .35s var(--ease);
  max-width:720px;margin:0 auto;
}
.sheet.in{transform:none}
.sheet-handle{width:36px;height:4px;border-radius:var(--pill);background:var(--outline);margin:0 auto var(--sp-lg)}
.sheet-body{display:flex;flex-direction:column;gap:var(--sp-sm)}
.sheet-title{font:700 18px/26px 'Sansation',sans-serif;letter-spacing:.09px;color:var(--navy)}
.sheet-msg{font:400 14px/20px 'Onest',sans-serif;letter-spacing:.035px;color:var(--ink-muted)}
.sheet-actions{display:flex;gap:var(--sp-md);margin-top:var(--sp-sm)}
.btn{
  flex:1;border-radius:var(--r-btn);padding:13px 18px;
  font:500 15px/20px 'Onest',sans-serif;letter-spacing:.075px;
  transition:background .15s var(--ease),color .15s var(--ease);
}
/* деструктив = accent, НЕ statusNegative (правило app_confirm_sheet) */
.btn-primary{background:var(--accent);color:var(--on-accent)}
.btn-primary:active{background:var(--accent-pressed)}
.btn-secondary{background:transparent;color:var(--ink);border:1px solid var(--outline)}
.btn-secondary:active{background:var(--surface-hover)}

/* ── просмотр фото ── */
.viewer{
  position:fixed;inset:0;z-index:70;background:rgba(43,41,56,.92);
  display:flex;align-items:center;justify-content:center;padding:24px;
}
.viewer img{max-width:100%;max-height:100%;border-radius:var(--r-tile)}
.viewer-close{
  position:absolute;top:calc(env(safe-area-inset-top) + 12px);right:16px;
  width:44px;height:44px;border-radius:50%;background:rgba(255,255,255,.14);color:#fff;
  display:inline-flex;align-items:center;justify-content:center;
}

/* ── Кнопка установки (в шапке) ────────────────────────────────────
   Показывается только по beforeinstallprompt — на iOS события нет, там
   подсказка «Поделиться → На экран Домой». Установка функциональна, а не
   косметична: только у home-screen PWA Safari не чистит хранилище через 7 дней. */
.head{display:flex;align-items:center;gap:12px}
.install-btn{
  border:1px solid var(--outline);background:var(--surface);color:var(--ink);
  font-family:inherit;font-size:13px;font-weight:600;
  padding:7px 14px;border-radius:var(--pill);cursor:pointer;flex:none;
  transition:background .15s ease,border-color .15s ease;
}
.install-btn:hover{background:var(--surface-hover);border-color:var(--ink-faint)}
.install-btn:active{background:var(--surface-muted)}

/* ── Тост — единственный канал ошибок отправки/удаления ──────────── */
.toast{
  position:fixed;left:50%;bottom:calc(96px + env(safe-area-inset-bottom));
  transform:translate(-50%,8px);z-index:80;
  max-width:min(420px,calc(100vw - 40px));
  background:var(--navy);color:#fff;
  font-size:13.5px;line-height:19px;font-weight:500;
  padding:11px 16px;border-radius:14px;
  box-shadow:0 12px 28px -10px rgba(43,41,56,.5);
  opacity:0;transition:opacity .25s ease,transform .25s ease;pointer-events:none;
}
.toast.in{opacity:1;transform:translate(-50%,0)}

/* Спиннер на кнопке отправки — тот же приём, что у кнопки входа */
.c-send.loading .ic{opacity:0}
.c-send.loading::after{
  content:'';position:absolute;width:16px;height:16px;border-radius:50%;
  border:2px solid rgba(255,255,255,.35);border-top-color:#fff;
  animation:spin .7s linear infinite;
}
.c-send{position:relative}


/* ── Подсказка про установку (iOS) ─────────────────────────────────
   Сидит над композером, не перекрывая его. Показывается один раз: тестер
   закрыл — больше не возвращается (localStorage). На Android не появляется —
   там есть настоящая кнопка по beforeinstallprompt. */
.ioshint{
  position:fixed;left:50%;transform:translateX(-50%);
  bottom:calc(96px + env(safe-area-inset-bottom));z-index:60;
  width:min(420px,calc(100vw - 40px));
  display:flex;align-items:flex-start;gap:10px;
  background:var(--surface);border:1px solid var(--outline);border-radius:14px;
  padding:12px 12px 12px 14px;box-shadow:0 12px 28px -12px rgba(43,41,56,.28);
  animation:hintIn .3s var(--ease);
}
@keyframes hintIn{from{opacity:0;transform:translate(-50%,6px)}to{opacity:1;transform:translate(-50%,0)}}
.ioshint-text{margin:0;font-size:13px;line-height:18px;color:var(--ink);flex:1}
.ioshint-how{color:var(--ink-muted);font-weight:600}
.ioshint-x{
  width:26px;height:26px;flex:none;border:0;border-radius:8px;background:transparent;
  color:var(--ink-faint);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;
}
.ioshint-x .ic{width:14px;height:14px}
.ioshint-x:hover{background:var(--surface-muted);color:var(--ink)}
