/* Jarvis visual system — extracted from admin.html, shared by all three pages. */
/* ── JARVIS visual system ────────────────────────────────────────────────
   Dark holographic glass on the FalconEye palette: deep-space navy,
   hairline gold, restrained glow. Every selector/class the widget JS
   touches is unchanged — this block is presentation only. Tokens live on
   the three jv roots so nothing leaks onto the light admin page. */
#jv-panel,#jv-srcpop,.jv-trigger{
  --jv-bg:#0a0e1a; --jv-glass:rgba(16,22,40,.72); --jv-line:rgba(201,169,122,.28);
  --jv-gold:#c9a97a; --jv-gold-hi:#e8cf9e; --jv-text:#dfe3ee; --jv-dim:#8b93a8;
  --jv-amber:#e3a53a; --jv-hair:rgba(255,255,255,.09);
}
.jv-trigger{position:fixed;right:18px;bottom:calc(64px + env(safe-area-inset-bottom));width:54px;height:54px;border-radius:50%;
  background:radial-gradient(circle at 50% 38%, #141b30 0%, #0a0e1a 78%);border:1px solid rgba(201,169,122,.55);
  box-shadow:0 6px 24px rgba(0,0,0,.55), 0 0 16px rgba(201,169,122,.22);cursor:pointer;z-index:11990;
  display:none;align-items:center;justify-content:center;padding:0;transition:transform .18s,box-shadow .18s;
  animation:jv-pulse 3.6s ease-in-out infinite}
.jv-trigger:hover{transform:scale(1.07);box-shadow:0 6px 26px rgba(0,0,0,.55), 0 0 26px rgba(201,169,122,.45);animation-play-state:paused}
.jv-trigger img{width:34px;height:34px;object-fit:contain;display:block;filter:drop-shadow(0 0 6px rgba(201,169,122,.35))}
@keyframes jv-pulse{0%,100%{box-shadow:0 6px 24px rgba(0,0,0,.55), 0 0 12px rgba(201,169,122,.16)}50%{box-shadow:0 6px 24px rgba(0,0,0,.55), 0 0 22px rgba(201,169,122,.34)}}
/* Z-ORDER: the house ladder puts the fixed footer at 9999 and true modal
   overlays (Duo push, Report Bug) at 12000. Jarvis is a surface, not a modal,
   so it sits just BELOW that tier — above the 11990 trigger, below anything
   that must be able to interrupt it. It previously sat at 12001 and rendered
   the Duo prompt behind itself, which in full-screen mode hid it entirely. */
#jv-backdrop{position:fixed;inset:0;background:rgba(6,9,18,.5);opacity:0;pointer-events:none;transition:opacity .2s;z-index:11994}
#jv-backdrop.show{opacity:1;pointer-events:auto}
#jv-panel{position:fixed;top:0;right:0;height:100dvh;width:min(460px,100vw);z-index:11995;
  background:
    radial-gradient(120% 40% at 100% 0%, rgba(201,169,122,.08) 0%, rgba(201,169,122,0) 55%),
    repeating-linear-gradient(0deg, rgba(255,255,255,.014) 0 1px, rgba(255,255,255,0) 1px 34px),
    linear-gradient(165deg, #0d1322 0%, #0a0e1a 60%, #090c16 100%);
  backdrop-filter:blur(18px) saturate(1.15);-webkit-backdrop-filter:blur(18px) saturate(1.15);
  border-left:1px solid var(--jv-line);
  display:flex;flex-direction:column;box-shadow:-16px 0 48px rgba(4,6,12,.65);
  transform:translateX(105%);transition:transform .3s cubic-bezier(.32,0,.15,1)}
#jv-panel.show{transform:translateX(0)}
.jv-head{display:flex;flex-direction:column;gap:10px;padding:14px 18px 12px;
  background:linear-gradient(180deg, rgba(201,169,122,.06) 0%, rgba(201,169,122,0) 100%);
  border-bottom:1px solid var(--jv-line)}
.jv-mark{position:relative;width:38px;height:38px;flex:0 0 auto;border-radius:50%;
  background:radial-gradient(circle at 50% 40%, #182036 0%, #0a0e1a 80%);padding:3px;
  border:1px solid rgba(201,169,122,.5);box-shadow:0 0 12px rgba(201,169,122,.28), inset 0 0 8px rgba(201,169,122,.12)}
.jv-mark img{width:100%;height:100%;object-fit:contain;display:block}
.jv-title{font-size:14px;font-weight:800;color:var(--jv-gold-hi);letter-spacing:.42em;text-transform:uppercase;
  text-shadow:0 0 14px rgba(201,169,122,.45);margin-right:-.42em}
.jv-sub{font-size:9.5px;color:var(--jv-dim);letter-spacing:.14em;text-transform:uppercase;margin-top:3px}
.jv-x{margin-left:auto;background:none;border:none;color:var(--jv-dim);font-size:22px;cursor:pointer;line-height:1;transition:color .15s,text-shadow .15s}
.jv-tts{flex:0 0 auto;background:none;border:1px solid var(--jv-hair);border-radius:8px;color:var(--jv-dim);font-size:13px;cursor:pointer;padding:3px 9px;transition:color .15s,border-color .15s,box-shadow .15s}
.jv-tts:hover{color:var(--jv-gold-hi)}
.jv-tts.on{color:var(--jv-gold-hi);border-color:rgba(201,169,122,.6);box-shadow:0 0 10px rgba(201,169,122,.3)}
.jv-x:hover{color:var(--jv-gold-hi);text-shadow:0 0 10px rgba(201,169,122,.5)}
.jv-body{flex:1;overflow-y:auto;padding:16px 14px;display:flex;flex-direction:column;gap:10px;background:transparent;scrollbar-width:thin;scrollbar-color:rgba(201,169,122,.35) transparent}
.jv-body::-webkit-scrollbar{width:6px}
.jv-body::-webkit-scrollbar-thumb{background:rgba(201,169,122,.28);border-radius:3px}
.jv-body::-webkit-scrollbar-track{background:transparent}
.jv-msg{max-width:92%;padding:10px 14px;border-radius:14px;font-size:13.5px;line-height:1.55;word-wrap:break-word}
.jv-msg.user{align-self:flex-end;background:rgba(201,169,122,.13);border:1px solid rgba(201,169,122,.34);color:#f0ead9;border-bottom-right-radius:4px}
.jv-msg.bot{align-self:flex-start;background:rgba(255,255,255,.04);border:1px solid var(--jv-hair);color:var(--jv-text);border-bottom-left-radius:4px;box-shadow:0 2px 12px rgba(4,6,12,.35)}
.jv-warn{display:block;background:rgba(227,165,58,.1);border-left:2px solid var(--jv-amber);color:#f0c27a;padding:7px 10px;border-radius:8px;margin:4px 0;font-size:12.5px}
.jv-uncited{background:rgba(227,165,58,.09);border-bottom:2px dotted var(--jv-amber);position:relative;color:#eadfc4}
.jv-uncited::after{content:'unsourced';font-size:9px;color:var(--jv-amber);vertical-align:super;margin-left:3px;letter-spacing:.06em}
.jv-cite{display:inline-flex;align-items:center;justify-content:center;min-width:17px;height:17px;margin:0 2px;padding:0 4px;
  border-radius:9px;border:1px solid rgba(201,169,122,.55);background:rgba(201,169,122,.08);color:var(--jv-gold-hi);
  font-size:10.5px;font-weight:700;cursor:pointer;vertical-align:super;transition:background .15s,box-shadow .15s}
.jv-cite:hover{background:rgba(201,169,122,.9);color:#0a0e1a;box-shadow:0 0 10px rgba(201,169,122,.5)}
.jv-sources{margin-top:9px;padding-top:8px;border-top:1px solid var(--jv-hair);font-size:10.5px;color:var(--jv-dim);display:flex;flex-wrap:wrap;gap:4px;align-items:center;letter-spacing:.04em}
.jv-src-chip{border:1px solid rgba(201,169,122,.3);background:transparent;border-radius:9px;padding:2px 8px;font-size:10.5px;color:var(--jv-gold);cursor:pointer;transition:border-color .15s,box-shadow .15s}
.jv-src-chip:hover{border-color:rgba(201,169,122,.7);box-shadow:0 0 8px rgba(201,169,122,.3)}
.jv-meta{margin-top:6px;font-size:10px;color:var(--jv-dim);font-style:italic;letter-spacing:.03em}
.jv-actions{margin-top:9px;display:flex;gap:6px}
.jv-actions button{border:1px solid var(--jv-hair);background:transparent;border-radius:8px;padding:3px 10px;font-size:10.5px;
  color:var(--jv-dim);cursor:pointer;letter-spacing:.05em;text-transform:uppercase;transition:color .15s,border-color .15s,box-shadow .15s}
.jv-actions button:hover{color:var(--jv-gold-hi);border-color:rgba(201,169,122,.55);box-shadow:0 0 8px rgba(201,169,122,.22)}
.jv-status{align-self:flex-start;display:flex;align-items:center;gap:9px;font-size:12px;color:var(--jv-gold);font-style:italic;padding:2px 4px;letter-spacing:.03em}
.jv-status-mark{position:relative;width:20px;height:20px;flex:0 0 auto;border-radius:50%;background:radial-gradient(circle at 50% 40%, #182036 0%, #0a0e1a 80%);padding:1px;
  border:1px solid rgba(201,169,122,.55);box-shadow:0 0 10px rgba(201,169,122,.35)}
.jv-status-mark img{width:100%;height:100%;object-fit:contain;display:block}
/* The falcon's own gold eye blinks — geometry traced off the 1024px logo,
   identical numbers to index.html's .welcome-eyelid; re-measure both if the
   asset ever changes. */
.jv-mark .welcome-eyelid,.jv-status-mark .welcome-eyelid,.jv-trigger .welcome-eyelid{position:absolute;left:48.83%;top:23.05%;width:15.33%;height:13.18%;pointer-events:none;
  clip-path:polygon(34.4% 0.0%,34.4% 7.4%,45.2% 7.4%,45.2% 14.8%,45.2% 22.2%,47.8% 22.2%,47.8% 29.6%,86.0% 29.6%,86.0% 37.0%,98.1% 37.0%,98.1% 44.4%,100.0% 44.4%,100.0% 66.7%,99.4% 66.7%,99.4% 74.1%,98.1% 74.1%,98.1% 81.5%,89.8% 81.5%,89.8% 88.9%,81.5% 88.9%,81.5% 96.3%,73.9% 96.3%,73.9% 100.0%,28.7% 100.0%,28.7% 96.3%,21.7% 96.3%,21.7% 88.9%,15.3% 88.9%,15.3% 81.5%,9.6% 81.5%,9.6% 74.1%,5.7% 74.1%,5.7% 66.7%,3.8% 66.7%,3.8% 59.3%,2.5% 59.3%,2.5% 51.9%,1.3% 51.9%,1.3% 44.4%,0.0% 44.4%,0.0% 29.6%,0.6% 29.6%,0.6% 22.2%,4.5% 22.2%,4.5% 14.8%,8.9% 14.8%,8.9% 7.4%,12.7% 7.4%,12.7% 0.0%)}
.jv-mark .welcome-eyelid i,.jv-status-mark .welcome-eyelid i,.jv-trigger .welcome-eyelid i{display:block;width:100%;height:100%;background:#141826;transform-origin:50% 0;transform:scaleY(0)}
@keyframes jv-blink{0%,78%{transform:scaleY(0)}86%{transform:scaleY(1)}94%,100%{transform:scaleY(0)}}
.jv-status-mark .welcome-eyelid i{animation:jv-blink 1500ms cubic-bezier(.4,0,.2,1) infinite}
@media (prefers-reduced-motion:reduce){.jv-status-mark .welcome-eyelid i{animation:none;transform:scaleY(0)}.jv-trigger{animation:none}}
.jv-empty{color:var(--jv-dim);font-size:13px;line-height:1.6;padding:14px 6px}
.jv-empty-title{font-size:15px;font-weight:800;color:var(--jv-gold-hi);letter-spacing:.2em;text-transform:uppercase;margin-bottom:8px;text-shadow:0 0 12px rgba(201,169,122,.35)}
.jv-empty-ctx{margin-top:10px;font-size:11.5px;color:var(--jv-gold)}
.jv-empty-ctx b{color:var(--jv-gold-hi)}
.jv-chips{margin-top:14px;display:flex;flex-direction:column;gap:7px;align-items:flex-start}
.jv-chips button{border:1px solid rgba(201,169,122,.35);background:rgba(201,169,122,.05);border-radius:12px;padding:7px 13px;font-size:12px;color:var(--jv-gold);cursor:pointer;text-align:left;transition:border-color .15s,box-shadow .15s,color .15s}
.jv-chips button:hover{border-color:rgba(201,169,122,.7);color:var(--jv-gold-hi);box-shadow:0 0 12px rgba(201,169,122,.25)}
.jv-foot{display:flex;gap:8px;padding:12px 14px calc(12px + env(safe-area-inset-bottom));border-top:1px solid var(--jv-line);
  background:linear-gradient(0deg, rgba(201,169,122,.05) 0%, rgba(201,169,122,0) 100%)}
#jv-input{flex:1;resize:none;border:1px solid var(--jv-hair);border-radius:12px;padding:9px 12px;font-size:13.5px;font-family:inherit;max-height:110px;
  background:rgba(255,255,255,.05);color:var(--jv-text);transition:border-color .15s,box-shadow .15s}
#jv-input::placeholder{color:#5b6378}
#jv-input:focus{outline:none;border-color:rgba(201,169,122,.65);box-shadow:0 0 12px rgba(201,169,122,.18)}
/* Mic: idle is a quiet outline; live it pulses so a hands-free user can tell
   at a glance whether the ear is actually open. */
/* padding + box-sizing stated explicitly: this stylesheet is now shared with
   pages whose button resets differ, and the Training Hub was handing these
   two the UA default 1px 6px, squeezing the icons. A shared widget cannot
   inherit its host's resets. */
.jv-mic{flex:0 0 auto;width:40px;height:40px;padding:0;box-sizing:border-box;border-radius:50%;border:1px solid var(--jv-hair);background:rgba(255,255,255,.04);
  color:var(--jv-dim);font-size:15px;cursor:pointer;transition:color .15s,border-color .15s,box-shadow .15s}
.jv-mic:hover{color:var(--jv-gold-hi);border-color:rgba(201,169,122,.5)}
.jv-mic.on{color:#0a0e1a;background:var(--jv-gold);border-color:var(--jv-gold-hi);animation:jv-mic-live 1.5s ease-in-out infinite}
@keyframes jv-mic-live{0%,100%{box-shadow:0 0 0 0 rgba(201,169,122,.55)}50%{box-shadow:0 0 0 7px rgba(201,169,122,0)}}
/* #id, not .jv-convo-btn: at equal specificity the later .jv-mode-btn.on rule
   won every property this set, making it dead CSS. */
#jv-convo.on{color:var(--jv-gold-hi);border-color:rgba(201,169,122,.6);box-shadow:0 0 10px rgba(201,169,122,.3)}
.jv-listen{color:var(--jv-gold-hi)}
.jv-mic-dot{width:9px;height:9px;border-radius:50%;background:var(--jv-gold);flex:0 0 auto;animation:jv-mic-live 1.3s ease-in-out infinite}
.jv-convo-note{display:block;font-size:11.5px;color:var(--jv-gold);letter-spacing:.03em;font-style:italic}
@media (prefers-reduced-motion:reduce){.jv-mic.on,.jv-mic-dot{animation:none}}
#jv-send{width:40px;height:40px;padding:0;box-sizing:border-box;border-radius:50%;border:1px solid rgba(201,169,122,.6);
  background:radial-gradient(circle at 50% 35%, rgba(201,169,122,.28) 0%, rgba(201,169,122,.1) 100%);
  color:var(--jv-gold-hi);font-size:17px;cursor:pointer;flex:0 0 auto;transition:box-shadow .15s,background .15s}
#jv-send:hover{box-shadow:0 0 14px rgba(201,169,122,.4)}
#jv-send:disabled{opacity:.35;cursor:default;box-shadow:none}
/* Stop state: unmistakably different from Send — a filled square in a warm
   red, so "he is still going" reads at a glance from a phone cradle. */
#jv-send.stopping{border-color:rgba(224,122,106,.75);color:#ffe9e4;font-size:13px;
  background:radial-gradient(circle at 50% 35%, rgba(224,122,106,.45) 0%, rgba(224,122,106,.18) 100%);
  animation:jv-stop-pulse 1.6s ease-in-out infinite}
#jv-send.stopping:hover{box-shadow:0 0 14px rgba(224,122,106,.5)}
@keyframes jv-stop-pulse{0%,100%{box-shadow:0 0 0 0 rgba(224,122,106,.4)}50%{box-shadow:0 0 0 6px rgba(224,122,106,0)}}
@media (prefers-reduced-motion:reduce){#jv-send.stopping{animation:none}}
.jv-chart{margin:10px 0;padding:11px 13px;background:rgba(255,255,255,.03);border:1px solid var(--jv-hair);border-radius:10px}
.jv-chart-title{font-size:11px;font-weight:700;color:var(--jv-gold-hi);letter-spacing:.12em;text-transform:uppercase;margin-bottom:9px}
.jv-legend{display:flex;gap:12px;font-size:10.5px;color:var(--jv-dim);margin-bottom:7px}
.jv-legend i{display:inline-block;width:9px;height:9px;border-radius:2px;margin-right:4px}
.jv-bar-group{margin-bottom:8px}
.jv-bar-lbl{font-size:10.5px;color:var(--jv-dim);margin-bottom:3px;letter-spacing:.03em}
.jv-bar-row{display:flex;align-items:center;gap:6px;margin-bottom:2px}
.jv-bar{height:11px;border-radius:2px;min-width:2px;box-shadow:0 0 8px rgba(201,169,122,.14)}
.jv-bar-val{font-size:10px;color:var(--jv-dim)}
.jv-pre{white-space:pre-wrap;font-size:11px;background:rgba(255,255,255,.05);color:var(--jv-text);border-radius:8px;padding:8px;overflow-x:auto}
#jv-srcpop{position:fixed;inset:0;display:none;align-items:center;justify-content:center;background:rgba(6,9,18,.55);z-index:11997}
#jv-srcpop.show{display:flex}
.jv-srcpop-in{background:linear-gradient(165deg, #10182c 0%, #0a0e1a 100%);border:1px solid var(--jv-line);border-radius:14px;padding:18px 20px;max-width:360px;
  font-size:13px;line-height:1.55;color:var(--jv-text);box-shadow:0 10px 44px rgba(4,6,12,.7), 0 0 20px rgba(201,169,122,.12)}
.jv-srcpop-in b{color:var(--jv-gold-hi)}
.jv-srcpop-in button{border:1px solid rgba(201,169,122,.5);background:transparent;border-radius:8px;padding:4px 12px;font-size:12px;color:var(--jv-gold);cursor:pointer}
.jv-srcpop-in button:hover{box-shadow:0 0 10px rgba(201,169,122,.3)}
/* ── PANEL MODES ──────────────────────────────────────────────────────────
   overlay (default) — floats over the hub, backdrop dims it, modal-ish.
   dock            — the hub keeps working beside Jarvis: no backdrop, and
                     body gets right padding so nothing hides under the panel.
                     .admin-shell is a centered max-width flex row, so padding
                     on body re-centers the whole hub rather than clipping it,
                     and admin.html's footer is in normal flow (not fixed), so
                     it shifts too without a special case.
   full            — Jarvis fills the viewport for reading long answers/charts.
   Under 900px dock collapses back to a full-width overlay: a 440px reserve on
   a phone would leave the hub unusable. */
/* The reserve MUST equal the panel width (both min(460px,100vw)) — at 440
   against a 460px panel a 20px strip of the hub sat permanently underneath. */
body.jv-docked{padding-right:min(460px,100vw);transition:padding-right .3s cubic-bezier(.32,0,.15,1)}
/* Toasts are position:fixed, so body padding doesn't move them: without this
   they drift off the hub's visual centre in dock mode and hide behind the
   panel. Raised above the panel too — a confirmation you can't see is worse
   than no confirmation. */
body.jv-docked .toast-container{transform:translateX(calc(-50% - min(460px,100vw)/2))}
.toast-container{z-index:12100}
#jv-panel.jv-dock{box-shadow:-10px 0 30px rgba(4,6,12,.5)}
#jv-panel.jv-full{width:100vw;border-left:none}
#jv-panel.jv-full .jv-body{max-width:1100px;width:100%;margin:0 auto;padding:22px 20px}
#jv-panel.jv-full .jv-foot{max-width:1100px;width:100%;margin:0 auto;box-sizing:border-box}
#jv-panel.jv-full .jv-head{padding-left:max(20px,calc((100vw - 1100px)/2));padding-right:max(20px,calc((100vw - 1100px)/2))}
#jv-panel.jv-full .jv-head-actions{max-width:1100px}
#jv-panel.jv-full .jv-msg{max-width:78%}
/* The context line and the history sheet centre with everything else in full
   mode, instead of hugging the far-left edge of a wide screen. */
#jv-panel.jv-full .jv-ctx{max-width:1100px;width:100%;margin:0 auto;box-sizing:border-box;padding-left:20px}
#jv-panel.jv-full .jv-hist-hdr,#jv-panel.jv-full .jv-hist-body{max-width:1100px;margin:0 auto}
.jv-mode-btn{flex:0 0 auto;background:none;border:1px solid var(--jv-hair);border-radius:8px;color:var(--jv-dim);font-size:12px;cursor:pointer;padding:4px 10px;transition:color .15s,border-color .15s,box-shadow .15s}
/* Row 1 — identity. The name gets the whole width, so it is never clipped;
   only a genuinely enormous label would ellipsis now. */
.jv-head-id{display:flex;align-items:center;gap:12px}
.jv-head-name{min-width:0;flex:1}
.jv-title,.jv-sub{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Row 2 — controls. Wrapping is the point: on a narrow panel they form a
   second line instead of squeezing the name above them. */
.jv-head-actions{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
@media (max-width:640px){
  /* Full screen is still inert here -- an overlay already fills the screen --
     but dock now means "share the screen with the hub", so it stays. */
  #jv-full-btn{display:none}
}
.jv-mode-btn:hover{color:var(--jv-gold-hi);border-color:rgba(201,169,122,.5)}
.jv-mode-btn.on{color:var(--jv-gold-hi);border-color:rgba(201,169,122,.6);box-shadow:0 0 10px rgba(201,169,122,.28)}
.jv-ctx{font-size:9.5px;color:var(--jv-gold);letter-spacing:.08em;text-transform:uppercase;padding:0 4px 2px;opacity:.75}
@media (max-width:900px){
  /* Dock genuinely collapses to a full-width overlay here — reserving 460px
     of a phone screen would leave the hub unusable, and a 460px panel with
     no reserve and no backdrop was the worst of both. jvApplyMode also
     forces overlay behaviour at this width so the backdrop comes back. */
  body.jv-docked{padding-right:0}
  #jv-panel.jv-dock{width:100vw}
  body.jv-docked .toast-container{transform:translateX(-50%)}
}
/* Saved conversations sheet — slides over the thread, inside the panel. */
/* inset:0, not top:<header height> — the sheet carries its own header with
   Close, so it never has to guess the panel header's height. */
.jv-hist{display:none;position:absolute;inset:0;z-index:3;
  background:linear-gradient(180deg,#0c1220 0%,#0a0e1a 100%);border-top:1px solid var(--jv-line);overflow-y:auto}
.jv-hist.show{display:block}
.jv-hist-hdr{display:flex;align-items:center;gap:8px;padding:12px 14px;border-bottom:1px solid var(--jv-hair);
  font-size:11px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--jv-gold-hi)}
.jv-hist-hdr span{flex:1}
.jv-hist-hdr button{border:1px solid var(--jv-hair);background:transparent;color:var(--jv-dim);border-radius:8px;
  padding:3px 10px;font-size:10px;letter-spacing:.06em;text-transform:uppercase;cursor:pointer}
.jv-hist-hdr button:hover{color:var(--jv-gold-hi);border-color:rgba(201,169,122,.5)}
.jv-hist-body{padding:6px 10px 18px}
.jv-hist-row{display:flex;align-items:stretch;gap:6px;border-bottom:1px solid rgba(255,255,255,.05)}
.jv-hist-row.current{background:rgba(201,169,122,.07)}
.jv-hist-open{flex:1;text-align:left;background:none;border:none;cursor:pointer;padding:10px 6px;display:flex;flex-direction:column;gap:3px}
.jv-hist-open:hover .jv-hist-title{color:var(--jv-gold-hi)}
.jv-hist-title{font-size:12.5px;color:var(--jv-text);line-height:1.35}
.jv-hist-meta{font-size:10px;color:var(--jv-dim);letter-spacing:.03em}
.jv-hist-arch{background:none;border:none;color:var(--jv-dim);cursor:pointer;font-size:13px;padding:0 8px}
.jv-hist-arch:hover{color:var(--jv-gold-hi)}
.jv-newnote{align-self:center;font-size:10.5px;color:var(--jv-dim);font-style:italic;letter-spacing:.03em;padding:4px 0;text-align:center}
.jv-proposal{margin-top:10px;padding:11px 13px;background:rgba(201,169,122,.07);border:1px solid rgba(201,169,122,.45);border-radius:10px;box-shadow:0 0 14px rgba(201,169,122,.12)}
.jv-proposal-hdr{font-size:10px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--jv-gold-hi);margin-bottom:5px}
.jv-proposal-hdr.done{color:#8fd18f}
.jv-proposal-hdr.fail{color:#e07a6a}
.jv-proposal-sum{font-size:12.5px;color:var(--jv-text);line-height:1.5}
.jv-proposal-btns{margin-top:9px;display:flex;gap:8px}
.jv-prop-exec{border:1px solid rgba(201,169,122,.7);background:rgba(201,169,122,.85);color:#0a0e1a;border-radius:8px;padding:5px 16px;font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;cursor:pointer;transition:box-shadow .15s}
.jv-prop-exec:hover{box-shadow:0 0 14px rgba(201,169,122,.5)}
.jv-prop-exec:disabled,.jv-prop-cancel:disabled{opacity:.4;cursor:default}
.jv-prop-cancel{border:1px solid var(--jv-hair);background:transparent;color:var(--jv-dim);border-radius:8px;padding:5px 12px;font-size:11px;letter-spacing:.06em;text-transform:uppercase;cursor:pointer}
@media (max-width:640px){#jv-panel{width:100vw}}

/* ── Bottom sheet: the phone's version of docking ────────────────────────── */
:root{--jv-sheet-h:56dvh}
#jv-panel.jv-sheet{
  top:auto;bottom:0;right:0;left:0;width:100vw;height:var(--jv-sheet-h);
  border-left:none;border-top:1px solid rgba(201,169,122,.45);
  border-radius:18px 18px 0 0;
  box-shadow:0 -14px 40px rgba(4,6,12,.7);
  /* Slides up, not across: it is anchored to the bottom edge now. */
  transform:translateY(102%)}
#jv-panel.jv-sheet.show{transform:translateY(0)}
/* A grab bar, so it reads as a sheet rather than a panel that lost its top. */
#jv-panel.jv-sheet .jv-head::before{content:"";display:block;width:38px;height:4px;border-radius:99px;
  background:rgba(201,169,122,.45);margin:-4px auto 8px}
#jv-panel.jv-sheet .jv-head{padding-top:10px}
/* The hub scrolls clear of the sheet instead of hiding underneath it. */
body.jv-sheet-open{padding-bottom:var(--jv-sheet-h)}
body.jv-sheet-open .toast-container{bottom:calc(var(--jv-sheet-h) + 16px)}

/* ── Reply bar: one tap = one turn, where Safari demands a gesture ───────── */
.jv-tapreply{display:none;margin:0 14px 10px;padding:15px 12px;width:calc(100% - 28px);
  border:1px solid rgba(201,169,122,.65);border-radius:14px;
  background:linear-gradient(180deg,rgba(201,169,122,.18) 0%,rgba(201,169,122,.08) 100%);
  color:var(--jv-gold-hi);font:inherit;font-size:13px;font-weight:800;letter-spacing:.14em;
  text-transform:uppercase;cursor:pointer;align-items:center;justify-content:center;gap:9px;
  box-shadow:0 0 18px rgba(201,169,122,.2);animation:jv-tap-breathe 2.2s ease-in-out infinite}
.jv-tapreply.show{display:flex}
.jv-tapreply:active{transform:scale(.985)}
@keyframes jv-tap-breathe{0%,100%{box-shadow:0 0 14px rgba(201,169,122,.16)}50%{box-shadow:0 0 22px rgba(201,169,122,.34)}}
@media (prefers-reduced-motion:reduce){.jv-tapreply{animation:none}}

/* ── Icons ──────────────────────────────────────────────────────────────────
   These were emoji codepoints. On iOS they render as full-colour stickers --
   a cartoon clock and a blue loudspeaker sitting inside a gold-on-black
   panel. Inline SVG inherits currentColor, so the controls finally match the
   rest of the interface and light up gold with their button. */
.jv-i{width:16px;height:16px;display:block;flex:0 0 auto}
.jv-mode-btn,.jv-tts{display:inline-flex;align-items:center;justify-content:center;min-width:36px;min-height:32px;padding:5px 10px}
.jv-mic{display:inline-flex;align-items:center;justify-content:center}
.jv-mic .jv-i{width:17px;height:17px}
/* border-box, or min-height lands on the CONTENT box and silently adds the
   padding on top -- which is what made a one-row composer two lines tall and
   clipped the placeholder halfway through its second line. */
#jv-input{box-sizing:border-box;min-height:40px;line-height:1.35}
/* Bottom-aligned so the buttons stay level with the last line as it grows. */
.jv-foot{align-items:flex-end}
/* LAST, deliberately: these share specificity with the rules above, so source
   order is the only thing that lets the phone sizes win. */
@media (max-width:640px){
  .jv-mode-btn,.jv-tts{min-width:40px;min-height:36px}
  #jv-input{min-height:44px}
  .jv-mic,#jv-send{width:44px;height:44px;min-height:44px}
}

/* Inline text button (the 'Change voice' prompt). */
.jv-linkish{background:none;border:none;padding:0;margin-left:4px;color:var(--jv-gold-hi);font:inherit;text-decoration:underline;cursor:pointer}

/* Voice bar — visible whenever read-aloud is on. */
.jv-voicebar{display:none;align-items:center;gap:8px;padding:6px 14px 8px;border-bottom:1px solid var(--jv-hair)}
.jv-voicebar label{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--jv-gold);flex:0 0 auto}
.jv-voicebar select{flex:1;min-width:0;background:rgba(255,255,255,.06);color:var(--jv-text);
  border:1px solid var(--jv-hair);border-radius:8px;padding:6px 8px;font:inherit;font-size:12.5px;
  min-height:34px;-webkit-appearance:none;appearance:none}
.jv-voicebar select:focus{outline:none;border-color:rgba(201,169,122,.65)}
/* Holding any header control must never start a text selection on a phone. */
.jv-tts,.jv-mode-btn{user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}

/* View pill: it is draggable, so say so on hover and lift it while moving. */
#vac-pill{cursor:grab}
#vac-pill.dragging{cursor:grabbing;opacity:.9;box-shadow:0 8px 22px rgba(26,26,46,.55)}
