/* One-glyph font: maps ONLY U+FFFC to a blank 4em-advance glyph (every other codepoint falls through to the next family). Loaded first in the composer font stack, it gives the placeholder a real cell width INSIDE the textarea, so the backdrop chip (same char, same stack) matches it by construction — the two layers cannot drift and the chip gets a usable label cell. */ @font-face { font-family: 'DshChipCell'; src: url('data:font/ttf;base64,AAEAAAAKAIAAAwAgT1MvMkT8SmIAAAEoAAAAYGNtYXAADQBPAAABkAAAADRnbHlmAAAAAAAAAcwAAAABaGVhZCwtPGoAAACsAAAANmhoZWEDIg7bAAAA5AAAACRobXR4EZQAAAAAAYgAAAAIbG9jYQAAAAAAAAHEAAAABm1heHAAAwACAAABCAAAACBuYW1lvljk2gAAAdAAAABscG9zdNNweNQAAAI8AAAALQABAAAAAQAAdia1tV8PPPUAAwPoAAAAAOaLfcUAAAAA5ot9xQAAAAAAAAAAAAAAAwACAAAAAAAAAAEAAAMg/zgAAA+gAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAACAAEAAAACAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAwjKAZAABQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAPz8/PwAA//z//AMg/zgAAAMgAMgAAAAAAAAAAAAAAAAAAAAgAAAB9AAAD6AAAAAAAAIAAAADAAAAFAADAAEAAAAUAAQAIAAAAAQABAABAAD//P//AAD//P//AAUAAQAAAAAAAAAAAAAAAAAAAAAAAAAEADYAAQAAAAAAAQALAAAAAQAAAAAAAgAHAAsAAwABBAkAAQAWABIAAwABBAkAAgAOAChEc2hDaGlwQ2VsbFJlZ3VsYXIARABzAGgAQwBoAGkAcABDAGUAbABsAFIAZQBnAHUAbABhAHIAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAABAgZvYmpyZXAAAAA=') format('truetype'); } /* Floating capsule input (figma Input_Bottom 75:8208): card floats above the viewport bottom inside the centered message column; textarea on top, action row below, one primary circle button bottom-right. Input width rides the column (800 is a cap, not a fixed size — layout rule: the box shrinks with the center column keeping its padding). Hero variant = the same card centered in the empty state; the transition between the two is a position move of one component. */ .root { display: flex; flex-direction: column; align-items: center; /* figma Input_Bottom: pad L32/R32/B12; the bottom gradient mask is owned by the chat scroller. Top 8 hosts the error strip's breathing room. */ padding: 8px 32px 12px; } .hero { padding: 0; } .error, .status { width: 100%; max-width: 800px; margin-bottom: 6px; padding: 4px 8px; border-radius: 8px; font-size: 12px; line-height: 18px; } .status { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-secondary); } .notice { width: 100%; max-width: 800px; margin-bottom: 6px; padding: 4px 8px; border-radius: 8px; background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 18px; } .noticeError { background: var(--dsw-alias-interactive-bg-hover-danger); color: var(--dsw-alias-state-error-primary); } .error { background: var(--dsw-alias-interactive-bg-hover-danger); color: var(--dsw-alias-state-error-primary); } .card { position: relative; /* overlay anchor positioning context */ display: flex; flex-direction: column; /* figma Input 75:8208: 12px between the text area and the button row; 10px top pad on the card before .InputText. */ gap: 12px; width: 100%; max-width: 800px; padding-top: 10px; /* Input stroke: black/0.10 light, white/0.06 dark (figma darkmode note says the input border is one notch weaker than buttons) — exactly the l2-darkmode-thin pair. Fill: the input surface token (elevated in dark). */ border: 1px solid var(--dsw-alias-border-l2-darkmode-thin); border-radius: 20px; background: var(--dsw-specific-input-major); box-shadow: var(--dsw-shadow-lv2); font-size: 16px; line-height: 24px; } .accessory { display: flex; align-items: center; gap: 8px; padding: 10px 12px 0; } /* Floating overlay anchor (menu / popupSelect shell): entries position themselves against the card (bottom: 100% + gap); closed entries render null. */ .overlayAnchor { position: absolute; inset: 0 0 auto; height: 0; } /* Mirror-div auto-grow wrapper: the hidden mirror is in normal flow and sets the height (min 2 lines / max 14 lines); the textarea rides it absolutely. Mirror and textarea MUST share font, line-height, padding and wrapping rules or heights diverge. */ .grow { position: relative; } /* Decoration backdrop: same metrics as the textarea, transparent glyphs; only the highlight backgrounds and the ghost hint show through the transparent textarea background above it. */ .backdrop { position: absolute; inset: 0; overflow: hidden; color: transparent; pointer-events: none; } .hlToken { border-radius: 4px; /* GOAL 稿 amber token emphasis (state warn pair; glyphs stay the textarea's). */ background: var(--dsw-alias-state-warn-tertiary); color: transparent; } .hlSegment { border-radius: 4px; background: var(--dsw-alias-interactive-bg-hover); color: transparent; } .hint { color: var(--dsw-alias-label-caption); } /* Machine pending dot (adjudicating / submitting). */ .pending { width: 8px; height: 8px; border-radius: 50%; background: var(--dsw-alias-state-business-primary); animation: input-pending 1s ease-in-out infinite alternate; } @keyframes input-pending { from { opacity: 0.35; } to { opacity: 1; } } .input { position: absolute; inset: 0; width: 100%; height: 100%; resize: none; overflow-y: auto; border: none; outline: none; background: transparent; color: var(--dsw-alias-label-primary); /* Business blue, not brand-primary: that token resolves to ink in this sheet. */ caret-color: var(--dsw-alias-state-business-primary); } .input, .mirror, .backdrop { /* figma .InputText 34:10434: pl 16 / pr 12 / pt 4. Backdrop MUST share these metrics or the highlight ranges drift off the glyphs. */ padding: 4px 12px 0 16px; /* DshChipCell first: ONLY U+FFFC resolves there (4em blank cell — the chip slot); everything else falls through to the app stack. All three layers share the stack, so placeholder advances agree by construction. */ font-family: 'DshChipCell', var(--dsw-font-family); font-size: inherit; line-height: inherit; white-space: pre-wrap; word-break: break-word; overflow-wrap: anywhere; } /* figma 34:10434: #ADB2B8 light / #81858C dark — the caption pair exactly. */ .input::placeholder { color: var(--dsw-alias-label-caption); user-select: none; } /* Running lock: grayed but the draft stays visible; the turn ending re-enables. */ .input:disabled { color: var(--dsw-alias-label-tertiary); cursor: not-allowed; } .mirror { visibility: hidden; pointer-events: none; /* figma min-h 52 (= ~2 × 24 line + 4pt); 14-line cap (336px). */ min-height: 52px; max-height: 336px; overflow: hidden; } /* Toolbar: attach + Plan + Read-only on the left; model + send on the right (figma Input_Bottom chrome). */ .row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 0 10px 10px 10px; min-width: 0; } .tools, .modes, .trailing { display: flex; align-items: center; min-width: 0; } /* figma 75:8208: 16 between + and the mode chips; 4 between Plan / Read-only. */ .tools { gap: 16px; } .modes { gap: 4px; } .trailing { flex: none; gap: 12px; } /* Attach circle (figma + control): 28px, selector fill, primary glyph. */ .add { display: grid; place-items: center; flex: none; width: 28px; height: 28px; border: none; border-radius: 999px; background: var(--dsw-specific-selector); color: var(--dsw-alias-label-primary); cursor: pointer; } .add:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover-solid); } .add:disabled { opacity: 0.5; cursor: default; } /* Plan / Read-only / model — native