/* ============================================================================
   COMSTACK DESIGN SYSTEM — PLATFORM LAYER (shared, theme-agnostic)
   The structural foundation: layout, the liquid-glass material, geometry,
   spacing, type roles, motion, and components. IDENTICAL across every project.

   It consumes SEMANTIC TOKENS (--accent, --page-bg, --font-sans, glass/fg tokens)
   that a THEME supplies. Neutral fallbacks are defined here so the platform works
   un-themed; a per-project theme (settings/design, resolved by
   web/src/lib/theme-tokens.ts) is injected AFTER this file to brand it.

   VENDORED from transformento/transformento:PRODUCT/DESIGN/tokens/platform.css.
   Do not hand-edit token VALUES here — they are the neutral defaults; per-project
   values come from settings/design via the resolver. See per_project_theming plan.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   PLATFORM-FIXED tokens — geometry, spacing, type roles, motion. Not themeable.
   --------------------------------------------------------------------------- */
:root {
  /* Radii — very rounded; capsule is the signature */
  --r-xs: 12px; --r-sm: 18px; --r-md: 24px; --r-lg: 32px;
  --r-xl: 40px; --r-2xl: 48px; --r-pill: 999px;

  /* Spacing — 4-based, generous */
  --s-1:4px; --s-2:8px; --s-3:12px; --s-4:16px; --s-5:20px; --s-6:24px;
  --s-8:32px; --s-10:40px; --s-12:48px; --s-16:64px; --s-20:80px; --s-24:96px;

  /* Centered feed column */
  --feed-width: 480px; --feed-gutter: 20px;

  /* Type roles (fluid). Faces come from theme tokens below. */
  --text-display: clamp(40px, 9vw, 68px);
  --text-question: clamp(28px, 6.2vw, 44px);
  --text-h1: clamp(28px, 5vw, 40px);
  --text-h2: clamp(23px, 3.4vw, 30px);
  --text-h3: 20px;
  --text-body-lg: 18px; --text-body: 16px; --text-small: 14px;
  --text-caption: 12.5px; --text-mono: 13.5px;
  --w-light:300; --w-regular:400; --w-medium:500; --w-semibold:600; --w-bold:700; --w-heavy:800;

  /* Glass recipe — FLAT-OPTICAL: the backdrop-blur does the work, finished with
     ONE whisper of top-edge light. No tall gloss sheen, no bottom bevel.
     (Material geometry is platform-fixed; the colors are themed.) */
  --glass-blur: 30px; --glass-saturate: 145%;
  --glass-spec: linear-gradient(180deg, rgba(255,255,255,.20) 0%, rgba(255,255,255,0) 22%);

  /* Motion */
  --ease-glass: cubic-bezier(0.32,0.72,0,1);
  --ease-spring: cubic-bezier(0.34,1.56,0.64,1);
  --ease-out: cubic-bezier(0.22,1,0.36,1);
  --dur-fast:160ms; --dur:280ms; --dur-slow:520ms;
}

/* ---------------------------------------------------------------------------
   THEMEABLE tokens — NEUTRAL DEFAULTS. A theme file overrides these.
   Light is the default; [data-theme="dark"] flips the glass + text tokens.
   --------------------------------------------------------------------------- */
:root, :root[data-theme="light"] {
  --page-bg: #F4F4F6;                 /* theme replaces with gradient/image/video */
  --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, monospace;

  --accent: #555; --accent-hover: #6a6a6a; --accent-press: #444;
  --accent-tint: #ececec; --fg-on-accent: #fff;
  --focus-ring: color-mix(in oklab, var(--accent) 55%, transparent);

  --fg-1:#16161A; --fg-2:#56545F; --fg-3:#7a7a82;

  --glass-bg: rgba(255,255,255,.52);
  --glass-bg-strong: rgba(255,255,255,.72);
  --glass-bg-thin: rgba(255,255,255,.34);
  --glass-border: rgba(255,255,255,.85);
  --glass-border-soft: rgba(255,255,255,.45);
  /* Flat-optical: ONE soft ambient drop shadow + a single 1px bright top inset.
     No bottom inset bevel — glass reads flat, never embossed/Aqua. */
  --glass-shadow:
     0 1px 0 rgba(255,255,255,.5) inset,
     0 14px 34px -14px rgba(30,24,20,.18),
     0 2px 6px -3px rgba(30,24,20,.07);
  --glass-shadow-sm:
     0 1px 0 rgba(255,255,255,.45) inset,
     0 5px 16px -8px rgba(30,24,20,.16);
  /* Solid surface (§9b) — the SOLID counterpart of the glass tokens for
     components on backgrounds the platform doesn't control (knowledge white, any
     project surface): opaque fill + hairline border + soft drop shadow, NO
     backdrop blur and NO white inset gloss. --accent-fill is the AA-darkened
     accent (the only themed colour on a panel besides --accent; the resolver
     overrides it per project). See PRODUCT/DESIGN/surfaces.md. */
  --surface-bg: #ffffff;
  --surface-bg-sunken: #f4f4f6;
  --surface-border: rgba(20,16,12,.12);
  --surface-shadow: 0 14px 34px -14px rgba(30,24,20,.16), 0 2px 6px -3px rgba(30,24,20,.08);
  --accent-fill: #444;
  --scrim: rgba(20,16,12,.04);
  --scrim-modal: rgba(20,16,12,.42);   /* dim behind a focused (modal) flow card */
  --danger: #d4351c;                   /* inline validation / error text */
}

:root[data-theme="dark"] {
  --page-bg: #0E1124;
  --fg-1:#F4F2F7; --fg-2:rgba(244,242,247,.70); --fg-3:rgba(244,242,247,.50);
  --glass-bg: rgba(30,32,48,.46);
  --glass-bg-strong: rgba(34,36,54,.66);
  --glass-bg-thin: rgba(30,32,48,.30);
  --glass-border: rgba(255,255,255,.18);
  --glass-border-soft: rgba(255,255,255,.10);
  --glass-shadow:
     0 1px 0 rgba(255,255,255,.12) inset,
     0 18px 44px -16px rgba(0,0,0,.5),
     0 2px 8px -3px rgba(0,0,0,.35);
  --glass-shadow-sm:
     0 1px 0 rgba(255,255,255,.08) inset,
     0 6px 18px -8px rgba(0,0,0,.45);
  /* Solid surface (§9b) — dark flip of the opaque panel material. */
  --surface-bg: #171a2b;
  --surface-bg-sunken: #0e1124;
  --surface-border: rgba(255,255,255,.12);
  --surface-shadow: 0 18px 44px -16px rgba(0,0,0,.55), 0 2px 8px -3px rgba(0,0,0,.4);
  --scrim: rgba(0,0,0,.18);
  --scrim-modal: rgba(0,0,0,.58);
  --danger: #ff6b5e;
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast:0ms; --dur:0ms; --dur-slow:0ms; }
}

/* ---------------------------------------------------------------------------
   GLASS MATERIAL — the platform's signature surface.
   --------------------------------------------------------------------------- */
.glass {
  position: relative;
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border-soft);
  border-top-color: var(--glass-border);
  box-shadow: var(--glass-shadow);
  border-radius: var(--r-lg);
}
.glass::before {
  content:""; position:absolute; inset:0; border-radius:inherit;
  background: var(--glass-spec); pointer-events:none;
}
.glass.strong { background: var(--glass-bg-strong); }
.glass.thin   { background: var(--glass-bg-thin); }
.glass > * { position: relative; }

/* ---------------------------------------------------------------------------
   TYPE ROLES — faces from theme tokens.
   --------------------------------------------------------------------------- */
.t-question { font: var(--w-semibold) var(--text-question)/1.22 var(--font-sans); letter-spacing:-.011em; color:var(--fg-1); text-wrap:pretty; }
.t-display  { font: var(--w-heavy) var(--text-display)/1.08 var(--font-sans); letter-spacing:-.02em; color:var(--fg-1); }
.t-h1 { font: var(--w-bold) var(--text-h1)/1.22 var(--font-sans); letter-spacing:-.011em; color:var(--fg-1); }
.t-h2 { font: var(--w-bold) var(--text-h2)/1.22 var(--font-sans); color:var(--fg-1); }
.t-h3 { font: var(--w-semibold) var(--text-h3)/1.3 var(--font-sans); color:var(--fg-1); }
.t-body-lg { font: var(--w-regular) var(--text-body-lg)/1.62 var(--font-sans); color:var(--fg-2); }
.t-body { font: var(--w-regular) var(--text-body)/1.5 var(--font-sans); color:var(--fg-2); }
.t-small { font: var(--w-medium) var(--text-small)/1.4 var(--font-sans); color:var(--fg-2); }
.t-caption { font: var(--w-medium) var(--text-caption)/1.35 var(--font-sans); letter-spacing:.04em; text-transform:uppercase; color:var(--fg-3); }
.t-mono { font: var(--w-regular) var(--text-mono)/1.5 var(--font-mono); color:var(--fg-2); }

/* ---------------------------------------------------------------------------
   LAYOUT — centered feed + floating chrome.
   VIEWPORT-LOCK: the app fills the viewport and the feed scrolls INTERNALLY, so
   the bottom mic dock stays pinned no matter how long the conversation gets.
   This requires a 100% height chain — the JS mount node MUST carry height:100%,
   otherwise .tf-app grows with content and the dock slides off-screen.
   --------------------------------------------------------------------------- */
html, body { height: 100%; margin: 0; }
#root, [data-tf-root] { height: 100%; }
.tf-stage { position: fixed; inset: 0; background: var(--page-bg); background-size: 170% 170%; }
.tf-app { position: relative; height: 100%; display: flex; flex-direction: column; align-items: center; }
.tf-feed-scroll { flex:1; width:100%; overflow-y:auto; overflow-x:hidden; display:flex; justify-content:center; scrollbar-width:none; }
.tf-feed-scroll::-webkit-scrollbar { display:none; }
.tf-feed { width:100%; max-width:var(--feed-width); padding:96px var(--feed-gutter) 220px; display:flex; flex-direction:column; gap:16px; }

/* entrance — transform-only so content is never trapped invisible */
.tf-enter { transform:none; transition: transform var(--dur-slow) var(--ease-glass); }
@starting-style { .tf-enter { transform: translateY(18px) scale(.97); } }

/* ---------------------------------------------------------------------------
   COMPONENTS — capsules, options, mic dock, input. Theme-agnostic.
   --------------------------------------------------------------------------- */
.tf-btn { display:inline-flex; align-items:center; gap:8px; cursor:pointer; border:none;
  font: var(--w-semibold) 16px/1 var(--font-sans); padding:15px 26px; border-radius:var(--r-pill);
  transition: transform var(--dur-fast) var(--ease-out), background var(--dur-fast); }
.tf-btn:active { transform: scale(.96); }
.tf-btn--primary { background:var(--accent); color:var(--fg-on-accent); }
.tf-btn--primary:hover { background:var(--accent-hover); }
.tf-btn--primary:active { background:var(--accent-press); }
.tf-btn--glass { background:var(--glass-bg-strong); color:var(--fg-1); border:1px solid var(--glass-border); box-shadow:var(--glass-shadow-sm);
  -webkit-backdrop-filter:blur(20px) saturate(150%); backdrop-filter:blur(20px) saturate(150%); }
.tf-btn--ghost { background:transparent; color:var(--fg-1); }
.tf-btn--ghost:hover { background:var(--scrim); }

/* selectable options — fully rounded in BOTH default and selected states */
.tf-opt { display:flex; align-items:center; gap:13px; padding:15px 22px; cursor:pointer;
  border-radius:var(--r-pill); background:var(--glass-bg-strong);
  border:1px solid var(--glass-border-soft); box-shadow:var(--glass-shadow-sm);
  font: var(--w-medium) 16px/1.25 var(--font-sans); color:var(--fg-1);
  transition: transform var(--dur-fast) var(--ease-out), background var(--dur-fast); }
.tf-opt:active { transform: scale(.985); }
.tf-opt.is-selected { background:var(--accent); color:var(--fg-on-accent); border-color:transparent; }

/* primary control (mic) — LIQUID GLASS, never a solid fill. Glow sits BEHIND.
   Glyph is NEUTRAL at rest; it takes --accent ONLY while listening (a red/accent
   glyph at rest reads as "already recording"). The themeable glow fills the slot
   below (Aurora supplies the "Swirl" glow; another theme can supply its own or none). */
.tf-mic-wrap { position: relative; display: grid; place-items: center; }
.tf-mic-glow { position:absolute; inset:0; margin:auto; width:96px; height:96px; border-radius:50%;
  z-index:0; pointer-events:none; opacity:0; }      /* theme fills this slot (see theme-aurora.css) */
.tf-mic { position:relative; z-index:1; width:76px; height:76px; border-radius:50%;
  border:1px solid var(--glass-border); cursor:pointer; display:flex; align-items:center; justify-content:center;
  color:var(--fg-1); font-size:32px; background:var(--glass-bg-strong); box-shadow:var(--glass-shadow);
  -webkit-backdrop-filter:blur(16px) saturate(145%); backdrop-filter:blur(16px) saturate(145%);
  transition: transform var(--dur-fast) var(--ease-spring), color var(--dur-fast) var(--ease-out); }
.tf-mic::before { content:""; position:absolute; inset:0; border-radius:inherit; background:var(--glass-spec); pointer-events:none; }
.tf-mic:active { transform: scale(.94); }
.tf-mic.is-listening { color: var(--accent); }   /* accent ONLY while listening */

.tf-side-btn { width:52px; height:52px; border-radius:50%; border:1px solid var(--glass-border);
  background:var(--glass-bg-strong); box-shadow:var(--glass-shadow-sm); color:var(--fg-1); cursor:pointer;
  display:flex; align-items:center; justify-content:center; font-size:21px;
  -webkit-backdrop-filter:blur(20px) saturate(150%); backdrop-filter:blur(20px) saturate(150%);
  transition: transform var(--dur-fast) var(--ease-out); }
.tf-side-btn:active { transform: scale(.92); }

/* quiet text-only "type instead" affordance for the IDLE state (no keyboard glyph) */
.tf-type-link { border:none; background:transparent; cursor:pointer; padding:4px 8px; border-radius:var(--r-pill);
  font: var(--w-medium) 13.5px/1 var(--font-sans); color:var(--fg-2); letter-spacing:.01em;
  transition: color var(--dur-fast) var(--ease-out); }
.tf-type-link:hover { color:var(--fg-1); }

/* text input (capsule) + send */
.tf-textbar { display:flex; align-items:center; gap:8px; padding:8px 8px 8px 20px; border-radius:var(--r-pill);
  background:var(--glass-bg-strong); border:1px solid var(--glass-border); box-shadow:var(--glass-shadow);
  -webkit-backdrop-filter:blur(22px) saturate(150%); backdrop-filter:blur(22px) saturate(150%); }
.tf-textbar input { flex:1; border:none; background:transparent; outline:none; font:var(--w-regular) 16px/1 var(--font-sans); color:var(--fg-1); }
.tf-textbar input::placeholder { color:var(--fg-3); }
.tf-send { width:46px; height:46px; flex:none; border-radius:50%; border:none; background:var(--accent); color:var(--fg-on-accent);
  display:flex; align-items:center; justify-content:center; font-size:20px; cursor:pointer; }

/* live transcript pill */
.tf-transcript { display:flex; align-items:center; gap:10px; padding:11px 18px; border-radius:var(--r-pill);
  background:var(--glass-bg-strong); border:1px solid var(--glass-border); box-shadow:var(--glass-shadow-sm);
  -webkit-backdrop-filter:blur(22px) saturate(150%); backdrop-filter:blur(22px) saturate(150%);
  font:var(--w-regular) 15px/1.3 var(--font-mono); color:var(--fg-1); }

/* icons — Material Symbols Rounded, filled (face confirmed against source separately) */
.msr { font-family:'Material Symbols Rounded'; font-weight:normal; font-style:normal;
  font-variation-settings:'FILL' 1,'wght' 500,'GRAD' 0,'opsz' 24; line-height:1;
  display:inline-flex; align-items:center; justify-content:center; -webkit-font-smoothing:antialiased; }

/* ---------------------------------------------------------------------------
   §8 INTERACTION STATES (platform-fixed) — hover / focus-visible / disabled.
   Additive: the base component rules above own layout + :active (press).
   - hover: lighten + a touch more shadow lift (theme-safe brightness).
   - focus-visible: a soft, color-mixed accent ring (--focus-ring); NEVER a
     hard browser outline.
   - disabled / [aria-disabled]: ~40% opacity, no shadow, no pointer.
   - hit targets: never below 44×44px (tf-mic 76 / tf-side-btn 52 already pass;
     guard the capsules).

   Mic-dock behavior (state-driven, set by the renderer):
   - IDLE: neutral glyph, glow off, NO mute button — there is nothing to mute yet;
     a text-only "Type instead" (.tf-type-link) covers typing. No keyboard glyph.
   - LISTENING: .is-listening → accent glyph + the glow blooms in; the mute
     (mic_off) .tf-side-btn appears beside the mic.
   - MUTED: glow off + mic_off + reveal the text input (.tf-textbar). NOT a red
     affordance (no --danger mic).
   --------------------------------------------------------------------------- */
.tf-btn, .tf-opt { min-height: 44px; }

@media (hover: hover) {
  .tf-mic:hover, .tf-side-btn:hover, .tf-opt:hover, .tf-btn--glass:hover {
    filter: brightness(1.05); box-shadow: var(--glass-shadow);
  }
  .tf-opt.is-selected:hover { filter: none; background: var(--accent-hover); }
}

.tf-mic:focus-visible, .tf-side-btn:focus-visible, .tf-opt:focus-visible, .tf-btn:focus-visible {
  outline: none;
}
.tf-mic:focus-visible      { box-shadow: 0 0 0 3px var(--focus-ring), var(--glass-shadow); }
.tf-side-btn:focus-visible { box-shadow: 0 0 0 3px var(--focus-ring), var(--glass-shadow-sm); }
.tf-opt:focus-visible      { box-shadow: 0 0 0 3px var(--focus-ring), var(--glass-shadow-sm); }
.tf-btn:focus-visible      { box-shadow: 0 0 0 3px var(--focus-ring); }

.tf-mic:disabled, .tf-mic[aria-disabled="true"],
.tf-side-btn:disabled, .tf-side-btn[aria-disabled="true"],
.tf-opt[aria-disabled="true"], .tf-opt:disabled,
.tf-btn:disabled, .tf-btn[aria-disabled="true"] {
  opacity: .4; box-shadow: none; cursor: default; pointer-events: none; filter: none;
}

/* ---------------------------------------------------------------------------
   §9a FLOW CARD — multi-step form rendered one step at a time in a single
   glass card. ONE component in both presentation modes (inline in the feed;
   focused = scrim + elevation + responsive sheet). Built only from semantic
   tokens — the project theme paints --accent / --glass-* / --fg-* / fonts.
   Chrome: header (group + progress) · body (.t-question + hint + control +
   always-present validation region) · footer (Back ghost + Next primary) ·
   auto-advance timer bar (--accent fill).
   --------------------------------------------------------------------------- */
.tf-flow { display: block; }
.tf-flow-card {
  position: relative; overflow: hidden;          /* clip the timer bar to the radii */
  display: flex; flex-direction: column;
  border-radius: var(--r-lg);
}

.tf-flow-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  padding: var(--s-4) var(--s-5) 0;
}
.tf-flow-progress { color: var(--fg-3); }

.tf-flow-body { padding: var(--s-3) var(--s-5) var(--s-4); display: flex; flex-direction: column; gap: var(--s-3); }
.tf-flow-hint { color: var(--fg-2); margin-top: calc(-1 * var(--s-2)); }
.tf-flow-control { display: flex; flex-direction: column; gap: var(--s-2); margin-top: var(--s-1); }
.tf-flow-opts { display: flex; flex-direction: column; gap: var(--s-2); }
.tf-flow-fields { display: flex; flex-direction: column; gap: var(--s-3); }
.tf-flow-field-label { display: block; margin-bottom: var(--s-1); }
.tf-flow-info { color: var(--fg-1); }            /* information-step body */

/* a single-line field reuses the capsule text input look */
.tf-flow-input {
  width: 100%; border: 1px solid var(--glass-border); border-radius: var(--r-pill);
  background: var(--glass-bg-strong); color: var(--fg-1);
  font: var(--w-regular) 16px/1.2 var(--font-sans); padding: 13px 20px; outline: none;
  -webkit-backdrop-filter: blur(12px) saturate(140%); backdrop-filter: blur(12px) saturate(140%);
}
textarea.tf-flow-input { border-radius: var(--r-md); resize: vertical; min-height: 96px; line-height: 1.5; }
.tf-flow-input::placeholder { color: var(--fg-3); }
.tf-flow-input:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--focus-ring); }

/* rating scale — number pills in a wrapping row (was an inline style) */
.tf-flow-rate-row { flex-direction: row; flex-wrap: wrap; }

/* free-text "Other" affordance (allow_other): a text input revealed under the
   options when the Other pill is selected */
.tf-flow-other-input.is-hidden { display: none; }

/* signature — a styled accent consent affordance: typing your full name is the
   consent. Capsule field + accent underline + a caption. Value contract is
   unchanged (a length-capped string, same as a text step). */
.tf-flow-sign { display: flex; flex-direction: column; gap: var(--s-2); }
.tf-flow-sign-input { border-color: var(--accent); box-shadow: inset 0 -2px 0 0 var(--accent); font-style: italic; }
.tf-flow-sign-cap { color: var(--fg-3); }

/* fill-in-the-blank — inline inputs flow inside the sentence template (was an
   inline style on the container + each input) */
.tf-flow-blank { line-height: 2.4; }
.tf-flow-blank-input { display: inline-block; width: auto; min-width: 120px; padding: var(--s-1) var(--s-3); }

/* optional notes field (allow_notes) under any control */
.tf-flow-notes { display: flex; flex-direction: column; gap: var(--s-1); margin-top: var(--s-2); }

/* always-present inline validation region (collapses when empty) */
.tf-flow-error {
  color: var(--danger); font: var(--w-medium) var(--text-small)/1.4 var(--font-sans);
  min-height: 1.2em;                              /* reserve space so reveal doesn't jump */
}

.tf-flow-foot {
  display: flex; align-items: center; gap: var(--s-3);
  padding: 0 var(--s-5) var(--s-5);
}
.tf-flow-next { margin-inline-start: auto; }      /* Next/Submit pinned to the end */

/* auto-advance timer bar — accent fill across the card bottom */
.tf-flow-timer { height: 3px; width: 100%; background: var(--scrim); }
.tf-flow-timer-fill { height: 100%; width: 0; background: var(--accent); }
.tf-flow-timer.is-running .tf-flow-timer-fill { width: 100%; transition: width linear; } /* duration set inline */
.tf-flow-timer.is-hidden { display: none; }

/* completed summary */
.tf-flow-summary-icon { font-size: 18px; vertical-align: -3px; }
.tf-flow-summary { display: flex; flex-direction: column; gap: var(--s-2); }
.tf-flow-summary-row { display: flex; justify-content: space-between; gap: var(--s-4); }
.tf-flow-summary-row .tf-flow-summary-val { color: var(--fg-1); text-align: end; }

/* ── focused (modal) — same card, lifted above a scrim ────────────────────── */
.tf-flow--focused {
  position: fixed; inset: 0; z-index: 30;
  display: grid; place-items: center; padding: var(--s-5);
  background: var(--scrim-modal);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  animation: tf-scrim-in var(--dur) var(--ease-glass);
}
.tf-flow--focused .tf-flow-card { width: 100%; max-width: 440px; box-shadow: var(--glass-shadow); }

/* responsive rule (not a separate setting): full-height glass sheet on phones */
@media (max-width: 520px) {
  .tf-flow--focused { place-items: end stretch; padding: 0; }
  .tf-flow--focused .tf-flow-card {
    max-width: none; min-height: 86vh;
    border-radius: var(--r-2xl) var(--r-2xl) 0 0;
    animation: tf-sheet-up var(--dur-slow) var(--ease-glass);
  }
}

/* motion — animate every state change (content swap cross-fade + sheet/scrim
   entrances). Transform/opacity only; reduced-motion disables them below. */
.tf-flow-swap { animation: tf-flow-fade var(--dur) var(--ease-glass); }
@keyframes tf-flow-fade { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes tf-scrim-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes tf-sheet-up { from { transform: translateY(100%); } to { transform: none; } }

/* focused→complete settle: the modal drops down into the feed while the scrim
   fades, then the inline summary cross-fades in (renderFlowCard swaps after the
   card's animationend). §9a: "on complete: animates down into the feed." */
.tf-flow--focused.tf-flow-settling { animation: tf-scrim-out var(--dur) var(--ease-glass) forwards; }
.tf-flow--focused.tf-flow-settling .tf-flow-card { animation: tf-flow-settle var(--dur) var(--ease-glass) forwards; }
@keyframes tf-scrim-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes tf-flow-settle { from { transform: none; opacity: 1; } to { transform: translateY(40px) scale(.96); opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .tf-flow-swap, .tf-flow--focused, .tf-flow--focused .tf-flow-card { animation: none; }
  .tf-flow--focused.tf-flow-settling, .tf-flow--focused.tf-flow-settling .tf-flow-card { animation: none; }
  .tf-flow-timer.is-running .tf-flow-timer-fill { transition: none; }
}

/* ---------------------------------------------------------------------------
   §9b SOLID SURFACE — the opaque material for components (cs-x-* / cs-*) that
   render on backgrounds the platform does NOT control: a knowledge page's white,
   or any project surface. The counterpart to .glass — NO backdrop-filter, NO
   white inset gloss, opaque fill + hairline border + soft drop shadow. Glass
   needs the live-page gradient to refract and goes muddy/edgeless on flat white;
   a solid surface reads cleanly everywhere.

   one-accent: --accent / --accent-fill is the ONLY project-themed colour. The
   surface, border, text and shadow are FIXED neutrals (the --surface-* tokens
   above) that flip only via [data-theme]. See PRODUCT/DESIGN/surfaces.md.

   Fit modes:
     • framed-fit — .panel / [data-surface="solid"]: bordered, rounded, elevated.
       A component owns its frame; the SITE always uses this fit.
     • fill — .panel-fill / [data-surface="fill"]: edge-to-edge, no frame, for an
       MCP host that already frames the slot. The SITE never uses it.

   KEEP IN SYNC with SURFACE_MATERIAL_CSS in web/src/lib/components/surface.ts
   (the inline copy injected on knowledge pages, which don't load this file) —
   tests/web/components-surface.test.ts asserts both define the same contract.
   --------------------------------------------------------------------------- */
.panel, [data-surface="solid"] {
  background: var(--surface-bg, #fff);
  color: var(--fg-1, #16161a);
  border: 1px solid var(--surface-border, rgba(20,16,12,.12));
  border-radius: var(--r-lg, 32px);
  box-shadow: var(--surface-shadow, 0 14px 34px -14px rgba(30,24,20,.16), 0 2px 6px -3px rgba(30,24,20,.08));
}
.panel.sunken, [data-surface="sunken"] {
  background: var(--surface-bg-sunken, #f4f4f6);
  box-shadow: none;
}
.panel.flush { box-shadow: none; }              /* a panel without elevation */
.panel-fill, [data-surface="fill"] {
  background: var(--surface-bg, #fff);
  color: var(--fg-1, #16161a);
  border: 0; border-radius: 0; box-shadow: none;
}
