/* ===========================================================================
   AI House-Design — Phase 2 conversational messenger  ·  REAL BUILD stylesheet.

   Externalised from site/mock/messenger-mock.html so the page satisfies the
   site CSP (style-src 'self'; no inline <style>, no inline style= attributes —
   dynamic values are set via CSSOM in messenger.js, which CSP does not govern).

   Design language: the drafting-paper tokens below are mirrored VERBATIM from
   site/designer.css so the messenger reads as the same product. Keep the :root
   block in sync with designer.css if the palette ever changes. Component rules
   are messenger-local (they do NOT import designer.css, to avoid selector
   collisions on shared names like .btn/.chip/.topbar).
   =========================================================================== */
:root{
  --paper:#e7edf2; --paper-2:#f4f7fa; --paper-3:#dbe3ea;
  --grid:rgba(31,92,153,0.055); --grid-major:rgba(31,92,153,0.10);
  --ink:#14273b; --ink-soft:#47596c; --ink-faint:#6b7c8d;
  --line:#c1ccd7; --line-soft:#d5dde5;
  --accent:#1f5c99; --accent-strong:#123f6b;
  --accent-tint:rgba(31,92,153,0.10); --accent-tint-2:rgba(31,92,153,0.18);
  --done:#3f8f6b; --done-tint:rgba(63,143,107,0.15);
  --active:#c08411; --active-tint:rgba(192,132,17,0.16);
  --planned:#7d8b99; --planned-tint:rgba(125,139,153,0.16);
  --risk:#b0553f; --risk-tint:rgba(176,85,63,0.14);
  --font-display:"Space Grotesk","Segoe UI",system-ui,sans-serif;
  --font-body:"IBM Plex Sans",system-ui,-apple-system,sans-serif;
  --font-mono:"IBM Plex Mono",ui-monospace,"SF Mono",Menlo,monospace;
  --r-sm:4px; --r-md:8px; --r-lg:14px;
  --shadow:0 1px 2px rgba(18,39,59,0.06),0 8px 24px rgba(18,39,59,0.07);
  --shadow-sm:0 1px 2px rgba(18,39,59,0.08);
  --topbar-h:60px;
  /* floor-plan render palette (from engine SVG output, verbatim) */
  --plan-room:#f7f5f1; --plan-room-line:#d9d4cc; --plan-wall:#33322f; --plan-door:#0e7c86;
}
*{box-sizing:border-box;}
html{scroll-behavior:smooth;}
body{
  margin:0; font-family:var(--font-body); color:var(--ink);
  background-color:var(--paper);
  background-image:
    linear-gradient(var(--grid) 1px,transparent 1px),
    linear-gradient(90deg,var(--grid) 1px,transparent 1px),
    linear-gradient(var(--grid-major) 1px,transparent 1px),
    linear-gradient(90deg,var(--grid-major) 1px,transparent 1px);
  background-size:24px 24px,24px 24px,120px 120px,120px 120px;
  background-attachment:fixed;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  line-height:1.55;
  /* the app is a full-height column: topbar / scrolling thread / pinned composer */
  height:100dvh; display:flex; flex-direction:column; overflow:hidden;
}
a{color:var(--accent); text-decoration-color:var(--accent-tint-2);}
a:hover{color:var(--accent-strong);}
:focus-visible{outline:2.5px solid var(--accent); outline-offset:2px; border-radius:2px;}
.skip-link{
  position:fixed; top:-60px; left:12px; z-index:100;
  background:var(--accent-strong); color:#fff; padding:10px 16px; border-radius:var(--r-md);
  font-family:var(--font-mono); font-size:0.85rem; transition:top 0.15s ease;
}
.skip-link:focus{top:12px; color:#fff;}
.visually-hidden{
  position:absolute; width:1px; height:1px; margin:-1px; padding:0; border:0;
  clip-path:inset(50%); overflow:hidden; white-space:nowrap;
}
/* The `hidden` attribute only hides via a USER-AGENT rule ([hidden]{display:none}),
   and in the cascade a normal AUTHOR declaration beats any normal user-agent one
   regardless of specificity (CSS Cascade 4 §6.2). So .empty-state{display:flex}
   silently defeated el.hidden = true and the "Describe a house" onboarding stayed
   on screen underneath the first turn. Re-assert it in the author origin, with
   !important so the next component that sets `display` cannot break it again. */
[hidden]{display:none !important;}

/* ===========================================================================
   Top bar (dashboard/designer idiom)
   =========================================================================== */
.topbar{
  flex:0 0 auto; position:sticky; top:0; z-index:40; height:var(--topbar-h);
  display:flex; align-items:center; gap:14px; padding:0 20px;
  background:rgba(244,247,250,0.88); backdrop-filter:blur(8px);
  border-bottom:1px solid var(--line);
}
.brand{display:flex; align-items:center; gap:11px; color:var(--ink); text-decoration:none;}
.brand-mark{
  display:grid; place-items:center; width:36px; height:36px; border-radius:var(--r-md);
  background:var(--accent-strong); color:#eaf2fb; box-shadow:var(--shadow-sm);
}
.brand-text{display:flex; flex-direction:column; line-height:1.1;}
.brand-title{font-family:var(--font-display); font-weight:600; font-size:1.06rem; letter-spacing:-0.01em;}
.brand-sub{
  font-family:var(--font-mono); font-size:0.66rem; text-transform:uppercase;
  letter-spacing:0.16em; color:var(--ink-faint); margin-top:2px;
}
.topbar-meta{margin-left:auto; display:flex; align-items:center; gap:10px;}
.meta-chip{
  display:inline-flex; align-items:center; gap:6px; padding:4px 10px;
  border:1px solid var(--line); border-radius:100px; background:var(--paper-2);
  font-family:var(--font-mono); font-size:0.72rem; color:var(--ink-soft); white-space:nowrap;
}
.meta-chip b{color:var(--ink); font-weight:600;}
/* Clear-conversation control. Neutral .btn at rest -- it must not read as an
   alarm while nothing is happening -- and takes the `risk` role only once armed,
   which is the state where the next press really does delete. The armed LABEL
   stays full-strength ink, not --risk: --risk on --risk-tint measures 3.9:1,
   under the 4.5:1 this 0.7rem type needs, and "are you sure?" is the one string
   on the page that must be legible. The red frame carries the warning. */
.history-clear.is-armed,
.history-clear.is-armed:hover{
  color:var(--ink); border-color:var(--risk); background:var(--risk-tint);
}

/* ===========================================================================
   Buttons (drafting palette — verbatim idiom from designer.css)
   =========================================================================== */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:7px;
  font-family:var(--font-mono); font-size:0.78rem; font-weight:500;
  color:var(--ink-soft); text-decoration:none; padding:7px 14px;
  border:1px solid var(--line); border-radius:var(--r-md);
  background:var(--paper-2); box-shadow:var(--shadow-sm); cursor:pointer; white-space:nowrap;
  transition:border-color 0.14s ease,color 0.14s ease,background 0.14s ease;
}
.btn:hover{color:var(--accent-strong); border-color:var(--accent-tint-2); background:var(--paper);}
.btn:disabled{opacity:0.55; cursor:not-allowed; box-shadow:none;}
.btn:disabled:hover{color:var(--ink-soft); border-color:var(--line); background:var(--paper-2);}
.btn-primary{
  font-family:var(--font-display); font-weight:600; font-size:0.92rem;
  color:#fff; background:var(--accent); border-color:var(--accent-strong);
}
.btn-primary:hover{color:#fff; background:var(--accent-strong); border-color:var(--accent-strong);}
.btn-primary:disabled:hover{color:#fff; background:var(--accent); border-color:var(--accent-strong);}
.btn-small{padding:4px 10px; font-size:0.7rem;}
.btn svg{flex:0 0 auto;}

/* ===========================================================================
   Thread — scrolling message history
   =========================================================================== */
.thread{
  flex:1 1 auto; min-height:0; overflow-y:auto; overflow-x:hidden;
  padding:22px clamp(14px,4vw,32px) 28px;
  display:flex; flex-direction:column; align-items:stretch; gap:18px;
  scroll-behavior:smooth;
}
.thread-inner{
  width:100%; max-width:820px; margin:0 auto;
  display:flex; flex-direction:column; gap:18px;
}

/* system note (public-test privacy — mirrors designer .public-notice) */
.sys-note{
  align-self:center; max-width:70ch; margin:0;
  padding:9px 15px; border-radius:var(--r-md);
  border-left:3px solid var(--active); background:var(--active-tint);
  color:var(--ink-soft); font-size:0.86rem; line-height:1.45; text-align:left;
}
.sys-tag{
  font-family:var(--font-mono); font-size:0.62rem; font-weight:600;
  letter-spacing:0.1em; text-transform:uppercase; color:var(--active); margin-right:6px;
}
/* "Restored" banner — same note idiom, but the calm accent rather than the amber
   the privacy warning owns: two amber bars stacked would read as two warnings. */
.sys-note.is-restored{border-left-color:var(--accent); background:var(--accent-tint);}
.sys-note.is-restored .sys-tag{color:var(--accent);}

/* empty state — the on-ramp before the first message */
.empty-state{
  align-self:center; width:100%; max-width:560px; margin:6vh 0 0;
  display:flex; flex-direction:column; align-items:center; gap:14px; text-align:center;
}
.empty-mark{
  display:grid; place-items:center; width:52px; height:52px; border-radius:var(--r-lg);
  background:var(--paper-2); border:1px solid var(--line); color:var(--accent); box-shadow:var(--shadow-sm);
}
.empty-title{margin:0; font-family:var(--font-display); font-weight:600; font-size:1.24rem; color:var(--ink);}
.empty-sub{margin:0; max-width:44ch; font-size:0.94rem; color:var(--ink-soft); line-height:1.5;}
.empty-examples{display:flex; flex-wrap:wrap; gap:8px; justify-content:center; margin-top:2px;}
/* follow-up phrasings that work once a plan exists (Phase 3) — quieter than the
   example chips on purpose: these are not clickable, they teach the vocabulary. */
.empty-follow{
  margin:10px 0 0; max-width:52ch; font-size:0.82rem; color:var(--ink-faint);
  line-height:1.9;
}
.empty-follow .ef-ex{
  display:inline-block; margin:0 3px;
  font-family:var(--font-mono); font-size:0.76rem; color:var(--ink-soft);
  border:1px dashed var(--line); border-radius:100px; padding:2px 9px;
  background:var(--paper-2); white-space:nowrap;
}

/* a turn = one exchange row; user right, assistant left */
.turn{display:flex; flex-direction:column; gap:6px;}
.turn.user{align-items:flex-end;}
.turn.assistant{align-items:flex-start;}
.turn-role{
  font-family:var(--font-mono); font-size:0.6rem; letter-spacing:0.12em;
  text-transform:uppercase; color:var(--ink-faint); padding:0 4px;
}

/* user bubble — filled blueprint ink */
.bubble-user{
  max-width:min(74%,560px); padding:11px 15px;
  border-radius:var(--r-lg) var(--r-lg) var(--r-sm) var(--r-lg);
  background:linear-gradient(180deg,var(--accent),var(--accent-strong));
  color:#fff; font-size:0.98rem; line-height:1.5;
  box-shadow:var(--shadow-sm); word-wrap:break-word; overflow-wrap:anywhere;
}
.bubble-user.is-chip{font-family:var(--font-mono); font-size:0.9rem;}

/* assistant short reply bubble — light */
.bubble-asst{
  max-width:min(84%,620px); padding:10px 15px;
  border-radius:var(--r-lg) var(--r-lg) var(--r-lg) var(--r-sm);
  background:#fff; color:var(--ink); border:1px solid var(--line);
  font-size:0.96rem; line-height:1.5; box-shadow:var(--shadow-sm); overflow-wrap:anywhere;
}
.bubble-asst .asst-steer{
  margin:8px 0 0; font-size:0.84rem; color:var(--ink-soft);
}

/* ===========================================================================
   Assistant PLAN CARD — the hero; each generate/edit turn is one card
   =========================================================================== */
.plan-card{
  width:100%; max-width:660px;
  border:1px solid var(--line); border-radius:var(--r-lg);
  background:
    radial-gradient(130% 150% at 100% 0%,rgba(31,92,153,0.06),transparent 55%),
    var(--paper-2);
  box-shadow:var(--shadow); overflow:hidden;
}
.card-head{
  display:flex; align-items:center; gap:10px;
  padding:11px 16px; border-bottom:1px solid var(--line-soft);
}
.card-head h2{
  margin:0; font-family:var(--font-mono); font-size:0.7rem; font-weight:600;
  letter-spacing:0.15em; text-transform:uppercase; color:var(--accent);
}
.card-head .rule{flex:1; height:1px; background:var(--line-soft);}
.ver-pill{
  display:inline-flex; align-items:center; gap:5px;
  font-family:var(--font-mono); font-size:0.66rem; font-weight:600;
  padding:3px 9px; border-radius:100px;
  color:var(--accent-strong); background:var(--accent-tint); border:1px solid var(--accent-tint-2);
}
.ver-pill.is-new{color:var(--done); background:var(--done-tint); border-color:var(--done);}
/* Total delivered floor area. Full-strength ink and a touch larger than .card-note:
   it is the one number people look for first, and --ink-faint at 0.64rem does not carry
   4.5:1. The shape note beside it stays faint -- it is metadata, this is a measurement. */
.card-area{
  font-family:var(--font-mono); font-size:0.7rem; font-weight:600; color:var(--ink);
  white-space:nowrap;
}
.card-note{font-family:var(--font-mono); font-size:0.64rem; color:var(--ink-faint);}

.card-body{padding:14px 16px 16px;}
.card-reply{margin:0 0 14px; font-size:0.98rem; line-height:1.5; color:var(--ink);}

/* the two render panels sit side by side, stacking on narrow */
/* The 2D plan is the thing people read, so it gets the full width of the card and
   the 3D preview sits UNDER it rather than in a side column. Stacked, not columns:
   a floor plan squeezed into 1.55fr next to a thumbnail was the smaller drawing. */
.card-panels{
  display:grid; gap:12px;
  grid-template-columns:1fr;
  align-items:stretch;
}
.render-panel{
  border:1px solid var(--line-soft); border-radius:var(--r-md);
  background:#fff; overflow:hidden; display:flex; flex-direction:column; min-width:0;
}
.render-panel.is-3d{background:var(--paper);}
.render-head{
  display:flex; align-items:center; gap:8px; padding:7px 11px;
  border-bottom:1px solid var(--line-soft); background:rgba(255,255,255,0.5);
}
.render-head h3{
  margin:0; font-family:var(--font-mono); font-size:0.62rem; font-weight:600;
  letter-spacing:0.13em; text-transform:uppercase; color:var(--ink-faint);
}
.render-head .r-rule{flex:1; height:1px; background:var(--line-soft);}
.render-head .r-meta{font-family:var(--font-mono); font-size:0.6rem; color:var(--ink-faint);}
/* floor tabs — only rendered for a multi-storey plan; they replace the panel's
   `.r-meta` caption, so a single-storey card is visually unchanged. Same pill
   idiom as .chip, sized down to the render-head's mono scale. */
.floor-tabs{display:flex; gap:6px;}
.floor-tab{
  border:1px solid var(--line); border-radius:100px; background:var(--paper-2);
  padding:3px 10px; font-family:var(--font-mono); font-size:0.58rem; font-weight:600;
  letter-spacing:0.06em; text-transform:uppercase; color:var(--ink-soft); cursor:pointer;
  transition:color 0.14s ease,border-color 0.14s ease,background 0.14s ease;
}
.floor-tab:hover{color:var(--accent-strong); border-color:var(--accent-tint-2); background:#fff;}
.floor-tab.is-on{border-color:var(--active); background:var(--active-tint); color:var(--ink);}
.plan-svg-host{display:block; width:100%;}
.plan-svg-host svg,.plan-svg{display:block; width:100%; height:auto; background:#fff;}
.svg-empty{margin:0; padding:22px 12px; text-align:center; font-size:0.82rem; color:var(--ink-faint);}

/* 3D thumbnail — a static isometric that PROMOTES to the one shared viewer */
.thumb-3d{
  position:relative; flex:1; min-height:172px; display:grid; place-items:center;
  width:100%; padding:0; border:0; background:transparent; cursor:pointer; color:inherit;
}
/* Full-card width now that the panels stack, so the preview needs a ceiling: the
   thumb's viewBox is 320x200, and at an unbounded 100% width it would render ~2.5x
   taller than it did in the old side column and swamp the plan above it. Capped, the
   default preserveAspectRatio letterboxes the massing in the middle -- a wide banner. */
.thumb-3d svg{display:block; width:100%; height:auto; max-height:260px;}
.thumb-3d:hover .viewer-hint{color:var(--accent-strong); background:rgba(231,238,246,0.96);}
.thumb-3d:hover .thumb-play{color:var(--accent-strong); border-color:var(--accent-tint-2); background:#fff;}
.thumb-play{
  position:absolute; top:8px; right:8px; display:inline-flex; align-items:center; gap:5px;
  padding:3px 9px; border:1px solid var(--line); border-radius:100px; background:var(--paper-2);
  font-family:var(--font-mono); font-size:0.58rem; font-weight:600; letter-spacing:0.06em;
  text-transform:uppercase; color:var(--ink-soft); box-shadow:var(--shadow-sm);
  transition:color 0.14s ease,border-color 0.14s ease,background 0.14s ease;
}
.viewer-hint{
  position:absolute; inset:auto 0 0 0; margin:0; padding:5px 10px; text-align:center;
  font-family:var(--font-mono); font-size:0.58rem; color:var(--ink-faint);
  background:rgba(244,247,250,0.9); border-top:1px solid var(--line-soft);
  transition:color 0.14s ease,background 0.14s ease;
}

/* download row — per-version exports */
.dl-row{display:flex; flex-wrap:wrap; gap:8px; margin-top:14px;}
.dl-row .dl-label{
  font-family:var(--font-mono); font-size:0.62rem; letter-spacing:0.1em;
  text-transform:uppercase; color:var(--ink-faint); align-self:center; margin-right:2px;
}

/* honest surfacing inside a card (warnings / not-honored / fallback) */
.card-flags{margin:14px 0 0; display:flex; flex-direction:column; gap:8px;}
.card-flag{
  display:flex; gap:9px; align-items:flex-start;
  padding:9px 12px; border-radius:0 var(--r-md) var(--r-md) 0;
  font-size:0.84rem; line-height:1.45; color:var(--ink-soft);
}
.card-flag.warn{border-left:3px solid var(--active); background:var(--active-tint);}
.card-flag.info{border-left:3px solid var(--planned); background:var(--planned-tint);}
.card-flag .cf-ico{flex:0 0 auto; margin-top:1px;}
.card-flag.warn .cf-ico{color:var(--active);}
.card-flag.info .cf-ico{color:var(--planned);}
.card-flag ul{margin:2px 0 0; padding-left:18px;}
.card-flag li{margin:2px 0;}

/* editable assumption chips */
.chips-head{
  display:flex; align-items:center; gap:8px; margin:16px 0 8px;
  font-family:var(--font-mono); font-size:0.62rem; font-weight:600;
  letter-spacing:0.14em; text-transform:uppercase; color:var(--ink-faint);
}
.chips-head::after{content:""; flex:1; height:1px; background:var(--line-soft);}
.chips{display:flex; flex-wrap:wrap; gap:8px; align-items:flex-start;}
.chip{
  display:inline-flex; align-items:center; gap:7px;
  border:1px solid var(--line); border-radius:100px; background:var(--paper-2);
  padding:6px 12px; color:var(--ink); font-size:0.84rem; font-family:var(--font-body);
  box-shadow:var(--shadow-sm); cursor:pointer;
  transition:border-color 0.14s ease,color 0.14s ease,background 0.14s ease;
}
.chip:hover{color:var(--accent-strong); border-color:var(--accent-tint-2); background:#fff;}
.chip[disabled]{opacity:0.55; cursor:not-allowed;}
.chip .chip-edit{color:var(--ink-faint); transition:color 0.14s ease;}
.chip:hover .chip-edit{color:var(--accent);}
.chip.is-cap{border-color:var(--active); background:var(--active-tint); color:var(--ink);}
.chip.is-cap .chip-edit{color:var(--active);}
.chip.is-cleared{border-style:dashed; color:var(--ink-soft);}
.chip.example-chip{font-family:var(--font-body);}
.chips-foot{
  margin:9px 2px 0; font-family:var(--font-mono); font-size:0.64rem; color:var(--ink-faint);
}

/* inline chip editor — opens IN PLACE (never the old Assumptions panel) */
.chip-editor{
  display:inline-flex; align-items:center; gap:6px; flex-wrap:wrap;
  border:1px solid var(--accent-tint-2); border-radius:100px; background:#fff;
  padding:4px 6px 4px 12px; box-shadow:var(--shadow-sm);
}
.chip-editor .ce-label{
  font-family:var(--font-mono); font-size:0.66rem; letter-spacing:0.04em;
  text-transform:uppercase; color:var(--ink-faint);
}
.chip-editor input[type=number],.chip-editor select{
  font-family:var(--font-body); font-size:0.86rem; color:var(--ink);
  border:1px solid var(--line); border-radius:var(--r-sm); background:var(--paper-2);
  padding:3px 6px; min-width:64px;
}
.chip-editor input[type=number]{width:70px;}
.ce-btn{
  display:inline-grid; place-items:center; width:26px; height:26px; padding:0;
  border:1px solid var(--line); border-radius:var(--r-sm); background:var(--paper-2);
  color:var(--ink-soft); cursor:pointer;
  transition:border-color 0.14s ease,color 0.14s ease,background 0.14s ease;
}
.ce-btn:hover{color:var(--accent-strong); border-color:var(--accent-tint-2); background:#fff;}
.ce-btn.ce-ok{color:#fff; background:var(--accent); border-color:var(--accent-strong);}
.ce-btn.ce-ok:hover{background:var(--accent-strong);}
.ce-btn.ce-clear{color:var(--risk); border-color:var(--line);}

/* ===========================================================================
   WORKING / SOLVING state — the honest latency turn
   =========================================================================== */
.working{
  width:100%; max-width:660px;
  border:1px solid var(--line); border-radius:var(--r-lg);
  background:var(--paper-2); box-shadow:var(--shadow-sm); overflow:hidden;
}
.working-body{padding:16px 18px 18px; display:flex; flex-direction:column; gap:12px;}
.working-top{display:flex; align-items:center; gap:12px;}
.working-dot{
  flex:0 0 auto; width:30px; height:30px; border-radius:50%;
  border:3px solid var(--accent-tint-2); border-top-color:var(--accent);
}
.working-titles{display:flex; flex-direction:column; gap:2px; min-width:0;}
.working-title{margin:0; font-family:var(--font-display); font-weight:600; font-size:1.0rem; color:var(--ink);}
.working-sub{margin:0; font-size:0.86rem; color:var(--ink-soft);}
.progress{
  position:relative; height:8px; border-radius:100px; overflow:hidden;
  background:var(--paper-3); border:1px solid var(--line-soft);
}
.progress-fill{
  position:absolute; top:0; bottom:0; left:0; width:8%; border-radius:100px;
  background:linear-gradient(90deg,var(--accent),var(--accent-strong));
  transition:width 0.5s ease;
}
.progress-fill::after{
  content:""; position:absolute; inset:0; border-radius:100px;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,0.45),transparent);
}
.working-meta{
  display:flex; flex-wrap:wrap; align-items:center; gap:6px 14px;
  font-family:var(--font-mono); font-size:0.72rem; color:var(--ink-faint);
}
.working-meta .elapsed{color:var(--ink-soft);}
.working-phase{color:var(--accent-strong);}
.working-note{
  margin:2px 0 0; font-size:0.82rem; color:var(--ink-soft); line-height:1.45;
}
/* skeleton of the forthcoming plan (reserves the card's shape) */
.skeleton{
  display:grid; gap:10px; grid-template-columns:1.55fr 1fr; margin-top:2px;
}
.sk-box{border-radius:var(--r-md); background:var(--paper-3); border:1px solid var(--line-soft);}
.sk-2d{height:150px;} .sk-3d{height:150px;}

/* ===========================================================================
   DEGRADED / EXPIRED honest states (small but present)
   =========================================================================== */
.state-card{
  width:100%; max-width:620px;
  display:flex; gap:12px; align-items:flex-start;
  padding:13px 16px; border-radius:0 var(--r-md) var(--r-md) 0;
  font-size:0.92rem; line-height:1.5;
}
.state-card.expired{border-left:3px solid var(--risk); background:var(--risk-tint); color:var(--ink-soft);}
.state-card.basic{border-left:3px solid var(--planned); background:var(--planned-tint); color:var(--ink-soft);}
.state-card.error{border-left:3px solid var(--risk); background:var(--risk-tint); color:var(--ink-soft);}
/* A reply lost to a reload is not an error and not a failure of the plan — it is
   a gap in the record. Neutral `planned` grey, like Basic mode. */
.state-card.interrupted{border-left:3px solid var(--planned); background:var(--planned-tint); color:var(--ink-soft);}
.state-ico{flex:0 0 auto; margin-top:1px;}
.state-card.expired .state-ico,.state-card.error .state-ico{color:var(--risk);}
.state-card.basic .state-ico,.state-card.interrupted .state-ico{color:var(--planned);}
.state-body{flex:1; min-width:0;}
.state-kind{
  display:block; font-family:var(--font-mono); font-size:0.62rem; font-weight:600;
  letter-spacing:0.1em; text-transform:uppercase; margin-bottom:3px;
}
.state-card.expired .state-kind,.state-card.error .state-kind{color:var(--risk);}
.state-card.basic .state-kind,.state-card.interrupted .state-kind{color:var(--planned);}
.state-body .state-action{margin-top:10px;}
/* --ink-soft, not --ink-faint: on the `planned` tint this card uses, --ink-faint
   measures 3.1:1 and this is 0.86rem body copy. Size alone marks it as secondary. */
.state-body .state-sub{margin:8px 0 0; font-size:0.86rem; color:var(--ink-soft); line-height:1.5;}

/* ===========================================================================
   Composer — pinned at the bottom
   =========================================================================== */
.composer{
  flex:0 0 auto; border-top:1px solid var(--line);
  background:rgba(244,247,250,0.92); backdrop-filter:blur(8px);
  padding:12px clamp(14px,4vw,32px) max(12px,env(safe-area-inset-bottom));
}
.composer-inner{width:100%; max-width:820px; margin:0 auto;}
.composer-row{
  display:flex; gap:10px; align-items:flex-end;
  border:1px solid var(--line); border-radius:var(--r-lg);
  background:#fff; box-shadow:var(--shadow-sm); padding:8px 8px 8px 14px;
}
.composer-row:focus-within{border-color:var(--accent-tint-2); box-shadow:var(--shadow);}
.composer-input{
  flex:1; min-width:0; border:0; outline:0; resize:none;
  font-family:var(--font-body); font-size:1.02rem; color:var(--ink);
  background:transparent; line-height:1.5; padding:6px 0; max-height:140px;
}
.composer-input::placeholder{color:var(--ink-faint);}
.composer-input:disabled{color:var(--ink-faint);}
.send-btn{
  flex:0 0 auto; width:42px; height:42px; padding:0; border-radius:var(--r-md);
  display:grid; place-items:center;
}
.composer-foot{
  display:flex; flex-wrap:wrap; align-items:center; gap:6px 14px;
  margin:8px 4px 0; font-family:var(--font-mono); font-size:0.66rem; color:var(--ink-faint);
}
.composer-foot .dot{opacity:0.5;}

/* ===========================================================================
   Shared 3D viewer — ONE WebGL context for the whole thread (a live context
   per card would exhaust the browser limit). Opened as a modal <dialog>.
   =========================================================================== */
.viewer-modal{
  width:min(920px,94vw); max-width:94vw; height:min(84dvh,720px);
  padding:0; border:1px solid var(--line); border-radius:var(--r-lg);
  background:var(--paper-2); color:var(--ink); box-shadow:var(--shadow); overflow:hidden;
}
.viewer-modal::backdrop{background:rgba(18,39,59,0.42); backdrop-filter:blur(2px);}
.viewer-modal[open]{display:flex; flex-direction:column;}
.viewer-head{
  flex:0 0 auto; display:flex; align-items:center; gap:12px;
  padding:10px 14px; border-bottom:1px solid var(--line-soft);
  background:rgba(244,247,250,0.9);
}
.viewer-head h2{
  margin:0; font-family:var(--font-mono); font-size:0.72rem; font-weight:600;
  letter-spacing:0.12em; text-transform:uppercase; color:var(--accent);
}
.viewer-head .rule{flex:1; height:1px; background:var(--line-soft);}
.panel-toggle{
  display:inline-flex; align-items:center; gap:6px;
  font-family:var(--font-mono); font-size:0.7rem; color:var(--ink-soft); white-space:nowrap; cursor:pointer;
}
.dialog-close{
  display:inline-grid; place-items:center; width:32px; height:32px; padding:0;
  border:1px solid var(--line); border-radius:var(--r-md); background:var(--paper-2);
  color:var(--ink-soft); font-size:1.1rem; line-height:1; cursor:pointer;
  transition:border-color 0.14s ease,color 0.14s ease,background 0.14s ease;
}
.dialog-close:hover{color:var(--accent-strong); border-color:var(--accent-tint-2); background:#fff;}
.viewer-host{
  position:relative; flex:1 1 auto; min-height:0; background:var(--paper);
  display:block; overflow:hidden;
}
.viewer-host canvas{display:block; width:100%; height:100%; touch-action:none;}
.viewer-status{
  position:absolute; left:12px; bottom:12px; margin:0; max-width:calc(100% - 24px);
  padding:7px 12px; border-radius:var(--r-md);
  background:rgba(244,247,250,0.94); border:1px solid var(--line-soft);
  font-family:var(--font-mono); font-size:0.72rem; color:var(--ink-soft); box-shadow:var(--shadow-sm);
}
.viewer-status.error{border-left:3px solid var(--risk); color:var(--ink);}
.viewer-foot{
  flex:0 0 auto; padding:7px 14px; border-top:1px solid var(--line-soft);
  font-family:var(--font-mono); font-size:0.62rem; color:var(--ink-faint);
  background:rgba(244,247,250,0.9);
}

/* ===========================================================================
   Motion — determinate bar shimmer / spinner only when motion is welcome
   =========================================================================== */
@media (prefers-reduced-motion:no-preference){
  .working-dot{animation:spin 0.9s linear infinite;}
  @keyframes spin{to{transform:rotate(360deg);}}
  .progress-fill::after{animation:sheen 1.6s ease-in-out infinite;}
  @keyframes sheen{0%{transform:translateX(-100%);}100%{transform:translateX(240%);}}
  .sk-box{animation:pulse 1.8s ease-in-out infinite;}
  @keyframes pulse{0%,100%{opacity:1;}50%{opacity:0.55;}}
}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto;}
  *,*::before,*::after{
    animation-duration:0.001ms !important; animation-iteration-count:1 !important;
    transition-duration:0.001ms !important;
  }
}

/* ===========================================================================
   Responsive — usable on a narrow viewport; plan card fits; no horizontal scroll
   =========================================================================== */
@media (max-width:640px){
  /* .card-panels is single-column at every width now -- nothing to collapse here. */
  .skeleton{grid-template-columns:1fr;}
  .bubble-user{max-width:88%;}
  .bubble-asst{max-width:92%;}
  /* Only the tagline goes; the topbar-meta row stays so "Clear conversation"
     survives on a phone -- it is the ONLY way to reset a restored thread, and a
     control that exists on desktop but not mobile is not a control. */
  .meta-chip{display:none;}
  .brand-sub{display:none;}
  .topbar{gap:10px; padding:0 14px;}
  .viewer-modal{width:96vw; height:88dvh;}
}
