/* ============================================================================
   FoxOS SHARED WEB-APP SHELL — the ONE source for the chat-shell chrome.
   Canon: 01_global_context/SHARED_WEBAPP_TEMPLATE_SPEC.md (EXTRACTION GATE).
   Every FoxOS surface (candidate /interview, /line front door, /app cockpit)
   links this file. Per-surface = config + brain + surface-specific CSS only.
   Fix the shell HERE → all three inherit. Do NOT re-copy these rules inline.
   (Stage 1 of the extraction: drift-prone chrome only — layout, color grammar,
   composer, bubbles, safe-area. DOM/brain unification is Stage 2.)
   ============================================================================ */

:root {
  /* WhatsApp-faithful palette — identical across every surface */
  --wa-bg:#0b141a; --wa-in:#202c33; --wa-out:#005c4b; --wa-head:#1f2c34;
  --wa-text:#e9edef; --wa-sub:#8696a0; --wa-accent:#00a884; --wa-link:#53bdeb;
  --wa-rec:#ff3b30;          /* red — voice-note recording */
  --fox-end:#ea0038;         /* red — live call End/hang-up. RED IS ONLY FOR LIVE. */
}

* { box-sizing:border-box; -webkit-tap-highlight-color:transparent; }

/* ── FIXED APP: the PAGE never scrolls; only the message list does ──────────── */
/* overscroll-behavior:none kills iOS Safari rubber-band so the PAGE truly freezes
   (the report was "page doesn't freeze" in Safari — this is the page-level half). */
html, body { height:100%; margin:0; overflow:hidden; overscroll-behavior:none; }
body { touch-action:manipulation; background:var(--wa-bg); color:var(--wa-text);
  font:16px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif; }

/* root app container (surfaces use #screen or #screen2).
   ── DOCUMENTED PRODUCTION PATTERN (World Bank data-ai-chatbot #96 / Sparka.ai): NO position:fixed.
   The root is a normal-flow flex COLUMN sized with 100dvh; combined with the viewport meta token
   `interactive-widget=resizes-content`, iOS Safari resizes the LAYOUT VIEWPORT (and thus dvh) when
   the toolbar/keyboard changes — so the header pins, the message list absorbs the resize, and the
   composer stays on-screen WITHOUT any fixed-position fighting. 100vh is the fallback for engines
   without dvh; 100dvh overrides where supported.
   display is handled per-state so /line's show/hide toggle (#screen2 hidden until .show) is preserved. */
#screen, #screen2 {
  height:100vh;            /* fallback */
  height:100dvh;           /* overrides where supported — tracks toolbar+keyboard correctly */
  /* v7 #6: iOS keyboards OVERLAY instead of resizing dvh — shell.js keyboardLock() sets
     --fox-vvh to the visual viewport height while the keyboard is open, clamping the flex
     column so the header stays pinned at the visual top. Unset = normal dvh behavior. */
  height:var(--fox-vvh, 100dvh);
  display:flex; flex-direction:column; overflow:hidden; background:var(--wa-bg); }

/* v7.3 round 4 — REAL-DEVICE keyboard fix: while the keyboard is open, keyboardLock()
   adds `.kb-open` on <html>. Lock html+body (fixed, no overflow) so iOS Safari cannot
   scroll the DOCUMENT to reveal the focused field (that was dragging the header off the
   top). The layout then moves ONLY via --fox-vvh. Config-safe, no frame changes. */
:root.kb-open, :root.kb-open body {
  position:fixed; top:0; left:0; right:0; width:100%;
  overflow:hidden; overscroll-behavior:none; -webkit-overflow-scrolling:auto; }
/* FIX 17 (v39, ADDITIVE — the locked layout above is unchanged): Safari (repro on iOS
   beta, keyboard + AutoFill bar) can keep the VISUAL viewport offset below the layout
   top even with html/body pinned — the composer then sits behind the keyboard.
   shell.js mirrors visualViewport.offsetTop into --fox-vvo while kb-open; translating
   the app root by it re-aligns the flex column with the VISIBLE viewport. --fox-vvo is
   0 wherever the viewport isn't displaced, so Chrome/Brave render exactly as before. */
:root.kb-open #screen, :root.kb-open #screen2 {
  transform: translateY(var(--fox-vvo, 0px)); }
#screen { display:flex; }                /* candidate / app: always shown */
#screen2 { display:none; }               /* /line: hidden until JS adds .show */
#screen2.show { display:flex; }

/* HEADER — first child of the flex-column root, OUTSIDE the scroller, so it pins with NO
   position:sticky needed (flex:0 0 auto = take natural height, never grow/shrink). */
.wa-head { background:var(--wa-head); padding:calc(7px + env(safe-area-inset-top)) 12px 7px;
  display:flex; align-items:center; gap:10px; flex:0 0 auto; }
.wa-head .meta { min-width:0; flex:1; }
.wa-head .nm { font-size:15px; font-weight:600; color:var(--wa-text); }
.wa-head .st { font-size:11.5px; color:var(--wa-sub); }
.wa-head .st.live { color:var(--wa-accent); }
/* HEADER CONTROL PILL (SHARED) — the call + video buttons live in ONE rounded
   charcoal pill with a thin vertical divider between them. Every surface's
   .wa-head .icons inherits this automatically; per-vertical only the glyphs differ. */
.wa-head .icons { display:flex; align-items:stretch; flex:none; gap:0;
  background:#1a222c; border:1px solid #2a3744; border-radius:999px; padding:3px; }
.wa-head .icons > .iconbtn, .wa-head .icons > .ic { width:42px; height:32px; border-radius:0; }
.wa-head .icons > * + * { border-left:1px solid #2a3744; }          /* divider between the two icons */
.wa-head .icons > *:first-child { border-radius:999px 0 0 999px; }  /* round the outer ends so the */
.wa-head .icons > *:last-child  { border-radius:0 999px 999px 0; }  /* live-call red fill follows the pill */

/* CLEAR-SPACE (brand): a head-mark avatar gets internal padding so the mark never
   bleeds to the circle edge (~13%). Opt-in via .av.headmark so photo avatars are
   unaffected. Mirrors the footer Powered-by mark rule below. */
.wa-head .av.headmark img { width:74%; height:74%; object-fit:contain; margin:auto; }

/* MESSAGE LIST — the ONLY scroll region. min-height:0 lets it shrink/scroll
   instead of pushing the composer off-screen. */
.wa-body { flex:1 1 auto; min-height:0; overflow-y:auto; overflow-x:hidden;
  -webkit-overflow-scrolling:touch;       /* momentum scroll inside the list on iOS Safari */
  overscroll-behavior:contain;            /* scroll stays in the list; never chains to the (frozen) page */
  padding:14px 9px; display:flex; flex-direction:column; gap:7px; }

/* message bubbles */
.m { max-width:84%; padding:7px 10px 6px; border-radius:8px; font-size:13.5px; line-height:1.45;
  animation:fox-pop .2s ease; word-wrap:break-word; overflow-wrap:anywhere; white-space:pre-wrap; }
@keyframes fox-pop { from { opacity:0; transform:translateY(5px); } to { opacity:1; transform:none; } }
.m.in { background:var(--wa-in); color:var(--wa-text); align-self:flex-start; border-top-left-radius:2px; }
.m.out { background:var(--wa-out); color:#e9edef; align-self:flex-end; border-top-right-radius:2px; }
.m a { color:var(--wa-link); }

/* COMPOSER — last child of the flex-column root, OUTSIDE the scroller (flex:0 0 auto), so it
   pins to the bottom without any viewport-unit math. L/R insets = no notch clip. NO 100vw (flex
   already bounds the width). The bottom safe-area inset is owned by whichever element is actually
   LAST in the column: when the .wa-secure/.fox-poweredby footer follows, the pill carries it (see
   below); only when .wa-foot is itself the last child (composer-only surfaces) does it add the
   inset — otherwise it would be counted twice and open an oversized gap in iOS standalone/PWA. */
.wa-foot { background:var(--wa-head); display:flex; align-items:flex-end; gap:7px; flex:0 0 auto;
  position:relative; width:100%;
  padding:7px calc(8px + env(safe-area-inset-right)) 7px calc(8px + env(safe-area-inset-left)); }
.wa-foot:last-child { padding-bottom:calc(7px + env(safe-area-inset-bottom)); }
/* flex:1 1 auto + min-width:0 = the key that lets the input shrink so the trailing
   camera/mic/send buttons stay fully on-screen. */
.inwrap { flex:1 1 auto; min-width:0; background:#2a3942; border:1px solid #3b4a54; border-radius:20px;
  display:flex; align-items:center; gap:6px; padding:8px 12px; min-height:44px; }
/* covers every surface's composer textarea (.field / .field2) — the `.inwrap .field2`
   selector matches /line's specificity so the min-width:0 fix actually reaches it. */
.inwrap .field, .inwrap textarea, .inwrap .field2 { flex:1 1 auto; min-width:0; background:transparent;
  border:0; outline:none; resize:none; color:var(--wa-text); font:inherit; font-size:15px; line-height:1.35;
  max-height:120px; overflow-y:auto; }
.inwrap .field::placeholder, .inwrap textarea::placeholder, .inwrap .field2::placeholder { color:var(--wa-sub); }

/* ── BUTTON COLOR GRAMMAR — NEUTRAL at rest; RED only when LIVE ─────────────── */
/* header call/video buttons */
.iconbtn { width:40px; height:40px; border:0; border-radius:50%; display:grid; place-items:center;
  cursor:pointer; padding:0; background:transparent; }
.iconbtn svg { width:20px; height:20px; display:block; fill:var(--wa-text); }
.iconbtn.call { background:transparent; }                 /* neutral at rest */
.iconbtn.call svg { fill:var(--wa-text); }
.iconbtn.call .i-end { display:none; }
.iconbtn.call.ending { background:var(--fox-end); }       /* live call → red End in place */
.iconbtn.call.ending svg { fill:#fff; }
.iconbtn.call.ending .i-call, .iconbtn.call.ending .i-start { display:none; }
.iconbtn.call.ending .i-end { display:block; }
.iconbtn.call.disabled { opacity:.45; pointer-events:none; }   /* greyed, stays in place */

/* ── COMPOSER — TWO STATES (v7.3, WhatsApp-exact) ─────────────────────────────
   STATE A (field empty)     : [+] [pill] [camera] [mic]  — camera+mic OUTSIDE the pill.
   STATE B (field has text)  : camera+mic REMOVED, pill expands, ONE green send (paper-plane).
   RECORDING                 : pill/camera/mic hidden, rec-ui (timer+cancel) fills, green send sends.
   State is driven by `.wa-foot.has-text` / `.wa-foot.recording` (shell.js). ── */

/* State-A trailing controls: camera + mic, outside the pill, right side */
.wa-foot > .cam.cbtn, .wa-foot > .mic.cbtn { width:40px; height:44px; display:grid; place-items:center;
  flex:none; cursor:pointer; background:transparent; border:0; padding:0; }
.wa-foot > .cam.cbtn svg, .wa-foot > .mic.cbtn svg { width:25px; height:25px; fill:var(--wa-sub); display:block; }

/* Green send button — HIDDEN in State A; shown in State B + while recording */
.sendbtn { width:44px; height:44px; border-radius:50%; background:var(--wa-accent); display:none;
  place-items:center; flex:none; cursor:pointer; border:0; padding:0; transition:transform .12s; }
.sendbtn:active { transform:scale(.92); }
.sendbtn svg, .sendbtn .i-send { width:22px; height:22px; fill:#fff; display:block; }

/* STATE B: camera + mic gone (not squeezed), green send appears; pill takes the freed space */
.wa-foot.has-text > .cam.cbtn, .wa-foot.has-text > .mic.cbtn { display:none; }
.wa-foot.has-text .sendbtn { display:grid; }

/* RECORDING: pill + camera + mic hidden; rec-ui fills the row; green send sends the note */
.wa-foot.recording > .inwrap,
.wa-foot.recording > .cam.cbtn,
.wa-foot.recording > .mic.cbtn { display:none; }
.wa-foot.recording .sendbtn { display:grid; }

/* ── FOOTER (SHARED): just a subtle "Powered by Agendos" pill (v7.1: the encrypted-
   line row was removed). shell.js injects the pill and hides any legacy footer node;
   the build stamp is a HIDDEN data-build attribute (cache-debug only), never visible. */
.wa-secure { display:none !important; }   /* v7.1: legacy footer row retired */
/* the whole Powered-by is a centered, subdued DARK rounded pill */
.fox-poweredby { background:var(--wa-head); flex:none; display:flex; justify-content:center;
  padding:1px 8px calc(8px + env(safe-area-inset-bottom)); }
.fox-poweredby .pb-pill { display:inline-flex; align-items:center; gap:7px;
  background:#141c24; border:1px solid #233039; border-radius:999px; padding:3px 11px 3px 4px; }
/* a small WHITE CIRCLE holding the Agendos head mark */
.fox-poweredby .pb-mark { width:18px; height:18px; border-radius:50%; background:#fff; flex:none;
  display:grid; place-items:center; overflow:hidden; }
/* CLEAR-SPACE: the head mark keeps ~13% internal padding, never touching the edge */
.fox-poweredby .pb-mark img { width:74%; height:74%; object-fit:contain; display:block; }
.fox-poweredby .pb-txt { color:var(--wa-sub); font-size:10.5px; opacity:.85; letter-spacing:.1px; }

/* ── TYPING INDICATOR — WhatsApp 3-dot animated bubble (shell.js typingBubble()) ── */
.m.typing { display:inline-flex; align-items:center; gap:4px; width:auto; max-width:max-content;
  padding:11px 13px; }
.m.typing .tdot { width:7px; height:7px; border-radius:50%; background:var(--wa-sub);
  animation:fox-typing 1.3s infinite ease-in-out; }
.m.typing .tdot:nth-child(2) { animation-delay:.18s; }
.m.typing .tdot:nth-child(3) { animation-delay:.36s; }
@keyframes fox-typing { 0%,60%,100% { transform:translateY(0); opacity:.45; }
  30% { transform:translateY(-4px); opacity:1; } }

/* ── VOICE-NOTE RECORDING STATE — inline pill (cancel + red dot + timer); the green
   send button to its right sends the note. Shown only under `.wa-foot.recording`. ── */
.rec-ui { display:none; flex:1 1 auto; min-width:0; align-items:center; gap:10px;
  background:#2a3942; border:1px solid #3b4a54; border-radius:20px; min-height:44px; padding:6px 14px; }
.wa-foot.recording .rec-ui { display:flex; }
.rec-ui .rec-cancel { width:34px; height:34px; border:0; border-radius:50%; background:transparent;
  display:grid; place-items:center; cursor:pointer; flex:none; padding:0; }
.rec-ui .rec-cancel svg { width:20px; height:20px; fill:var(--wa-sub); display:block; }
.rec-ui .rec-cancel:active { background:rgba(255,255,255,.08); }
.rec-ui .dot { width:11px; height:11px; border-radius:50%; background:var(--wa-rec); flex:none;
  box-shadow:none; animation:fox-blink 1s infinite; }
.rec-ui .rlabel { color:var(--wa-sub); font-size:12px; }
.rec-ui .rtime { flex:1; font-size:13.5px; color:var(--wa-text); font-variant-numeric:tabular-nums; }
@keyframes fox-blink { 50% { opacity:.25; } }

/* v7.3: the Powered-by pill is HIDDEN from the composer row (markup kept; placement is
   the tomorrow-redesign batch's call). */
.fox-poweredby { display:none !important; }
.sendbtn.recording .i-mic { display:none; }
.sendbtn.recording .i-send { display:block; }

/* ── PLAYABLE VOICE-NOTE BUBBLE (shell.js buildAudioPlayer) — lives inside .m.out ── */
.wa-voice { min-width:198px; max-width:240px; }
.wa-voice-row { display:flex; align-items:center; gap:9px; }
.wa-voice-btn { width:34px; height:34px; border:0; border-radius:50%; background:rgba(255,255,255,.18);
  display:grid; place-items:center; cursor:pointer; flex:none; padding:0; }
.wa-voice-btn svg { width:20px; height:20px; fill:#e9edef; display:block; }
.wa-voice-btn .i-pause { display:none; }
.wa-voice.playing .wa-voice-btn .i-play { display:none; }
.wa-voice.playing .wa-voice-btn .i-pause { display:block; }
.wa-voice-track { flex:1 1 auto; height:3px; border-radius:2px; background:rgba(255,255,255,.28); position:relative; }
.wa-voice-fill { position:absolute; left:0; top:0; bottom:0; width:0%; border-radius:2px; background:#e9edef; }
.wa-voice-dur { font-size:11px; color:rgba(233,237,239,.85); font-variant-numeric:tabular-nums;
  flex:none; min-width:30px; text-align:right; }
.wa-voice-tx { display:none; margin-top:6px; font-size:13px; line-height:1.4; color:#e9edef; opacity:.92;
  border-top:1px solid rgba(255,255,255,.14); padding-top:5px; white-space:pre-wrap; }
.wa-voice.has-tx .wa-voice-tx { display:block; }

/* ── SENT ATTACHMENT (shell.js buildAttachment) — inside an .m.out bubble ────── */
/* image → WhatsApp-style thumbnail (tap to enlarge); non-image → the DOC tile */
.wa-att-img { line-height:0; }
.wa-att-img img { display:block; max-width:230px; width:100%; max-height:320px;
  object-fit:cover; border-radius:7px; cursor:pointer; }
.docb { display:flex; align-items:center; gap:9px; min-width:180px; background:rgba(0,0,0,.18);
  padding:8px; border-radius:7px; }
.docb .ic { width:30px; height:36px; border-radius:5px; background:#cf4b4b; display:grid;
  place-items:center; color:#fff; font-size:10px; font-weight:700; flex:none; }
.docb .dn { font-size:12.5px; font-weight:600; }
.docb .dm { font-size:10.5px; opacity:.7; }

/* ── FULL-SCREEN IMAGE LIGHTBOX (tap anywhere to dismiss) ─────────────────────── */
.wa-lightbox { position:fixed; inset:0; z-index:200; display:none; align-items:center;
  justify-content:center; background:rgba(0,0,0,.92); -webkit-tap-highlight-color:transparent;
  padding:calc(8px + env(safe-area-inset-top)) 12px calc(8px + env(safe-area-inset-bottom)); }
.wa-lightbox.show { display:flex; animation:fox-pop .15s ease; }
.wa-lightbox img { max-width:100%; max-height:100%; object-fit:contain; border-radius:4px; }

/* v7.4 FIX 1: in-app PDF overlay (never navigates → the live call + thread survive) */
.wa-docov { position:fixed; inset:0; z-index:210; display:none; flex-direction:column;
  background:rgba(0,0,0,.96); }
.wa-docov.show { display:flex; animation:fox-pop .15s ease; }
.wa-docov-bar { flex:none; display:flex; align-items:center; gap:10px;
  padding:calc(8px + env(safe-area-inset-top)) 14px 8px; background:var(--wa-head); color:var(--wa-text); }
.wa-docov-title { flex:1; min-width:0; font-size:14px; font-weight:600; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.wa-docov-ext, .wa-docov-close { flex:none; width:34px; height:34px; display:grid; place-items:center;
  border:0; border-radius:50%; background:transparent; color:var(--wa-text); font-size:18px;
  text-decoration:none; cursor:pointer; }
.wa-docov-ext:active, .wa-docov-close:active { background:rgba(255,255,255,.1); }
.wa-docov-frame { flex:1; width:100%; border:0; background:#fff; }

/* FIX 5: generated-PDF card with a page-1 poster thumbnail (opens the overlay on tap) */
.m .docposter { max-width:230px; background:rgba(0,0,0,.18); border-radius:9px; overflow:hidden; }
.m .docposter img { display:block; width:100%; height:auto; max-height:300px; object-fit:cover;
  object-position:top center; background:#fff; }
.m .docposter .dn { font-size:12.5px; font-weight:600; padding:7px 9px; }
