/* jay-warm.css -- chat styles (.orb / .jay-panel / .jay-head / .jay-log / ...), ported
 * verbatim from JustAI-WaveCity/engine/theme.mjs -- this is the actual reference design
 * that comments in this file used to just cite, while the real rules here were written
 * fresh for a different markup (.fab/.w-chat) and drifted from it.
 * Ported into wavecity-just-ai 2026-09-22 together with the markup (jayClassic() in
 * jay.mjs) and behavior (jay-warm.client.js -- ported jay-behaviour.mjs).
 *
 * Lens (.w-orb) is a component that already lived in this file (see block below headed
 * 'Jay lens and plate'); the reference design drew the lens with <img src=orb.png>, and
 * here the existing CSS-based .w-orb is used instead, to avoid adding a new binary asset
 * just for one icon.
 */

/* -- Lens (.w-orb) -- carried over from the previous jay-warm.css unchanged -- */
.w-orb{--o:38px;--oa:240,120,36;--ob:146,82,238;--oc:36,178,238;width:var(--o);height:var(--o);flex:none;position:relative;border-radius:50%;overflow:hidden;isolation:isolate;background:radial-gradient(46% 40% at 34% 62%,rgba(var(--oa),1),rgba(var(--oa),0) 66%),radial-gradient(44% 38% at 66% 34%,rgba(var(--ob),1),rgba(var(--ob),0) 66%),radial-gradient(40% 34% at 52% 86%,rgba(var(--oc),.96),rgba(var(--oc),0) 64%),radial-gradient(70% 60% at 50% 50%,rgba(var(--ob),.36),rgba(var(--oa),.28) 60%,transparent 88%);background-size:190% 190%,180% 180%,180% 180%,140% 140%;background-position:22% 68%,74% 26%,50% 92%,50% 50%;filter:saturate(1.16);backdrop-filter:saturate(1.25);-webkit-backdrop-filter:saturate(1.25);box-shadow:inset 0 0 0 1px rgba(255,255,255,.28),inset calc(var(--o)*.04) calc(var(--o)*.05) calc(var(--o)*.1) calc(var(--o)*-.06) rgba(255,255,255,.62),inset calc(var(--o)*-.04) calc(var(--o)*-.06) calc(var(--o)*.12) calc(var(--o)*-.07) rgba(52,24,74,.4),0 calc(var(--o)*.05) calc(var(--o)*.13) calc(var(--o)*-.06) rgba(26,25,23,.26);animation:w-orb-blobs 26s ease-in-out infinite}
/* кромка стекла — тонкое цветное кольцо */
.w-orb::before{content:"";position:absolute;inset:0;border-radius:50%;padding:1px;background:conic-gradient(from 215deg,rgba(255,255,255,.8),rgba(120,190,255,.55) 16%,rgba(178,120,255,.45) 34%,rgba(255,255,255,.06) 50%,rgba(255,170,90,.6) 70%,rgba(255,255,255,.7) 88%,rgba(255,255,255,.8));-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask-composite:exclude;animation:none;z-index:3}
/* узкий серп и тёплый отскок снизу */
.w-orb::after{content:"";position:absolute;inset:0;border-radius:50%;background:radial-gradient(22% 15% at 28% 17%,rgba(255,255,255,.8),rgba(255,255,255,.08) 62%,transparent 82%),radial-gradient(58% 30% at 52% 106%,rgba(255,196,138,.3),transparent 74%);animation:none;z-index:4}
@keyframes w-orb-blobs{0%,100%{background-position:22% 68%,74% 26%,50% 92%,50% 50%}33%{background-position:58% 42%,44% 62%,28% 74%,50% 50%}66%{background-position:78% 24%,26% 76%,70% 40%,50% 50%}}

/* ⛔ АЛЬТЕРНАТИВНЫЙ ОБРАЗ «СФЕРА» — ПО ЗАПРОСУ, НЕ ОСНОВНОЙ. Слово фаундера 01.09, поздний
   вечер, дословно: «Ты не тот орб взял за основу… Было раньше — три переливающихся орба
   янтарно-мятно-фиолетовых оттенках… Сине-фиолетовый оставь как альтернативный вариант
   по запросу».

   Я перекрасил основной орб в эту сферу утром 01.09 по передаче ветки A — передача
   оказалась неверной (её разбор: decisions/26.09.01-a-orb-perelivayushchiysya-osnovnoy.md).
   ==Работа не выброшена: сине-фиолетовая сфера — знак из SVG и ДС презентаций, и она
   нужна там, где просят именно его.== Ставится классом `is-sfera`, значения дословно
   из эталона ДС. Основной образ — переливающийся, он выше. */
   «орб делаем таким как в svg» (решение 26.09.01-a-orb-kak-v-svg-i-ds-bez-sluzhebnogo).

   со знаком, который теперь стоит в ДС презентаций и в медиатеке. ==Знак, который на сайте
   и в презентации выглядит по-разному, перестаёт быть знаком.==

   Значения взяты ДОСЛОВНО из эталона ДС (`docs/site/ds-prezentacii-web.html`), а не подобраны
   на глаз: тот же градиент, тот же блик, то же дышащее кольцо. Подбор «похожего» дал бы
   второй источник правды, и они разъехались бы на первой правке одного из двух. */
.w-orb.is-sfera{--o:38px;--jay-0:#9DD8FF;--jay-1:#5BB8FF;--jay-2:#8B5BFF;width:var(--o);height:var(--o);flex:none;position:relative;border-radius:50%;background:radial-gradient(130% 130% at 34% 28%,var(--jay-0),var(--jay-1) 46%,var(--jay-2) 100%);box-shadow:inset 0 0 0 1px rgba(255,255,255,.3),inset calc(var(--o)*.04) calc(var(--o)*.05) calc(var(--o)*.1) calc(var(--o)*-.06) rgba(255,255,255,.62),inset calc(var(--o)*-.04) calc(var(--o)*-.06) calc(var(--o)*.12) calc(var(--o)*-.07) rgba(52,24,74,.4),0 calc(var(--o)*.05) calc(var(--o)*.13) calc(var(--o)*-.06) rgba(26,25,23,.26)}
/* белый блик — НЕ переключается по теме: он часть знака, а не оформления */
.w-orb.is-sfera::before{content:"";position:absolute;left:22%;top:10%;width:40%;height:26%;border-radius:50%;background:radial-gradient(closest-side,rgba(255,255,255,.85),rgba(255,255,255,0));transform:rotate(-24deg);z-index:2}
/* дышащее кольцо снаружи сферы */
.w-orb.is-sfera::after{content:"";position:absolute;inset:-12%;border-radius:50%;border:1px solid var(--jay-2);opacity:.3}
@media(prefers-reduced-motion:no-preference){.w-orb.is-sfera::after{animation:w-orb-dyshit 5.6s ease-in-out infinite}}
@keyframes w-orb-dyshit{0%,100%{opacity:.3;transform:scale(1)}50%{opacity:.1;transform:scale(1.07)}}
/* опция · широкие поля цвета: границ нет вовсе, свет стоит широкими полями */
.w-orb.is-fields{background:radial-gradient(58% 44% at 32% 64%,rgba(232,124,44,.98),rgba(232,124,44,.2) 62%,transparent 80%),radial-gradient(54% 42% at 70% 34%,rgba(150,92,232,.98),rgba(150,92,232,.18) 62%,transparent 80%),radial-gradient(46% 34% at 54% 92%,rgba(52,190,232,.9),transparent 76%),radial-gradient(40% 30% at 22% 26%,rgba(120,240,205,.7),transparent 78%);background-size:200% 200%,190% 190%,180% 180%,180% 180%;background-position:18% 70%,78% 24%,52% 94%,20% 24%;animation-duration:38s}
/* опция · ленты: три широкие полосы идут поперёк шара под разными углами */
.w-orb.is-ribbons{background:linear-gradient(64deg,transparent 0 22%,rgba(238,116,28,.95) 34%,rgba(255,176,92,.85) 46%,rgba(238,116,28,.9) 56%,transparent 70%),linear-gradient(146deg,transparent 0 26%,rgba(148,78,238,.92) 38%,rgba(196,146,255,.8) 50%,rgba(148,78,238,.88) 60%,transparent 74%),linear-gradient(-38deg,transparent 0 30%,rgba(30,172,240,.85) 42%,rgba(132,234,244,.72) 50%,rgba(30,172,240,.8) 58%,transparent 72%),radial-gradient(70% 60% at 50% 50%,rgba(146,82,238,.22),rgba(240,120,36,.18) 62%,transparent 88%);background-size:260% 260%,240% 240%,280% 280%,140% 140%;background-position:20% 30%,74% 66%,46% 80%,50% 50%;animation:w-orb-ribbons 32s ease-in-out infinite}
@keyframes w-orb-ribbons{0%,100%{background-position:20% 30%,74% 66%,46% 80%,50% 50%}50%{background-position:62% 62%,34% 30%,74% 34%,50% 50%}}
/* опция · ток: волны-кривые с гало внутри шара. Нужна разметка:
   <div class="w-orb is-flow"><svg class="w-orb__wv" viewBox="0 0 100 100" preserveAspectRatio="none">4 path.p1…p4</svg><i class="w-orb__fr"></i></div>
   Градиенты #gwA…#gwD объявляются один раз в скрытом svg на странице. */
.w-orb.is-flow{perspective:calc(var(--o)*2.6);background:radial-gradient(58% 50% at 30% 62%,rgba(240,118,26,.36),transparent 76%),radial-gradient(56% 48% at 70% 34%,rgba(146,78,240,.36),transparent 76%),radial-gradient(50% 44% at 52% 88%,rgba(28,186,214,.3),transparent 74%);animation:none}
.w-orb__wv{position:absolute;inset:-14%;width:128%;height:128%;filter:blur(calc(var(--o)*.012));z-index:1;transform-style:preserve-3d;animation:w-fl-turn 29s ease-in-out infinite}
.w-orb__wv path{fill:none;stroke-linecap:round}
.w-orb__wv .p1{stroke:url(#gwA);filter:drop-shadow(0 0 calc(var(--o)*.05) rgba(240,118,26,.5));animation:w-fl-a 16s ease-in-out infinite}
.w-orb__wv .p2{stroke:url(#gwB);filter:drop-shadow(0 0 calc(var(--o)*.05) rgba(150,80,242,.5));animation:w-fl-b 21s ease-in-out infinite}
.w-orb__wv .p3{stroke:url(#gwC);filter:drop-shadow(0 0 calc(var(--o)*.045) rgba(30,186,220,.46));animation:w-fl-c 27s ease-in-out infinite}
.w-orb__wv .p4{stroke:url(#gwD);filter:drop-shadow(0 0 calc(var(--o)*.04) rgba(255,186,104,.44));animation:w-fl-d 33s ease-in-out infinite}
.w-orb__fr{position:absolute;inset:0;border-radius:50%;background:linear-gradient(180deg,rgba(255,255,255,.26) 0 14%,rgba(255,255,255,.1) 26%,transparent 38% 62%,rgba(255,255,255,.08) 74%,rgba(255,246,236,.2) 100%);backdrop-filter:blur(calc(var(--o)*.05)) saturate(1.1);-webkit-backdrop-filter:blur(calc(var(--o)*.05)) saturate(1.1);-webkit-mask:linear-gradient(180deg,#000 0 20%,rgba(0,0,0,.35) 32%,transparent 42% 58%,rgba(0,0,0,.3) 70%,#000 84% 100%);mask:linear-gradient(180deg,#000 0 20%,rgba(0,0,0,.35) 32%,transparent 42% 58%,rgba(0,0,0,.3) 70%,#000 84% 100%);z-index:2}
@keyframes w-fl-turn{0%,100%{transform:rotate3d(1,.3,0,0deg) rotate(0)}28%{transform:rotate3d(1,.4,.08,28deg) rotate(9deg)}52%{transform:rotate3d(.7,1,.15,-24deg) rotate(-7deg)}76%{transform:rotate3d(1,.2,-.12,18deg) rotate(-14deg)}}
@keyframes w-fl-a{0%,100%{d:path("M-12,58 C14,30 34,78 58,48 C76,24 92,52 112,38");stroke-width:11}50%{d:path("M-12,44 C18,74 38,24 60,62 C80,92 94,38 112,56");stroke-width:17}}
@keyframes w-fl-b{0%,100%{d:path("M-12,30 C12,64 34,20 56,58 C74,90 92,44 112,68");stroke-width:10}50%{d:path("M-12,46 C16,18 36,66 58,32 C78,6 94,58 112,36");stroke-width:15}}
@keyframes w-fl-c{0%,100%{d:path("M-12,80 C14,52 36,96 60,70 C80,48 96,82 112,60");stroke-width:8}50%{d:path("M-12,66 C18,92 38,50 62,84 C82,108 96,60 112,80");stroke-width:13}}
@keyframes w-fl-d{0%,100%{d:path("M-12,14 C16,44 38,2 60,32 C78,56 96,16 112,42");stroke-width:7}50%{d:path("M-12,26 C14,-2 36,42 58,12 C80,-14 94,34 112,10");stroke-width:12}}
@media(prefers-reduced-motion:reduce){.w-orb__wv,.w-orb__wv path{animation:none}.w-orb__wv path{stroke-width:12}}
/* опция · прежний образ: фиолетово-синее стекло с проходящим бликом */
.w-orb.is-legacy{--oa:150,110,214;--ob:79,179,234;--oc:186,158,236;background:radial-gradient(66% 60% at 26% 70%,rgba(var(--oa),.5),rgba(var(--oa),.14) 58%,rgba(var(--oa),0) 78%),radial-gradient(62% 58% at 76% 30%,rgba(var(--ob),.5),rgba(var(--ob),.14) 58%,rgba(var(--ob),0) 78%),radial-gradient(48% 44% at 54% 102%,rgba(var(--oc),.7),rgba(var(--oc),0) 72%),linear-gradient(152deg,#C6ADEF,#7FC7EE);background-size:auto;background-position:0 0;filter:none;animation:none;box-shadow:inset 0 0 0 1px rgba(255,255,255,.5),inset calc(var(--o)*.08) calc(var(--o)*.09) calc(var(--o)*.21) calc(var(--o)*-.11) rgba(255,255,255,1),inset calc(var(--o)*-.09) calc(var(--o)*-.12) calc(var(--o)*.27) calc(var(--o)*-.15) rgba(52,24,74,.9),0 calc(var(--o)*.08) calc(var(--o)*.24) calc(var(--o)*-.09) rgba(198,173,239,.6),0 calc(var(--o)*.03) calc(var(--o)*.09) calc(var(--o)*-.06) rgba(26,25,23,.4)}
.w-orb.is-legacy::before{inset:-22%;padding:0;border-radius:50%;background:radial-gradient(circle at 34% 50%,rgba(var(--oa),.98),rgba(var(--oa),0) 40%),radial-gradient(circle at 66% 50%,rgba(var(--ob),.96),rgba(var(--ob),0) 42%);-webkit-mask:none;mask:none;animation:w-orb-drift 28s linear infinite}
.w-orb.is-legacy::after{background:linear-gradient(100deg,rgba(255,255,255,0) 36%,rgba(255,255,255,.4) 46%,rgba(255,255,255,0) 56%);animation:w-orb-sweep 12s ease-in-out infinite}
.w-orb.is-sm{--o:24px}
.w-orb.is-md{--o:46px}
.w-orb.is-lg{--o:66px}
.w-orb.is-xl{--o:104px}
/* «Отвечает» — оба слоя основного орба ускоряются; у альтернативной сферы это ускоряет
   дыхание кольца. Строку про `::before` я снял утром как «мёртвую» — она была мёртвой
   ровно у сине-фиолетовой сферы и жива у основного образа, куда мы вернулись.
   ==Правило, снятое по одному образу, нельзя снимать во всём слое: у соседнего образа
   тот же селектор работает.== */
.w-orb.is-answering::before{animation-duration:9s}
.w-orb.is-answering::after{animation-duration:3.4s}
.w-orb.is-offline{filter:saturate(.16);box-shadow:inset 0 0 0 1px rgba(255,255,255,.34),inset 4px 5px 12px -7px rgba(255,255,255,.8),0 2px 6px -4px rgba(26,25,23,.35)}
.w-orb.is-offline::before{animation:none;opacity:.5}
.w-orb.is-offline::after{animation:none;opacity:.25}
@keyframes w-orb-drift{to{transform:rotate(360deg)}}
@keyframes w-orb-sweep{0%{transform:translateX(-125%)}50%{transform:translateX(125%)}100%{transform:translateX(-125%)}}


/* -- .orb / .jay-panel / ... -- verbatim from theme.mjs -- */
.orb{position:fixed;right:24px;bottom:24px;z-index:50;display:flex;align-items:center;gap:10px;
  padding:8px 18px 8px 8px;border-radius:var(--r-pill);
  border:1px solid var(--line);box-shadow:var(--shadow-hover);
  font-size:14px;color:var(--ink2);cursor:pointer;background:var(--surface)}
.orb:hover{border-color:var(--line-strong);text-decoration:none;color:var(--ink)}
.orb[data-state="silent"]{opacity:.55;filter:saturate(.3) brightness(.94);cursor:default}
.orb[data-state="silent"] .orb-label{color:var(--muted)}
.jay .orb{font:inherit;font-size:14px}

/* ── панель Jay: свёрнутое состояние как часть каркаса ─────────────────── */
.jay-panel{position:fixed;right:24px;bottom:24px;z-index:51;width:380px;max-width:calc(100vw - 32px);
  max-height:min(620px,calc(100vh - 48px));display:flex;flex-direction:column;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r-panel);box-shadow:var(--shadow-float);
  overflow:hidden}
.jay-head{display:flex;align-items:center;gap:11px;padding:14px 16px;border-bottom:1px solid var(--line-soft)}
/* Имя забирает всё свободное место — значит ВСЁ, что правее, стоит справа независимо от того,
   видно ли колесико. Прежде вправо толкали сами кнопки, и стоило одной из них скрыться, как
   вторая уезжала к центру: расположение зависело от состояния соседа. */
.jay-head>div{margin-right:auto;min-width:0}
.jay-head b{display:block;font-size:15px;line-height:1.2}
.jay-head span{font-size:12px;color:var(--muted)}
.jay-close{margin-left:auto;border:0;background:none;font-size:22px;line-height:1;color:var(--muted);
  cursor:pointer;padding:2px 6px;border-radius:var(--r-s)}
.jay-close:hover{background:var(--surface-2);color:var(--ink)}
/* Прокрутка — на разговоре целиком. Единственный гибкий блок панели: всё остальное имеет
   свою высоту, и если гибкого нет, лишнее уходит под нижний край. «min-height:0» здесь не
   украшение — без него flex-элемент отказывается ужиматься ниже содержимого. */
.jay-scroll{flex:1 1 auto;min-height:0;overflow-y:auto;display:flex;flex-direction:column}
.jay-log{padding:16px;display:flex;flex-direction:column;gap:10px;flex:0 0 auto}
.jay-msg{max-width:86%;padding:9px 13px;border-radius:var(--r-l);font-size:14.5px;line-height:1.45}
.jay-msg.from-jay{background:var(--surface-2);color:var(--ink2);border-bottom-left-radius:var(--r-s)}
.jay-msg.from-me{background:var(--blue);color:var(--on-blue);align-self:flex-end;border-bottom-right-radius:var(--r-s)}


/* Подсказки Jay — ВНУТРИ её бабла, а не отдельным блоком под разговором.
   Замечание фаундера: вопрос, стоящий вне бабла, визуально не её вопрос, и человек читает
   его как анкету рядом с диалогом, а не как продолжение разговора.
   Это реплики ЧЕЛОВЕКА, поэтому и выглядят как то, что он мог бы сказать: светлые, лёгкие,
   без веса кнопки-действия. Кнопка действия у нас одна и живёт в карточке предложения. */
/* Откуда ответ. Тише самого ответа на два шага: это сноска, а не часть реплики.
   Человек читает её, когда усомнился, — и не спотыкается о неё, когда не усомнился. */
.jay-from{margin:6px 0 0;font-size:11.5px;line-height:1.35;color:var(--muted)}

.jay-hints{display:flex;flex-wrap:wrap;gap:6px;margin:9px 0 1px}
.jay-hints .chip{font-size:12.5px;padding:5px 11px;background:var(--bg);border:1px solid var(--line)}
.jay-hints .chip:hover{border-color:var(--blue);color:var(--blue)}
.jay-quick{padding:0 16px 14px;display:flex;flex-wrap:wrap;gap:7px}
/* Свёрнутые фильтры. Плитка видна сразу — панель управления материалами не должна стоять
   между человеком и материалами. */
.filters-fold{margin:0 0 4px}
.filters-fold>summary{cursor:pointer;list-style:none;display:inline-flex;align-items:baseline;gap:9px;
  padding:7px 14px;border:1px solid var(--line);border-radius:99px;font-size:13.5px;color:var(--ink2)}
.filters-fold>summary::-webkit-details-marker{display:none}
.filters-fold>summary:hover{border-color:var(--ink3)}
.filters-fold>summary:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.filters-fold[open]>summary{margin-bottom:12px}
.fold-hint{font-size:11.5px;color:var(--muted)}
.jay-ask{width:100%;margin:0 0 3px;font-size:12.5px;color:var(--muted)}
/* Выход из списка подсказок. Стоит тихо и последним: это не призыв, а снятая безысходность. */
.jay-or{width:100%;margin:6px 0 0;font-size:11.5px;line-height:1.4;color:var(--muted)}
.jay-quick .chip{font-size:12.5px;padding:5px 11px;cursor:pointer;font-family:var(--sans)}
/* Случай из работы — основной текст ценности, а не сноска под ней. Тринадцатым кеглем
   он читался как примечание к заголовку; обещание страницы при этом ровно обратное. */
.val-story{margin:0;font-size:18px;line-height:1.6;color:var(--ink)}
.val.wide .val-story{font-size:19px}
.val-pending{display:inline-block;font-size:12px;color:var(--muted)}
.jay-foot{padding:12px 16px;border-top:1px solid var(--line-soft);background:var(--surface-warm)}
.jay-foot p{margin:0;font-size:11.5px;line-height:1.45;color:var(--muted)}

/* Поле разговора. Строится скриптом вместе со всей Jay: поле, которое молчит в ответ, --
   обещание, которое некому исполнить. */
.jay-ask-form{display:flex;gap:7px;margin:0 0 10px}
.jay-ask-form input{flex:1;min-width:0;padding:9px 13px;border:1px solid var(--line);
  border-radius:99px;font:inherit;font-size:13.5px;background:var(--surface)}
.jay-ask-form input:focus{outline:2px solid var(--focus);outline-offset:1px;border-color:transparent}
.jay-send{flex:0 0 auto;width:36px;height:36px;border:0;border-radius:50%;background:var(--blue);
  color:var(--on-blue);font-size:16px;line-height:1;cursor:pointer}
.jay-send:hover{filter:brightness(1.08)}
/* Ожидание ответа. Поле гаснет — но этого мало: замер на живом шлюзе дал 8–11 секунд на
   реплику, потому что модель успевает подумать, и всё это время в разговоре не происходило
   НИЧЕГО. Тишина в переписке неотличима от поломки, а закрывший панель уже не вернётся.
   Поэтому ожидание стоит там же, где появится ответ, — следующей строкой разговора.
   Спиннера поверх текста по-прежнему нет: он перекрыл бы то, что человек читает. */
.jay-ask-form.waiting input{opacity:.55}
.jay-ask-form.waiting .jay-send{opacity:.45;pointer-events:none}
.jay-think{display:inline-flex;gap:5px;align-items:center;min-height:20px}
.jay-think i{width:6px;height:6px;border-radius:50%;background:var(--text-2,#8B91A1);
  animation:jay-think 1.25s ease-in-out infinite}
.jay-think i:nth-child(2){animation-delay:.18s}
.jay-think i:nth-child(3){animation-delay:.36s}
/* ЧТО JAY ДЕЛАЕТ ПРЯМО СЕЙЧАС — приходит потоком по ходу. Точки говорили «идёт работа» и не
   говорили КАКАЯ: восемь секунд одинаковых точек неотличимы от зависания. Подпись пустая, пока
   нечего сказать, — margin в :empty не съедается, поэтому его снимаем явно. */
.jay-think em[data-think-cap]{font-style:normal;font-size:12px;line-height:1.3;
  color:var(--muted,#6C6862);margin-left:4px}
.jay-think em[data-think-cap]:empty{margin-left:0}
/* ЗНАЧОК «ЕСТЬ СООБЩЕНИЕ» на свёрнутом агенте — единственный проактивный исход на сайте.
   Панель сама не открывается никогда: право на диалог требует сообщения, которое теряет смысл,
   если прочитать его позже, а таких здесь нет. Точка не мигает и не прыгает: она сообщает, а не
   требует. Внимание человек отдаёт сам. */
/* ⚠️ ЗДЕСЬ СТОЯЛО правило, дававшее овалу position:relative, — и оно СБИВАЛО ЕГО В ЛЕВЫЙ
   КРАЙ ЭКРАНА. Заводили его ради контекста для точки, но овал выше по файлу уже fixed, а
   fixed сам по себе такой контекст создаёт. Зато relative, стоящий ниже, перебивал fixed
   целиком: right:24px переставал означать «24 от правого края окна» и начинал означать
   «сдвинуть на 24 влево от своего места в потоке». Овал уезжал к левому краю подвала.
   Нашёл фаундер глазами: «спросить Jay уехало почему-то влево». */
.orb.has-news::after{content:"";position:absolute;top:2px;right:2px;width:10px;height:10px;
  border-radius:50%;background:var(--amber,#B85A2B);box-shadow:0 0 0 2px var(--bg,#FAF9F6)}
@media (prefers-reduced-motion:no-preference){
  .orb.has-news::after{animation:jay-news .4s ease-out}
}
@keyframes jay-news{from{transform:scale(.4);opacity:0}to{transform:scale(1);opacity:1}}
@keyframes jay-think{0%,60%,100%{opacity:.28;transform:translateY(0)}
  30%{opacity:.9;transform:translateY(-3px)}}
/* Кому анимация мешает — тот видит спокойную точку, а не прыгающую. Состояние остаётся
   видимым: убирать признак ожидания вместе с анимацией значило бы вернуть тишину. */
@media (prefers-reduced-motion:reduce){.jay-think i{animation:none;opacity:.55}}

/* Карточка «что я о вас помню». Спокойная, свёрнутая, всегда достижимая — и с крестиком
   у каждой строки. Правило не про закон о данных, а про доверие: невидимая память пугает,
   видимая успокаивает. Поэтому она не прячется в настройках и не открывается сама. */
.jay-mem{border-top:1px solid var(--line-soft)}

/* КОЛЕСИКО В ШАПКЕ ПАНЕЛИ — решение фаундера 02.08: карточка памяти уходит с первого экрана
   в одно нажатие. Не прячется: значок стоит в шапке рядом с закрытием, у него есть подпись
   для экранного диктора и заголовок со счётчиком при наведении.

   Скрыт, пока помнить нечего, — значок настроек, за которым пусто, обещает несуществующее.
   Размер тот же, что у крестика: два соседних управляющих элемента разного кегля читаются
   как разные по важности, а они равны. */
.jay-gear{width:26px;height:26px;display:grid;place-items:center;
  background:none;border:0;cursor:pointer;color:var(--muted);border-radius:8px}
.jay-gear svg{width:17px;height:17px;fill:currentColor}
.jay-gear:hover{color:var(--ink2);background:var(--surface-2)}
.jay-gear.on{color:var(--blue)}
.jay-gear:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
/* Крестик стоял последним и держался на автоматическом левом отступе. Теперь этот отступ у
   колесика, иначе оба уехали бы вправо вплотную. */
/* Крестик стоит рядом с колесиком в правом углу: вправо их толкает имя, а не они сами. */
.jay-head .jay-close{margin-left:0}
/* У памяти есть потолок высоты: двенадцать фактов и десять прочитанных материалов — это
   разрешённый максимум, и он не должен выдавливать разговор из панели. */
.jay-mem-body{padding:0 16px 12px;max-height:min(230px,30vh);overflow-y:auto}
.jay-mem-list{list-style:none;margin:0 0 10px;padding:0;display:flex;flex-direction:column;gap:1px}
.jay-mem-list li{display:flex;align-items:baseline;gap:8px;justify-content:space-between;
  padding:6px 0;border-bottom:1px solid var(--line-soft);font-size:12.5px;line-height:1.4;color:var(--ink2)}
.jay-mem-list li:last-child{border-bottom:0}
.jay-mem-list b{font-weight:400;color:var(--muted);margin-right:4px}
/* Шапка карточки памяти: заголовок + крестик, который СВОРАЧИВАЕТ карточку (не удаляет).
   Отделён от корзин у пунктов, чтобы «закрыть карточку» и «удалить факт» не путались. */
.jay-mem-head{display:flex;align-items:center;justify-content:space-between;
  padding:2px 0 8px;margin-bottom:2px;border-bottom:1px solid var(--line-soft)}
.jay-mem-title{font-size:12px;font-weight:600;color:var(--muted)}
.jay-mem-close{width:24px;height:24px;border:0;background:none;cursor:pointer;font-size:17px;
  line-height:1;color:var(--muted);border-radius:7px}
.jay-mem-close:hover{background:var(--surface-2);color:var(--ink2)}
/* Иконка корзины у пункта — «удалить этот факт». Приглушённая, краснеет на наведении:
   удаление — действие, и оно должно читаться как удаление, а не как «закрыть». */
.jay-mem-x{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:24px;height:24px;border:0;background:none;cursor:pointer;color:var(--muted);border-radius:7px}
.jay-mem-x svg{display:block}
.jay-mem-x:hover{background:var(--surface-2);color:var(--danger,#b4483c)}
.jay-mem-all{background:none;border:1px solid var(--line);border-radius:99px;padding:5px 12px;
  font:inherit;font-size:12px;color:var(--muted);cursor:pointer}
.jay-mem-all:hover{border-color:var(--ink3);color:var(--ink2)}
.jay-mem-note{margin:9px 0 0;font-size:11px;line-height:1.45;color:var(--muted)}

/* УПРАВЛЕНИЕ УЧЁТКОЙ — «Выйти» и, ОТДЕЛЬНО и КРАСНЫМ, удаление. Разные действия обязаны
   выглядеть по-разному: выход обычной кнопкой, удаление — мельче, приглушённо-красным, с
   отступом сверху, чтобы палец не попал по нему случайно (слово фаундера 08.08). */
.jay-acc{display:flex;flex-direction:column;align-items:flex-start;gap:8px;margin-top:4px}
.jay-acc-who{margin:0;font-size:11px;color:var(--muted)}
/* Граница выхода: выход из Jay Pass не гасит сессии продуктов, и это сказано словами
   (решение фаундера 09.08). Тон приглушённый — это уточнение, а не предупреждение. */
.jay-acc-note{margin:8px 0 0;font-size:10.5px;line-height:1.45;color:var(--muted);opacity:.85}
.jay-acc-out{background:none;border:1px solid var(--line);border-radius:99px;padding:5px 14px;
  font:inherit;font-size:12px;color:var(--muted);cursor:pointer}
.jay-acc-out:hover{border-color:var(--ink3);color:var(--ink2)}
.jay-acc-del{margin-top:10px;background:none;border:0;padding:2px 0;font:inherit;font-size:11px;
  color:var(--danger,#b4483c);opacity:.72;cursor:pointer;text-align:left}
.jay-acc-del:hover{opacity:1;text-decoration:underline}

/* КАРТОЧКА ВХОДА — типизированный элемент, состав рисует клиент, не модель. Живёт над полем
   ввода, как карточка памяти; поле кода держит секрет вне ленты разговора. */
.jay-login{border-top:1px solid var(--line-soft);padding:12px 16px}
.jay-login-body{display:flex;flex-direction:column;gap:8px}
/* Шапка карточки: заголовок слева, крестик в УГЛУ справа — он закрывает всю карточку,
   а не относится к кнопке действия под ним. */
.jay-login-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:2px}
.jay-login-title{font-size:12px;font-weight:600;color:var(--muted)}
.jay-login-in{width:100%;box-sizing:border-box;border:1px solid var(--line);border-radius:10px;
  padding:9px 11px;font:inherit;font-size:13px;color:var(--ink2);background:var(--surface)}
.jay-login-in:focus-visible{outline:2px solid var(--blue);outline-offset:1px}
.jay-login-shared{display:flex;align-items:center;gap:7px;font-size:11.5px;color:var(--muted)}
.jay-login-row{display:flex;align-items:center;gap:8px}
.jay-login-go{background:var(--blue);border:0;border-radius:99px;padding:7px 16px;
  font:inherit;font-size:12.5px;color:var(--on-blue);cursor:pointer}
.jay-login-go:disabled{opacity:.55;cursor:default}
.jay-login-x{width:26px;height:26px;border:0;background:none;font-size:17px;line-height:1;
  color:var(--muted);cursor:pointer;border-radius:8px}
.jay-login-x:hover{background:var(--surface-2);color:var(--ink2)}
.jay-login-note{margin:0;font-size:11px;line-height:1.45;color:var(--muted)}
/* Соцвход (этап 2, пока мок): под кнопкой почты, второстепенным рядом. */
.jay-login-sso{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.jay-login-or{font-size:11px;color:var(--muted)}
.jay-login-prov{background:none;border:1px solid var(--line);border-radius:99px;padding:5px 12px;
  font:inherit;font-size:12px;color:var(--muted);cursor:pointer}
.jay-login-prov:hover{border-color:var(--ink3);color:var(--ink2)}
/* «Войти» — в шапке панели у анонима и в настройках памяти. Тихая, не кричит.
   Вправо её толкает имя (.jay-head>div{margin-right:auto}) — свой margin не нужен. */
.jay-signin{background:none;border:1px solid var(--line);border-radius:99px;
  padding:4px 12px;font:inherit;font-size:12px;color:var(--muted);cursor:pointer}
.jay-signin:hover{border-color:var(--ink3);color:var(--ink2)}
/* «Наполнение» — переключатель режима, виден только тому, у кого есть право. Форма та же
   пилюля, что у «Войти»: это ровно такая же тихая кнопка состояния, а не действие над
   разговором. Включённое положение берёт синий — цвет роли «контекст», а не акцентную
   терракоту: режим сообщает, ГДЕ мы, а не требует внимания. */
.jay-build{background:none;border:1px solid var(--line);border-radius:99px;
  padding:4px 12px;font:inherit;font-size:12px;color:var(--muted);cursor:pointer}
.jay-build:hover{border-color:var(--ink3);color:var(--ink2)}
.jay-build.on{border-color:var(--blue);color:var(--blue);background:var(--blue-soft)}
.jay-build:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
/* «Начать заново» — круглая, размером с шестерёнку, рядом с ней: оба действия про сам
   разговор, а не про его содержание. Знак вместо слова намеренно: слово «заново» рядом с
   «Наполнение» читалось бы как ещё один режим. */
.jay-again{width:26px;height:26px;display:grid;place-items:center;font:inherit;font-size:15px;
  line-height:1;background:none;border:0;border-radius:50%;color:var(--muted);cursor:pointer}
.jay-again:hover{color:var(--ink2);background:var(--surface-2)}
.jay-again:disabled{opacity:.45;cursor:default}
.jay-again:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.jay-mem-in{background:none;border:1px solid var(--line);border-radius:99px;padding:5px 12px;
  font:inherit;font-size:12px;color:var(--muted);cursor:pointer;margin-right:8px}
.jay-mem-in:hover{border-color:var(--ink3);color:var(--ink2)}
/* Сообщение о сбое связи: видно, но тише реплики — это не слова Jay, а состояние канала.
   В разговоре не сохраняется и исчезает со следующим удачным ходом. Значок ⚠ (вариант D,
   jay-no-response-conditions.md) отделяет его от обычной реплики ещё и визуально, не только
   курсивом. */
.jay-fail{opacity:.72;font-style:italic}
.jay-fail::before{content:'⚠ ';font-style:normal}

/* Законное «Jay нечего добавить» (решение модели/исполнителя, не сбой, см. jay-warm.client.js
   ::say()/текстМолчания()) — та же лёгкая, несохраняемая подача, что у .jay-fail, но БЕЗ
   значка тревоги: это не поломка, пугать им не нужно. 2026-10-26: добавлено вместе с правилом
   «молчания быть не должно ни при каких условиях». */
.jay-note{opacity:.72;font-style:italic}

/* Предложение — единственный мост от агента к действию. Ничего не происходит,
   пока человек не нажал: молчаливая перестановка читается как угроза контролю. */
.jay-proposal{margin:0 16px 12px;padding:13px 15px;border:1px solid var(--blue-tint);
  background:var(--blue-soft);border-radius:var(--r-l)}
.jay-proposal p{margin:0 0 11px;font-size:13.5px;line-height:1.45;color:var(--ink2)}
.jay-proposal-act{display:flex;gap:8px}
.jay-proposal .btn{font-size:13px;padding:7px 14px}

/* Выбор из нескольких продуктов. Каждое различие стоит РЯДОМ со своей кнопкой: читать
   различия отдельно от выбора неудобно, а в общий текст реплики три различия не помещаются.
   Кнопки в столбец, а не в ряд, — подписи здесь длиннее «Да, покажите» и в ряд не встают. */
.jay-choice-opt{margin:0 0 10px;padding:0 0 10px;border-bottom:1px solid var(--blue-tint)}
.jay-choice-opt:last-of-type{border-bottom:0}
.jay-choice-opt p{margin:0 0 8px}
.jay-choice-opt .btn{width:100%;justify-content:center}

/* Подсветка НЕ двигает прокрутку — она только помечает. */
.jay-lit{outline:2px solid var(--focus);outline-offset:4px;border-radius:var(--r-m);
  animation:jay-pulse 2.4s ease-out}
@keyframes jay-pulse{0%{outline-color:var(--focus)}100%{outline-color:transparent}}
@media (prefers-reduced-motion:reduce){.jay-lit{animation:none}}

/* Mobile layout (ported from @media (max-width:680px) in theme.mjs) */
@media (max-width:680px){
  .orb{padding:10px 18px 10px 12px;height:44px}
  /*.orb{left:0;right:0;bottom:0;border-radius:0;border:0;border-top:1px solid var(--line);*/
  /*  background:color-mix(in oklab,var(--surface) 95%,transparent);backdrop-filter:blur(12px);padding:12px 16px;*/
  /*  box-shadow:none;justify-content:flex-start;gap:12px}*/
  /*.orb .orb-label{flex:1}*/
  /* Панель на телефоне — лист на пол-экрана снизу, а не окно в углу. */
  .jay-panel{left:0;right:0;bottom:0;width:auto;max-width:none;max-height:72vh;
    border-radius:var(--r-panel) var(--r-panel) 0 0;border-left:0;border-right:0;border-bottom:0}
}

/* color-mix(var(--surface)) выше уже верно меняется вместе с [data-theme="night"] — отдельный ночной оверрайд не нужен. */
.orb .w-orb,.jay-head .w-orb{flex:none}
.orb .w-orb{--o:22px}
.jay-head .w-orb{--o:32px}
