/* 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, primary action controls bottom-right. Input width rides the
   column (--dsh-composer-card-max-width = chat content + 32px, 16px per side,
   is a cap, not a fixed size — layout rule: the box shrinks with the center
   column keeping its clearance). 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;
  /* Side pads ride the shared clearance (figma Input_Bottom drew L32/R32/B8;
     the sides narrow with the shared width axis); the bottom gradient mask
     is owned by the chat scroller. No top pad: the composer stack's gap owns
     the space above; error/status strips still carry their own margin. */
  padding: 0 var(--dsh-composer-side-clearance) 8px;
}

.hero {
  /* No bottom pad in the centered hero, but the side clearance must survive:
     the hero wrapper is full-width on narrow viewports, so this padding is
     the only thing keeping the card off the edges there. */
  padding: 0 var(--dsh-composer-side-clearance);
}

.notice {
  width: 100%;
  max-width: var(--dsh-composer-card-max-width);
  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);
}

.card {
  box-sizing: border-box;
  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: var(--dsh-composer-card-max-width);
  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: 22px;
  background: var(--dsw-specific-input-major);
  box-shadow: var(--dsw-shadow-lv2);
  font-size: 16px;
  line-height: 24px;
  /* Elevated surface in dark, same as the menus: the draft scrollport inside
     scrolls once the composer hits its height cap, so the thumb takes the l2
     pair. Declared on the card because the elevation belongs to the surface,
     and the custom properties inherit down to the box that actually scrolls
     (see ui-theme styles/scrollbar.css for the rebinding contract). */
  --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
  --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
}

/* No-workspace trigger state: dashed l4 stroke marks the card as a pick-a-
   workspace affordance rather than a live composer; hover answers in the
   business blue to invite the click. Native `dashed` has a fixed browser
   pattern, so the stroke is an ::after overlay: theme-token background masked
   by an SVG dash ring (stroke-width 2 centered on the box edge = 1px visible
   inside), which keeps the 22px radius and both themes. */
.cardWorkspaceTrigger {
  border-color: transparent;
  cursor: pointer;
}

.cardWorkspaceTrigger::after {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: 22px;
  background: var(--dsw-alias-border-l4);
  transition: background-color 100ms ease;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='none' rx='22' ry='22' stroke='black' stroke-width='2' stroke-dasharray='4 4'/%3E%3C/svg%3E");
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='100%25' height='100%25' fill='none' rx='22' ry='22' stroke='black' stroke-width='2' stroke-dasharray='4 4'/%3E%3C/svg%3E");
  pointer-events: none;
}

/* Disabled toolbar controls neither receive nor swallow clicks in the trigger
   state: pointer events fall through to the card's own click handler, making
   the full capsule one pick target. */
.cardWorkspaceTrigger :disabled {
  pointer-events: none;
}

.cardWorkspaceTrigger:hover::after {
  background: var(--dsw-alias-state-business-primary);
}

.accessory {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px 0;
}

/* Rail seat: the card's top padding (10px) plus this 4px matches DeepSeek
   Chat's spacing above the thumbnails; the card's 12px flex gap owns the space
   below. The rail itself (arrows, hidden scrollbar, card geometry) is the
   ui-attachment atom's. */
.attachments {
  min-width: 0;
  padding: 4px 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;
}

/* The draft's scrollport, and the ONLY scrolling box in the composer: the
   caret is the textarea's and every visible glyph is the backdrop's, so the two
   layers stay together only by riding one offset the browser applies to both at
   once. Scrolling one box and assigning the offset to the other cannot hold —
   a wheel gesture is composited off the main thread, so the assignment lands
   frames late and the words visibly trail the caret. The 14-line cap lives here
   because this is the box the cap describes. */
.scroll {
  max-height: var(--dsh-composer-text-max-height);
  overflow-y: auto;
}

/* Mirror-div auto-grow stack: the hidden mirror is in normal flow and sets the FULL draft
   height (min 2 lines in hero); backdrop and textarea ride it absolutely, so both layers are
   as tall as the draft and the scrollport above shows a window onto them. 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: var(--dsw-alias-label-primary);
  pointer-events: none;
}

.hlToken {
  background-color: transparent;
  color: var(--dsw-alias-state-warn-label);
}

.hlSegment {
  border-radius: 4px;
  background-color: transparent;
  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;
  /* Never a scroller of its own: it is as tall as the draft, so it has no
     scrollable overflow to hold an offset that could differ from the glyphs'.
     The browser still reveals the caret — the scroll-into-view walks up to
     .scroll and moves both layers together. */
  overflow: hidden;
  border: none;
  outline: none;
  background: transparent;
  color: transparent;
  /* Business blue, not brand-primary: that token resolves to ink in this sheet. */
  caret-color: var(--dsw-alias-state-business-primary);
}

.input,
.mirror,
.backdrop {
  /* Textareas default to content-box (unlike buttons/inputs): without this the
     width:100% textarea gains its padding OUTSIDE the card and text runs past
     the right padding — and wraps 28px later than the mirror/backdrop layers. */
  box-sizing: border-box;
  /* 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;
  /* Three consumers, not two: the mirror sizes the stack, the layers must break
     lines identically, and the caret reveal parses this value to step one line
     down for a caret that sits after a newline. That parse needs a length, so a
     theme resolving this to `normal` would make the reveal a silent no-op. */
  line-height: inherit;
  white-space: pre-wrap;
  word-break: break-word;
  overflow-wrap: anywhere;
  /* These three MUST wrap at one width: the mirror decides the box height
     the other two are laid out in, and a glyph layer that breaks lines
     elsewhere than the textarea puts the words under the wrong caret. They do
     so by construction now that all three sit INSIDE .scroll — a scrollbar
     that consumes layout space narrows the scrollport, which is their shared
     containing block, so it costs all three the same width on every engine.
     A textarea that scrolls itself would break this, and no property fixes
     it: WebKit reserves gutter space for an overflow-y:auto textarea and not
     for the overflow:hidden layers beside it, leaving them 8px apart
     (768 against 776) — worth 2 to 5 wrapped lines on a long draft. */
}

/* 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;
}

.input[aria-haspopup='menu'] {
  cursor: pointer;
}

.mirror {
  visibility: hidden;
  pointer-events: none;
}

/* Hero (centered empty-state) keeps the 2-line floor (figma min-h 52 = ~2 × 24
   line + 4pt); the docked composer collapses to the content height. */
.hero .mirror {
  min-height: 52px;
}

/* 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;
  /* 2px moved from the bottom pad to the top: the whole control row sits 2px
     lower in the card (it read too high against the textarea) while the card
     height and the controls' own centering stay untouched. */
  padding: 2px 8px 6px;
  min-width: 0;
  /* Size container so the chips inside can collapse to icon-only when the
     card runs out of row width (PermissionSelect @container rule). Anonymous
     on purpose: CSS modules hash container-name per module, so a name declared
     here can never match a query in another module's sheet. */
  container-type: inline-size;
}

.tools,
.modes,
.trailing {
  display: flex;
  align-items: center;
  min-width: 0;
}

/* figma 75:8208 drew 16 between + and the mode chips and 4 between Plan /
   Read-only; the chip gap widened to 12 so the pill chips read as separate
   controls. */
.tools {
  gap: 16px;
}

.modes {
  gap: 12px;
}

.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 <select>, chip-like closed chrome
   (figma ToggleButton: 13/20 medium secondary, 12px chevron). */
.select {
  max-width: 220px;
  height: 28px;
  padding: 0 20px 0 8px;
  border: none;
  border-radius: 8px;
  outline: none;
  background-color: transparent;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 4px center;
  background-size: 12px 12px;
  color: var(--dsw-alias-label-secondary);
  font-size: 13px;
  line-height: 20px;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  appearance: none;
}

.select:hover:not(:disabled) {
  background-color: var(--dsw-alias-interactive-bg-hover);
}

.select:disabled {
  opacity: 0.5;
  cursor: default;
}

/* Primary send (figma IconButton 34:10465): 34px circle, #3964FE light /
   #679EFE dark — the info-fill pair (500→400), NOT button-primary (ink);
   white glyph; empty text = 0.4 opacity. */
.primary {
  display: grid;
  place-items: center;
  flex: none;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 999px;
  background: var(--dsw-alias-button-info-fill);
  /* Static white, not the foreground token: the arrow stays white on the blue
     fill in both themes (design 34:10465). */
  color: #fff;
  cursor: pointer;
  transition: background-color 100ms ease;
  /* Opts out of the row's 2px downward shift (.row top pad): the send circle
     keeps its original seat while the smaller chips sit lower. Transform, not
     margin, so flex centering math is untouched. */
  transform: translateY(-2px);
}

.primary:hover:not(:disabled) {
  background: var(--dsw-alias-button-info-hover);
}

.primary:disabled {
  opacity: 0.4;
  cursor: default;
}

.retry {
  margin-left: 8px;
  padding: 1px 8px;
  border: 1px solid currentColor;
  border-radius: 4px;
  background: transparent;
  color: inherit;
  font-size: 12px;
  cursor: pointer;
}

/* Plain-text reference highlight: a pure range mark over the
   draft's own glyphs — advance untouched, so the two layers cannot drift.
   Chip family colors; clone keeps rounded ends on soft-wrap fragments. */
.textRef {
  background-color: transparent;
  color: var(--dsw-alias-state-business-primary);
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}
.textRef:after {
  display: none;
}

/* Reference chip: rendered in the backdrop at the placeholder offset. Hard
   alignment constraint: the chip's advance must equal the textarea's U+FFFC
   advance EXACTLY or every glyph after it drifts (caret/selection follow the
   textarea character stream). The ::before renders the same U+FFFC through
   the same font stack (DshChipCell 4em cell), so both layers agree by
   construction — no measured widths. The label overlays the cell, clipped
   with an ellipsis; the full name rides the title tooltip. */
.chip {
  position: relative;
  border-radius: 6px;
  background: rgba(97, 135, 216, 0.22);
}

.chip::before {
  content: '\FFFC';
  color: transparent;
}

.chipLabel {
  /* Compensated-scale centering: overflow clipping happens BEFORE transform,
     so the box is laid out at 1/0.72 of the cell and scaled back down — the
     clip edge then lands on the visual cell edge, not mid-glyph. */
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(100% / 0.72 - 10px);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  color: var(--dsw-alias-label-primary);
  white-space: nowrap;
  transform: translate(-50%, -50%) scale(0.72);
}

.chipInvalid {
  background: rgba(216, 97, 97, 0.2);
  text-decoration: line-through;
  opacity: 0.7;
}
