/* Weft — layout and components for the chat view
 *
 * Lifted verbatim from the integration bench (web/demo/3-bench.html) when the client
 * moved to ES modules. Kept as a separate file rather than inline so the CSP can be a
 * plain 'self' with no nonce, and so the browser can cache it across page loads.
 */

/* ---- layer 0: canvas, the floor. Fixed, full viewport, never reacts to content. */
#cv-wrap{position:fixed;inset:0;z-index:0}
#cv{position:absolute;inset:0;width:100%;height:100%}

/* ---- layer 1: chat log, floats over the scene, transparent background */
#log{
  position:fixed; left:0; right:0; bottom:0; z-index:1;
  padding:16px; padding-bottom:calc(90px + env(safe-area-inset-bottom,0px) + var(--input-h, 0px));
  display:flex; flex-direction:column; gap:10px;
  overflow-y:auto; max-height:100dvh;
  pointer-events:none;           /* let taps fall through to canvas */
}
#log > *{pointer-events:auto}    /* bubbles themselves still clickable */
.row{display:flex;flex-direction:column;align-items:flex-start;gap:4px}
.row.user{align-items:flex-end}
.bubble{
  max-width:82%; padding:10px 14px; border-radius:16px;
  background:color-mix(in srgb, var(--panel) 82%, transparent);
  backdrop-filter:blur(6px);
  box-shadow:0 2px 6px rgba(0,0,0,.12);
  white-space:pre-wrap; overflow-wrap:break-word;
}
.row.user .bubble{border-bottom-right-radius:5px}
.row.ai .bubble{border-bottom-left-radius:5px}
/* identity tint: bubbles always wear the live palette. :root defines DEFAULT
   (fern/twilight); setBuddy() overrides the vars per identity, un-dressing =
   removing the overrides so theme defaults shine through. */
:root{
  --buddy-a:var(--fern);
  --buddy-b:var(--twilight);
}
.row.ai .bubble{
  border:3px solid var(--buddy-a);
  background:color-mix(in srgb, var(--buddy-a) 12%,
              color-mix(in srgb, var(--panel) 50%, transparent));
}
/* user bubbles: same frosted glass, neutral — identity tint keys off the SENDER
   (colour-B) once the bridge supplies it, not the picked buddy */
.row .bubble{
  background:color-mix(in srgb, var(--panel) 50%, transparent);
}
.row.user .bubble{
  border:3px solid color-mix(in srgb, var(--buddy-b) 55%, transparent);
}
:root[data-buddy] #dot{background:radial-gradient(circle at 30% 30%, var(--buddy-a), var(--buddy-b))}

/* ---- layer 2: chrome (input bar). Fixed, floats over bubbles. */
#bar{
  position:fixed; left:0; right:0; bottom:0; z-index:2;
  display:flex; gap:8px; align-items:flex-end;
  padding:10px 12px; padding-bottom:calc(10px + env(safe-area-inset-bottom,0px));
  background:color-mix(in srgb, var(--panel) 85%, transparent);
  backdrop-filter:blur(8px);
  border-top:1px solid var(--edge);
}
#bar > *{flex-shrink:0}
#in{
  flex:1; min-width:0; resize:none; font:inherit;
  background:color-mix(in srgb, var(--in) 90%, transparent);
  border:1px solid var(--inedge); border-radius:20px; color:var(--text);
  padding:10px 16px; max-height:120px; line-height:1.4;
  transition:max-height .15s;
}
#in:focus{outline:none; border-color:var(--fern)}
button{background:var(--twilight); color:#fff; border:0; border-radius:20px; padding:10px 16px; font:inherit; cursor:pointer}

/* ---- layer 3: top chrome + drawer pages, above everything */
#topbar{
  position:fixed; top:0; left:0; right:0; z-index:3;
  display:flex; align-items:center; gap:10px; padding:8px 14px;
  padding-top:calc(8px + env(safe-area-inset-top,0px));
  background:color-mix(in srgb, var(--panel) 60%, transparent);
  backdrop-filter:blur(8px);
  border-bottom:1px solid var(--edge);
}
/* aero rule: chrome ON the glass rail is solid; the rail itself floats */
#stat-led{
  width:14px; height:14px; border-radius:50%; flex-shrink:0;
  background:var(--dim); box-shadow:0 0 8px 1px currentColor;
  transition:background .4s;
}
#stat-led.red{background:#e05555; color:#e05555}
#stat-led.green{background:var(--fern); color:var(--fern)}
#stat-led.blue{background:#4da3ff; color:#4da3ff}
#stat-led.amber{background:#f0a832; color:#f0a832; animation:ledpulse 1s ease-in-out infinite}
@keyframes ledpulse{0%,100%{opacity:.45}50%{opacity:1}}
/* pick chips: presence pills wearing their palette (solid, on the glass rail) */
#pick{display:flex; gap:6px; overflow-x:auto; scrollbar-width:none; flex:1}
#pick::-webkit-scrollbar{display:none}
#pick .chip{
  display:flex; align-items:center; gap:6px; padding:6px 12px; border-radius:14px;
  background:var(--in); color:var(--text); border:1px solid var(--inedge);
  font-size:13px; cursor:pointer; white-space:nowrap; flex-shrink:0;
}
#pick .chip .led{width:8px; height:8px; border-radius:50%; background:var(--dim)}
#pick .chip.on{border-color:var(--fern)}
#pick .chip:hover{border-color:var(--fern)}
#topbar span{font-size:13px; color:var(--dim); flex:1}
#burger{background:none; border:0; cursor:pointer; padding:6px; border-radius:8px; display:flex; flex-direction:column; gap:4px}
#burger div{width:20px; height:2px; background:var(--dim); border-radius:2px}
#burger:hover div{background:var(--text)}
#scrim{position:fixed; inset:0; z-index:4; background:rgba(0,0,0,.35); display:none}
#scrim.show{display:block}
#drawer{
  position:fixed; top:0; right:0; height:100%; width:calc(100vw - 36px); max-width:520px; z-index:5;
  background:color-mix(in srgb, var(--panel) 88%, transparent);
  backdrop-filter:blur(14px);
  border-left:1px solid var(--edge);
  transform:translateX(100%); transition:transform .28s ease;
  padding:0; display:flex; flex-direction:column;
  box-shadow:-8px 0 24px rgba(0,0,0,.25);
  overflow-y:auto;
}
/* the weft footer: fixed at the drawer's bottom, wordmark + links */
#drawer-foot{
  margin-top:auto; padding:14px 18px; padding-bottom:calc(14px + env(safe-area-inset-bottom,0px));
  border-top:1px solid var(--edge); flex-shrink:0;
  display:flex; align-items:center; gap:14px;
}
#drawer-foot .wordmark{font-size:15px; font-weight:700; letter-spacing:.04em; color:var(--text)}
#drawer-foot .wordmark em{font-style:normal; color:var(--fern)}
#drawer-foot .links{margin-left:auto; display:flex; gap:12px}
#drawer-foot a{color:var(--dim); font-size:13px; text-decoration:none; padding:4px 6px; border-radius:6px}
#drawer-foot a:hover{color:var(--text); background:var(--in)}
#drawer-foot .slogan{font-size:11px; color:var(--dim); margin-top:2px}
#drawer.open{transform:translateX(0)}
/* drawer anatomy: fixed header (title + close) / scrollable body / fixed footer */
#drawer-head{
  position:sticky; top:0; z-index:1; flex-shrink:0;
  padding:16px 18px;
  padding-top:calc(16px + env(safe-area-inset-top,0px));
  display:flex; align-items:center; gap:12px;
  background:var(--panel); backdrop-filter:blur(14px);
  border-bottom:1px solid var(--edge);
}
#drawer-head h2{font-size:16px; font-weight:700; margin:0; flex:1}
#drawer-close{background:none; border:0; cursor:pointer; color:var(--dim);
  font-size:20px; line-height:1; padding:6px 10px; border-radius:8px}
#drawer-close:hover{color:var(--text); background:var(--in)}
#drawer-body{flex:1; display:flex; flex-direction:column; gap:14px; min-height:0;
  padding:14px 18px; overflow-y:auto}
#drawer h3{font-size:14px; color:var(--dim); font-weight:600; letter-spacing:.05em}
#drawer label{display:flex; gap:8px; align-items:center; padding:8px 10px; border-radius:8px; cursor:pointer; font-size:14px}
#drawer label:hover{background:var(--in)}

/* ============================================================================
   Views added when the client moved to ES modules: the login card, the forced
   password change, and the boot-error card. Same glass-and-fern language as the
   chat window, so signing in does not feel like a different application.
   ============================================================================ */

/* The shell is empty until main.js mounts a view; give it the full stage. */
#app{min-height:100dvh}

/* Centred single-card layouts (login, password change, boot error). */
.centre{
  min-height:100dvh;
  display:flex; align-items:center; justify-content:center;
  padding:24px 16px;
}

.card{
  width:100%; max-width:380px;
  display:flex; flex-direction:column; gap:10px;
  padding:28px 24px;
  border-radius:18px;
  background:color-mix(in srgb, var(--panel) 50%, transparent);
  border:1px solid var(--edge);
  box-shadow:0 8px 28px rgba(0,0,0,.18);
  backdrop-filter:blur(6px);
}

.card h1{font-size:1.15rem; font-weight:600; margin-bottom:2px}

.card label{
  font-size:.78rem; letter-spacing:.04em; text-transform:uppercase;
  color:var(--dim); margin-top:8px;
}

.card input[type=text],
.card input[type=password]{
  width:100%; padding:11px 13px;
  font:inherit; color:var(--text);
  background:var(--in); border:1px solid var(--inedge); border-radius:11px;
  /* 16px minimum, or iOS Safari zooms the viewport on focus and never zooms back. */
  font-size:16px;
}
.card input:focus-visible{
  outline:2px solid var(--fern); outline-offset:1px; border-color:var(--fern);
}

.card button[type=submit]{
  margin-top:14px; padding:12px 16px;
  font:inherit; font-weight:600; color:#12141a;
  background:var(--fern); border:0; border-radius:11px; cursor:pointer;
}
.card button[type=submit]:hover{filter:brightness(1.06)}
.card button[type=submit]:disabled{opacity:.6; cursor:default; filter:none}

/* Secondary actions: "sign out instead". A button, because it acts — not a link. */
.linkish{
  align-self:flex-start;
  margin-top:4px; padding:4px 0;
  font:inherit; font-size:.85rem;
  color:var(--dim); background:none; border:0; cursor:pointer;
  text-decoration:underline; text-underline-offset:3px;
}
.linkish:hover{color:var(--text)}

.form-error{
  margin-top:8px; padding:9px 12px;
  font-size:.88rem; color:#ffb4a8;
  background:color-mix(in srgb, #c62828 22%, transparent);
  border:1px solid color-mix(in srgb, #c62828 45%, transparent);
  border-radius:9px;
}

.hint{font-size:.8rem; color:var(--dim); margin-top:-2px}

/* The wordmark, login-sized. The e is the weft: the one letter that travels. */
.wordmark-lg{
  font-size:2.1rem; font-weight:700; letter-spacing:-.02em; line-height:1;
}
.wordmark-lg em{font-style:normal; color:var(--fern)}

.card .slogan{font-size:.85rem; color:var(--dim); margin-bottom:6px}

/* The drawer's slide already lives above (#drawer / #drawer.open) — do not restate it
   here, or the later rule silently wins and the timing changes for no reason.

   The scrim DOES need correcting. The bench toggled it with display:none/.show, which
   cannot animate and — more to the point — `display:none` beats any opacity rule, so
   the scrim would never appear at all and clicking outside would not close the drawer.
   Give it a real box and fade it instead. */
#scrim{
  display:block; opacity:0; pointer-events:none;
  transition:opacity .22s ease;
}
#scrim.open{opacity:1; pointer-events:auto}

#drawer-body label{display:block; padding:6px 0; cursor:pointer}
#drawer-body h3{
  margin-top:16px; margin-bottom:4px;
  font-size:.72rem; letter-spacing:.1em; color:var(--dim);
}
#drawer-body .linkish{margin-bottom:4px}

@media (prefers-reduced-motion: reduce){
  #drawer, #scrim{transition:none}
}

/* The login page's quiet tenants — one grey donut breathing at a time,
 * quarter-scale children of the chat donut, behind the card's glass.
 * Grey only, by the colour law: colour is reserved for heartbeat and speech. */
canvas.breathers{
  position:fixed; inset:0; z-index:0; pointer-events:none;
  /* A canvas with no CSS size displays at its ATTRIBUTE size — the backing
   * store — which here is the viewport times devicePixelRatio. Without these
   * lines the element is dpr× too big on screen (huge dotted lines) and, worse,
   * resize() reads its own inflated clientWidth, doubling the backing store on
   * every pass until the browser frowns. Explicit 100% breaks that loop: the
   * CSS box is always the viewport, the attribute is always the box times dpr,
   * and the two never feed back into each other. */
  width:100%; height:100%;
}
.centre{ position:relative; z-index:1; }
