/*
 * talk-shell.css - shared modular layer for every *-talk.html page.
 *
 * Goal: keep per-page palettes (Avery kid-pink, Henry slate, etc.) BUT
 * unify the cross-cutting rules:
 *   1. AI portrait propagates as a soft, blurred backdrop when body has
 *      data-ai-portrait="/path/to/portrait". Default = page's own gradient.
 *   2. Mic emoji override via data-mic-emoji (Avery → 🌼, others → 🎙).
 *   3. Top-bar (sign-in pill + theme toggle) parity injected by talk-shell.js.
 *   4. Attachment button + voice button parity for chat-mode pages.
 *
 * Companion: cam-dock.css (cam-mic-row two-circle pattern), cam-dock.js,
 * vision-agent.js, top-bar.js, talk-shell.js.
 *
 * Pattern: import after page styles so cascading wins for the parts we
 * intentionally override; per-page palette colors win for everything else.
 */

/* ---------- AI portrait backdrop ---------- */
/* When body has [data-ai-portrait], paint that image full-bleed behind everything,
   blurred and dimmed so it reads as a backdrop, not a focal element. The page's
   own gradient/palette remains layered on top via its own background.
   isolation:isolate makes body a stacking context so the negative-z pseudo-elements
   below stay BEHIND every child (without needing the old position:relative blanket
   that broke position:fixed on modals + top-bar — 2026-04-27 Jason fix). */
body[data-ai-portrait]{isolation:isolate}
body[data-ai-portrait]::before{
  content:"";
  position:fixed;inset:0;
  background-image:var(--ai-portrait-image, none);
  background-size:cover;
  background-position:center 30%;
  background-repeat:no-repeat;
  /* 2026-05-08 Jason: opacity 0.55 was reading as a "big purple thing covering
     the background" on Rachel/AI-Exec mobile. Dropped to 0.22 + heavier blur
     so the portrait reads as a soft tint, not a focal element. */
  filter:blur(48px) saturate(1.0);
  opacity:0.22;
  z-index:-2;
  pointer-events:none;
}
/* Subtle dark overlay so foreground text/buttons stay legible no matter the photo. */
body[data-ai-portrait]::after{
  content:"";
  position:fixed;inset:0;
  background:radial-gradient(120% 90% at 50% 35%, rgba(0,0,0,0) 0%, rgba(8,12,24,0.32) 60%, rgba(8,12,24,0.55) 100%);
  z-index:-1;
  pointer-events:none;
}
/* Light mode dims the backdrop further so dark cards still read clean. */
html.light-mode body[data-ai-portrait]::before{opacity:0.32;filter:blur(40px) saturate(0.95) brightness(1.08)}
html.light-mode body[data-ai-portrait]::after{
  background:radial-gradient(120% 90% at 50% 35%, rgba(255,255,255,0.05) 0%, rgba(214,219,230,0.45) 60%, rgba(214,219,230,0.7) 100%);
}

/* ---------- Generic Henry-style titlebar and subtitle parity ---------- */
body.ts-ai-titlebar .brand{display:none !important}
.ai-titlebar{
  position:fixed;
  top:0;
  left:50%;
  transform:translateX(-50%);
  /* Was a hardcoded 48px while the bar it overlays measured 45-49px and now
     56px, so the AI's name floated a few px off the centre line of the
     controls beside it. One token, one alignment. */
  height:var(--hdr-h,56px);
  display:flex;
  align-items:center;
  justify-content:center;
  pointer-events:none;
  z-index:9701;
  font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  text-align:center;
  max-width:60vw;
  padding:0 12px;
}
.ai-titlebar .ai-name{
  font-size:clamp(24px,3.6vw,32px);
  font-weight:800;
  letter-spacing:0;
  background:linear-gradient(135deg,#60a5fa,#a78bfa,#34d399);
  -webkit-background-clip:text;
  -webkit-text-fill-color:transparent;
  background-clip:text;
  white-space:nowrap;
  line-height:1;
}
.ai-subtitle-below{
  text-align:center;
  color:#8892b0;
  font-size:clamp(11px,1.6vw,14px);
  font-weight:300;
  margin-top:2px;
  margin-bottom:2px;
  letter-spacing:0;
  pointer-events:none;
}
body.has-content .ai-subtitle-below{display:none !important}
body[data-ai-slug] .mic-btn{
  outline:3px solid rgba(96,165,250,0.70) !important;
  outline-offset:2px !important;
}
@media(max-width:480px){
  .ai-titlebar{max-width:60vw}
  .ai-titlebar .ai-name{font-size:22px}
}

/* Top-bar parity is owned by top-bar.css/top-bar.js; talk-shell does not duplicate. */

/* ---------- Webcam pip = USER camera (always) ---------- */
/* The left-hand pip is for the user's webcam, never the AI portrait.
   vision-agent.js toggles #vision-pip.active when the stream is attached.
   Hide the inner <video> until .active so the gray placeholder reads clean. */
body #vision-pip:not(.active) > video{display:none !important}
body #vision-pip.active > video{display:block !important;width:100%;height:100%;object-fit:cover;border-radius:50%;transform:scaleX(-1)}

/* Cam-dock visibility is OPT-IN: only shows after the user taps the eyeball
   icon. Default = AI mic alone, centered. When user enables cam, the second
   circle slides in to the LEFT of the mic. */

/* "AI IS WATCHING" label is meaningless when no cam stream — hide it. */
body #vision-pip:not(.active) #vision-watching-label,
body #vision-pip:not(.active) #vision-dot{display:none !important}

/* Empty pip placeholder color when shown (cam-active but stream not yet
   attached) — neutral gray, no portrait fill. */
body #vision-pip:not(.active){
  background:#1f2937 !important;
  border:2px solid rgba(255,255,255,0.15) !important;
}

/* ---------- AI portrait sits BEHIND the mic button ---------- */
/* When the page declares data-ai-portrait, the mic-btn (right-hand circle) shows
   the AI's portrait behind the mic emoji. When no portrait is declared, the mic
   keeps its default gray/colored gradient (per-page palette). */
body[data-ai-portrait] .mic-btn{
  background-image:var(--ai-portrait-image) !important;
  background-size:cover !important;
  background-position:center 30% !important;
  background-repeat:no-repeat !important;
  background-color:transparent !important;
  /* 2026-04-29 (Jason): mic emoji sits with its base touching the circle edge.
   * line-height:0.9 collapses the emoji's natural whitespace below the glyph
   * so the visual baseline of the mic body lands at the circle's bottom edge. */
  align-items: flex-end !important;
  padding-bottom: 4% !important;
  line-height: 0.9 !important;
  overflow: visible !important;
}
/* Soft inner shadow so the mic emoji stays readable on top of the portrait. */
body[data-ai-portrait] .mic-btn::after{
  content:"";position:absolute;inset:0;border-radius:50%;
  background:radial-gradient(circle at center, rgba(0,0,0,0.45) 0%, rgba(0,0,0,0.15) 55%, rgba(0,0,0,0.55) 100%);
  pointer-events:none;z-index:0;
}
body[data-ai-portrait] .mic-btn > *{position:relative;z-index:1}

/* 2026-04-28 Jason: glow halo around the mic emoji so it reads as a
 * clickable affordance (was fading into the portrait). 2026-04-28 (later):
 * switched to bright white so it pops against any backdrop (purple starfield,
 * pink kid bubbles, dark gradients). AIs can still override --ai-glow-color
 * if they want a tinted halo, but white is the default. */
/* 2026-04-29 (Jason): glow emanates FROM the mic itself, not below it as a
 * separate light source. The radial gradient is centered ON the mic emoji
 * position (~12% from bottom of circle) and radiates outward — bright at the
 * mic body, fading down + outward so it reads as the mic's own glow rather
 * than a floor lamp underneath it. */
body[data-ai-portrait] .mic-btn::before{
  content:"";
  position:absolute;
  left:50%;
  bottom:12%;
  width:78%;
  height:78%;
  border-radius:50%;
  transform:translate(-50%, 50%);
  background:radial-gradient(circle at center,
    var(--ai-glow-color, rgba(255,255,255,0.95)) 0%,
    var(--ai-glow-color, rgba(255,255,255,0.55)) 18%,
    rgba(255,255,255,0.20) 38%,
    transparent 70%);
  filter:blur(8px);
  z-index:0;
  animation:tsMicGlowPulse 2.4s ease-in-out infinite;
  pointer-events:none;
}
@keyframes tsMicGlowPulse{
  0%,100%{opacity:0.75;transform:translate(-50%, 50%) scale(1);}
  50%{opacity:1;transform:translate(-50%, 50%) scale(1.10);}
}
body[data-ai-portrait] .mic-btn:active::before{
  animation:none;opacity:1;transform:translate(-50%, 50%) scale(0.92);
}

/* ---------- Attachment + voice buttons (chat-mode parity) ---------- */
.ts-attach-btn,.ts-voice-btn{
  width:38px;height:38px;border-radius:50%;border:none;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,0.08);color:inherit;
  font-size:17px;line-height:1;transition:background .2s ease;
}
.ts-attach-btn:hover,.ts-voice-btn:hover{background:rgba(255,255,255,0.16)}
.ts-voice-btn.active{background:#22c55e;color:#fff;animation:tsVoicePulse 1.6s ease-in-out infinite}
@keyframes tsVoicePulse{0%,100%{box-shadow:0 0 0 0 rgba(34,197,94,0.6)}50%{box-shadow:0 0 0 8px rgba(34,197,94,0)}}

/* ---------- Empty-section auto-hide (modular content sections) ---------- */
[data-empty="true"]{display:none !important}

/* ---------- iMESSAGE-STYLE CHAT BUBBLES (canonical, 2026-04-29) ----------
 * Originally shipped on henry-talk only after Jason's voice-handoff. Now
 * canonical so every talk page gets the iMessage feel without per-page work.
 * User bubbles pin right with bottom-right tail; AI bubbles pin left with
 * bottom-left tail. Max-width 72% so bubbles look like messages, not panels.
 *
 * Pages still own their gradient colors — these rules only set the SHAPE,
 * positioning, and tail mask. Per-page CSS for `.msg.user` / `.msg.ai`
 * background gradients takes precedence over the fallback colors here. */
#transcript .msg, .chat-scroller .msg{position:relative}
body[data-ai-slug] #transcript .msg{max-width:72%;border-radius:18px}
body[data-ai-slug] #transcript .msg.user{align-self:flex-end;border-bottom-right-radius:4px;margin-right:8px}
body[data-ai-slug] #transcript .msg.ai  {align-self:flex-start;border-bottom-left-radius:4px;margin-left:8px}
/* Tails — two-pseudo recipe so the colored bump reads as attached to the
 * bubble corner. ::before is a transcript-bg-colored notch carving the curve. */
body[data-ai-slug] #transcript .msg.user::after{
  content:'';position:absolute;bottom:0;right:-6px;width:14px;height:18px;
  background:inherit;border-bottom-left-radius:16px 14px;z-index:-1;
}
body[data-ai-slug] #transcript .msg.user::before{
  content:'';position:absolute;bottom:0;right:-12px;width:12px;height:18px;
  background:rgba(15,20,40,0.45);border-bottom-left-radius:10px;z-index:-1;
}
body[data-ai-slug] #transcript .msg.ai::after{
  content:'';position:absolute;bottom:0;left:-6px;width:14px;height:18px;
  background:inherit;border-bottom-right-radius:16px 14px;z-index:-1;
}
body[data-ai-slug] #transcript .msg.ai::before{
  content:'';position:absolute;bottom:0;left:-12px;width:12px;height:18px;
  background:rgba(15,20,40,0.45);border-bottom-right-radius:10px;z-index:-1;
}
/* Light-mode notch matches the lighter transcript bg so tails still read clean. */
html.light-mode body[data-ai-slug] #transcript .msg.user::before,
html.light-mode body[data-ai-slug] #transcript .msg.ai::before{
  background:rgba(214,219,230,0.95) !important;
}

/* ---------- MOBILE: KEEP THE TITLE ON-SCREEN (2026-04-29) ----------
 * Per-page CSS uses `.mic-anchor { top: 22%; transform: translate(-50%, -50%) }`
 * which vertically centers the anchor. On small viewports the anchor content
 * (title + portrait + mic + instruction + camera) is taller than the available
 * space above the chat input, so the h1 gets clipped above the visible area.
 *
 * Fix: at narrow viewports, anchor the top of the content (instead of centering)
 * and drop the H1 size so the whole stack fits. Applies to every talk page that
 * uses .mic-anchor — no per-page edit needed. */
@media (max-width: 760px), (max-height: 760px) {
  .mic-anchor {
    top: 70px !important;
    transform: translateX(-50%) !important;
  }
  .mic-anchor .brand h1 {
    font-size: clamp(28px, 7vw, 44px) !important;
    line-height: 1.05 !important;
  }
  .mic-anchor .brand p {
    font-size: clamp(11px, 3vw, 14px) !important;
  }
}

/* ---------- LIGHT MODE FIXES (2026-04-29) ----------
 * Default mic glow is bright white — invisible on a light background AND
 * washes out the "Tap the mic to begin" text below. Switch to an indigo
 * tint in light mode so the glow reads + the instruction stays legible. */
html.light-mode body[data-ai-portrait] .mic-btn::before{
  background:radial-gradient(circle at center,
    rgba(99,102,241,0.55) 0%,
    rgba(99,102,241,0.30) 25%,
    rgba(99,102,241,0.10) 50%,
    transparent 75%) !important;
}
html.light-mode .mic-instruction{
  color:#1e293b !important;
  opacity:1 !important;
  text-shadow:0 1px 2px rgba(255,255,255,0.6);
  font-weight:600 !important;
}
html.light-mode .mic-instruction strong{color:#4f46e5 !important;}
/* Camera toggle button visibility on light backdrop */
html.light-mode .gear-slot button,
html.light-mode #vision-gear-slot button{
  background:rgba(99,102,241,0.10) !important;
  border-color:rgba(99,102,241,0.30) !important;
  color:#4338ca !important;
}

/* ---------- Canonical side-by-side cam + mic layout (2026-04-28) ----------
 * Any talk page that wraps its cam-dock + .mic-area in a `.cam-mic-row` div
 * gets the same Henry-style side-by-side behavior automatically:
 *   - cam off  → mic centered, cam dock hidden
 *   - cam on   → cam pip + mic share the row, both centered
 * No per-page bespoke CSS required. Pages opt in by:
 *   <div class="cam-mic-row">
 *     <div id="cam-dock"></div>
 *     <div class="mic-area">...</div>
 *   </div>
 */
.cam-mic-row{
  display:flex;
  flex-direction:row;
  align-items:center;
  justify-content:center;
  width:100%;
  margin:20px 0;
  min-height:170px;
  gap:24px;
}
body:not(.cam-active) .cam-mic-row > [id$="cam-dock"]{display:none !important}
body.cam-active .cam-mic-row > [id$="cam-dock"],
body.cam-active .cam-mic-row > .mic-area{
  flex:1 1 0;
  display:flex;
  align-items:center;
  justify-content:center;
  min-width:0;
}
body.cam-active .cam-mic-row > [id$="cam-dock"]{flex-direction:row !important}

/* ---------- Canonical dual-circle (cam-pip + mic-btn) — 2026-04-28 ----------
 * Every talk page gets the same dual-circle when the user clicks the eyeball.
 * Cam pip is forced to a perfect circle matching mic-btn proportions.
 * Per-page bespoke CSS (Rosie 18px square, Avery no-radius square, etc.) was
 * causing visual drift; this rule wins via attribute selector + !important so
 * the eye-icon always opens to two matching circles. */
body[data-ai-slug] #vision-pip{
  width: clamp(110px, 21vw, 170px) !important;
  height: clamp(110px, 21vw, 170px) !important;
  border-radius: 50% !important;
  overflow: hidden !important;
  position: relative;
  z-index: 2;
}
body[data-ai-slug] #vision-pip video{
  width: 100% !important;
  height: 100% !important;
  object-fit: cover !important;
}
/* Hide the cam-pip placeholder UNTIL the user opts in (clicks camera icon).
 * Rosie + others had `display:block !important` on `#vision-pip` which made
 * an empty dark circle hover above their portrait at all times. The `html`
 * prefix bumps specificity over per-page `body[data-ai-slug="X"]` overrides.
 * Once cam is active OR has-stream, vision-agent toggles `.active` and the
 * canonical sizing/circle rule above takes over. */
html body[data-ai-slug] #vision-pip:not(.active):not(.has-stream){
  display: none !important;
}
/* When cam IS active but stream not yet attached, show a clean dark
 * placeholder circle so the user knows the dock is alive. */
html body[data-ai-slug] #vision-pip.active:not(.has-stream){
  background: #1f2937 !important;
  border: 2px solid rgba(255,255,255,0.15) !important;
}

/* 2026-05-15 Henry: chat textarea text-color hardening.
 * Jason hit: after the first submit on Aegis, every subsequent live STT
 * write into the chat textarea painted in BLACK over the dark page bg.
 * Root cause: WebKit's autofill / user-modified state engaged once the
 * page started programmatically clearing+rewriting input.value, which
 * overrides the inline color via -webkit-text-fill-color. The inline
 * color:#f0f2f8 was being shadowed.
 *
 * Fix: lock light text on dark theme for ANY chat textarea (id matches
 * <slug>-text-input) using -webkit-text-fill-color !important, which
 * sits above the autofill paint cascade. Light-mode rule restores dark
 * text on the matching white bg. Modular: applies to every talk page. */
html textarea[id$="-text-input"]{
  color: #f0f2f8 !important;
  -webkit-text-fill-color: #f0f2f8 !important;
  caret-color: #f0f2f8 !important;
}
html textarea[id$="-text-input"]:-webkit-autofill,
html textarea[id$="-text-input"]:-webkit-autofill:hover,
html textarea[id$="-text-input"]:-webkit-autofill:focus,
html textarea[id$="-text-input"]:-webkit-autofill:active{
  -webkit-text-fill-color: #f0f2f8 !important;
  caret-color: #f0f2f8 !important;
  -webkit-box-shadow: 0 0 0 1000px rgba(15,23,42,0.6) inset !important;
  transition: background-color 9999s ease-out !important;
}
html.light-mode textarea[id$="-text-input"]{
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  caret-color: #0f172a !important;
}
html.light-mode textarea[id$="-text-input"]:-webkit-autofill,
html.light-mode textarea[id$="-text-input"]:-webkit-autofill:hover,
html.light-mode textarea[id$="-text-input"]:-webkit-autofill:focus,
html.light-mode textarea[id$="-text-input"]:-webkit-autofill:active{
  -webkit-text-fill-color: #0f172a !important;
  caret-color: #0f172a !important;
  -webkit-box-shadow: 0 0 0 1000px rgba(255,255,255,0.95) inset !important;
}
