@import 'tailwindcss';
@plugin '@tailwindcss/typography';
@import 'tw-shimmer';
@import 'katex/dist/katex.min.css';
@import '@vscode/codicons/dist/codicon.css';
@custom-variant dark (&:is(.dark *));

/* Sidebar sections: tall viewports give each its own scroller; compact ones
   (this variant) flatten everything into one shared scroll. See ChatSidebar. */
@custom-variant compact (@media (max-height: 768px));

@font-face {
  font-family: 'Collapse';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../../../node_modules/@nous-research/ui/dist/fonts/Collapse-Bold.woff2') format('woff2');
}

/* JetBrains Mono — bundled terminal font (Apache-2.0) so bold/italic share the
   regular face's metrics instead of squeezing against a system fallback. */
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('./fonts/JetBrainsMono-Regular.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('./fonts/JetBrainsMono-Bold.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('./fonts/JetBrainsMono-Italic.woff2') format('woff2');
}

@theme inline {
  --color-background: var(--dt-background);
  --color-foreground: var(--dt-foreground);
  --color-card: var(--dt-card);
  --color-card-foreground: var(--dt-card-foreground);
  --color-muted: var(--dt-muted);
  --color-muted-foreground: var(--dt-muted-foreground);
  --color-popover: var(--dt-popover);
  --color-popover-foreground: var(--dt-popover-foreground);
  --color-primary: var(--dt-primary);
  --color-primary-foreground: var(--dt-primary-foreground);
  --color-secondary: var(--dt-secondary);
  --color-secondary-foreground: var(--dt-secondary-foreground);
  --color-accent: var(--dt-accent);
  --color-accent-foreground: var(--dt-accent-foreground);
  --color-border: var(--dt-border);
  --color-input: var(--dt-input);
  --color-ring: var(--dt-ring);
  --color-destructive: var(--dt-destructive);
  --color-destructive-foreground: var(--dt-destructive-foreground);

  --color-midground: var(--dt-midground);
  --color-midground-foreground: var(--dt-midground-foreground);

  --font-sans: var(--dt-font-sans);
  --font-mono: var(--dt-font-mono);

  --spacing-mul: var(--dt-spacing-mul, 1);

  --radius-xs: calc(var(--radius-scalar) * 0.125rem);
  --radius-sm: calc(var(--radius-scalar) * 0.5rem);
  --radius-md: calc(var(--radius-scalar) * 0.625rem);
  --radius-lg: calc(var(--radius-scalar) * 0.75rem);
  --radius-xl: calc(var(--radius-scalar) * 1rem);
  --radius-2xl: calc(var(--radius-scalar) * 1.5rem);
  --radius-3xl: calc(var(--radius-scalar) * 2rem);
  --radius-4xl: calc(var(--radius-scalar) * 2.5rem);

  --color-sidebar-ring: var(--sidebar-ring);
  --color-sidebar-border: var(--sidebar-border);
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
  --color-sidebar-accent: var(--sidebar-accent);
  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
  --color-sidebar-primary: var(--sidebar-primary);
  --color-sidebar-foreground: var(--sidebar-foreground);
  --color-sidebar: var(--sidebar);

  --shadow-xs: 0 0.0625rem 0.125rem color-mix(in srgb, #000 5%, transparent);
  --shadow-sm:
    0 0 0 0.0625rem color-mix(in srgb, var(--dt-foreground) 6%, transparent),
    0 0.125rem 0.5rem color-mix(in srgb, #000 4%, transparent);
  --shadow-md:
    0 0 0 0.0625rem color-mix(in srgb, var(--dt-foreground) 8%, transparent),
    0 0.25rem 1rem color-mix(in srgb, #000 8%, transparent),
    0 1rem 2rem -1.5rem color-mix(in srgb, #000 18%, transparent);
  /* Soft floating shadow for borderless modals/overlays. Single top light
     source: every layer is centered (x=0) and cast downward, with negative
     spread that grows with the blur so each layer is pulled horizontally inward
     — the shadow pools below the panel instead of bleeding out every side.
     Layered (contact → ambient) for a smooth, natural falloff. */
  --shadow-nous:
    0 0.125rem 0.25rem -0.125rem color-mix(in srgb, #000 7%, transparent),
    0 0.5rem 0.75rem -0.375rem color-mix(in srgb, #000 6%, transparent),
    0 1.25rem 1.75rem -0.875rem color-mix(in srgb, #000 6%, transparent),
    0 2.25rem 3rem -1.75rem color-mix(in srgb, #000 0%, transparent);
  /* Hairline border paired with --shadow-nous on borderless overlays.
     currentColor resolves per-element, so it adapts to text color/theme. */
  --stroke-nous: color-mix(in srgb, currentColor 3%, transparent);
  --shadow-lg:
    inset 0 0.0625rem 0 color-mix(in srgb, #fff 28%, transparent),
    0 0 0 0.0625rem color-mix(in srgb, var(--dt-foreground) 8%, transparent),
    0 0.75rem 2rem color-mix(in srgb, #000 12%, transparent);
  --shadow-composer: 0 0.0625rem 0.125rem color-mix(in srgb, #000 5%, transparent);
}

@layer base {
  :root {
    color-scheme: light;

    --theme-foreground: #17171a;
    --theme-primary: #0053fd;
    --theme-secondary: color-mix(in srgb, #0053fd 7%, #ffffff);
    --theme-accent-soft: color-mix(in srgb, #0053fd 10%, #ffffff);
    --theme-midground: #0053fd;
    --theme-warm: #cf806d;
    --theme-background-seed: #f8faff;
    --theme-sidebar-seed: #f3f7ff;
    --theme-card-seed: #ffffff;
    --theme-elevated-seed: #ffffff;
    --theme-bubble-seed: color-mix(in srgb, #0053fd 6%, #ffffff);
    --theme-neutral-chrome: #f3f3f3;
    --theme-neutral-sidebar: #f3f3f3;
    --theme-neutral-card: #fcfcfc;
    --theme-mix-chrome: 92%;
    --theme-mix-sidebar: 100%;
    --theme-mix-card: 22%;
    --theme-mix-elevated: 28%;
    --theme-mix-bubble: 0%;
    --theme-fill-primary-accent-mix: 16%;
    --theme-fill-secondary-accent-mix: 11%;
    --theme-fill-tertiary-accent-mix: 8%;
    --theme-fill-quaternary-accent-mix: 5%;
    --theme-fill-quinary-accent-mix: 3%;
    --theme-stroke-primary-accent-mix: 24%;
    --theme-stroke-secondary-accent-mix: 16%;
    --theme-stroke-tertiary-accent-mix: 10%;
    --theme-stroke-quaternary-accent-mix: 6%;
    --theme-row-hover-accent-mix: 4%;
    --theme-row-active-accent-mix: 8%;
    --theme-control-hover-accent-mix: 6%;
    --theme-control-active-accent-mix: 8%;

    --ui-base: var(--theme-foreground);
    --ui-accent: var(--theme-midground);
    --ui-accent-secondary: var(--theme-primary);
    --ui-warm: var(--theme-warm);
    --ui-red: #cf2d56;
    --ui-orange: #db704b;
    --ui-yellow: #c08532;
    --ui-green: #1f8a65;
    --ui-cyan: #4c7f8c;
    --ui-blue: #0053fd;
    --ui-purple: #9e94d5;
    --ui-bg-chrome: color-mix(
      in srgb,
      var(--theme-background-seed) var(--theme-mix-chrome),
      var(--theme-neutral-chrome)
    );
    --ui-bg-sidebar: color-mix(
      in srgb,
      var(--theme-sidebar-seed) var(--theme-mix-sidebar),
      var(--theme-neutral-sidebar)
    );
    --ui-bg-editor: color-mix(in srgb, var(--theme-card-seed) var(--theme-mix-card), var(--theme-neutral-card));
    --ui-bg-elevated: color-mix(
      in srgb,
      var(--theme-elevated-seed) var(--theme-mix-elevated),
      var(--theme-neutral-card)
    );
    --ui-bg-card: color-mix(in srgb, var(--ui-accent) 4%, color-mix(in srgb, var(--ui-base) 4%, transparent));
    --ui-bg-input: #fcfcfc;
    --ui-bg-primary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-fill-primary-accent-mix),
      color-mix(in srgb, var(--ui-base) 10%, transparent)
    );
    --ui-bg-secondary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-fill-secondary-accent-mix),
      color-mix(in srgb, var(--ui-base) 7%, transparent)
    );
    --ui-bg-tertiary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-fill-tertiary-accent-mix),
      color-mix(in srgb, var(--ui-base) 5%, transparent)
    );
    --ui-bg-quaternary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-fill-quaternary-accent-mix),
      color-mix(in srgb, var(--ui-base) 4%, transparent)
    );
    --ui-bg-quinary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-fill-quinary-accent-mix),
      color-mix(in srgb, var(--ui-base) 3%, transparent)
    );
    --ui-row-hover-background: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-row-hover-accent-mix),
      color-mix(in srgb, var(--ui-base) 3%, transparent)
    );
    --ui-row-active-background: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-row-active-accent-mix),
      color-mix(in srgb, var(--ui-base) 5%, transparent)
    );
    --ui-control-hover-background: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-control-hover-accent-mix),
      color-mix(in srgb, var(--ui-base) 4%, transparent)
    );
    --ui-control-active-background: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-control-active-accent-mix),
      color-mix(in srgb, var(--ui-base) 5%, transparent)
    );
    --ui-text-primary: color-mix(in srgb, var(--ui-base) 94%, transparent);
    --ui-text-secondary: color-mix(in srgb, var(--ui-base) 74%, transparent);
    --ui-text-tertiary: color-mix(in srgb, var(--ui-base) 54%, transparent);
    --ui-text-quaternary: color-mix(in srgb, var(--ui-base) 36%, transparent);
    --ui-stroke-primary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-stroke-primary-accent-mix),
      color-mix(in srgb, var(--ui-base) 10%, transparent)
    );
    --ui-stroke-secondary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-stroke-secondary-accent-mix),
      color-mix(in srgb, var(--ui-base) 7%, transparent)
    );
    --ui-stroke-tertiary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-stroke-tertiary-accent-mix),
      color-mix(in srgb, var(--ui-base) 5%, transparent)
    );
    --ui-stroke-quaternary: color-mix(
      in srgb,
      var(--ui-accent) var(--theme-stroke-quaternary-accent-mix),
      color-mix(in srgb, var(--ui-base) 3%, transparent)
    );
    --ui-sash-hover-border: color-mix(in srgb, var(--ui-accent) 18%, var(--ui-stroke-tertiary));
    --ui-sash-hover-background: color-mix(in srgb, var(--ui-accent) 6%, transparent);
    --ui-surface-background: var(--ui-bg-editor);
    --ui-sidebar-surface-background: var(--ui-bg-sidebar);
    --ui-chat-surface-background: var(--ui-bg-chrome);
    --ui-editor-surface-background: var(--ui-bg-chrome);
    --ui-chat-bubble-background: color-mix(
      in srgb,
      var(--theme-bubble-seed) var(--theme-mix-bubble),
      var(--theme-neutral-card)
    );
    --ui-chat-bubble-opaque-background: var(--ui-bg-editor);
    --ui-inline-code-background: color-mix(in srgb, #141414 5%, transparent);
    --ui-inline-code-foreground: color-mix(in srgb, #141414 88%, transparent);
    --ui-selection-background: color-mix(in srgb, #ffd24a 55%, transparent);

    --dt-background: var(--ui-bg-chrome);
    --dt-foreground: var(--ui-text-primary);
    --dt-card: var(--ui-bg-editor);
    --dt-card-foreground: var(--ui-text-primary);
    --dt-muted: var(--ui-bg-tertiary);
    --dt-muted-foreground: var(--ui-text-tertiary);
    --dt-popover: color-mix(in srgb, var(--ui-bg-elevated) 96%, transparent);
    --dt-popover-foreground: var(--ui-text-primary);
    --dt-primary: var(--theme-primary);
    --dt-primary-foreground: #fcfcfc;
    --dt-secondary: var(--theme-secondary);
    --dt-secondary-foreground: var(--ui-text-secondary);
    --dt-accent: var(--theme-accent-soft);
    --dt-accent-foreground: var(--ui-text-primary);
    --dt-border: var(--ui-stroke-secondary);
    --dt-input: var(--ui-stroke-primary);
    --dt-ring: var(--ui-stroke-primary);
    --dt-midground: var(--theme-midground);
    --dt-composer-ring: var(--ui-base);
    --dt-destructive: #cf2d56;
    --dt-destructive-foreground: #ffffff;
    --dt-sidebar-bg: var(--ui-bg-sidebar);
    --dt-sidebar-border: var(--ui-stroke-secondary);
    --dt-user-bubble: var(--ui-chat-bubble-background);
    --dt-user-bubble-border: var(--ui-stroke-tertiary);

    --dt-font-sans:
      'Segoe WPC', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif,
      'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji', emoji;
    /* Key caps always use the native UI face — never theme typography overrides. */
    --dt-font-kbd: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', system-ui, sans-serif;
    /* JetBrains Mono first — the face we bundle (@font-face above) and the
       terminal's primary — so code/diff match the terminal on every platform
       instead of drifting to a system Cascadia Code where it's installed. */
    --dt-font-mono:
      'JetBrains Mono', 'Cascadia Code', 'SF Mono', ui-monospace, Menlo, Consolas, monospace, 'Apple Color Emoji',
      'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji', emoji;
    --dt-base-size: 1rem;
    --dt-line-height: 1.5;
    --dt-letter-spacing: 0;
    --dt-spacing-mul: 1;

    --radius: 0.75rem;
    --radius-scalar: 0.6;

    /* Space under last message vs overlay composer — driven by the measured composer height (see composer/index.tsx)
       plus the out-of-flow status stack's measured height (see status-stack/index.tsx) when one is showing. */
    --status-stack-measured-height: 0px;
    --thread-last-message-clearance: calc(var(--composer-measured-height) + var(--status-stack-measured-height) + 2rem);

    --composer-shell-pad-block-end: 0.625rem;
    --message-text-indent: 0.75rem;
    --conversation-text-font-size: 0.8125rem;
    --conversation-tool-font-size: 0.6875rem;
    --conversation-caption-font-size: 0.75rem;
    --conversation-line-height: 1.125rem;
    --conversation-caption-line-height: 1rem;
    --conversation-turn-gap: 0.375rem;
    /* Gap between top-level turn blocks (prose ↔ tools ↔ thinking) — enough air
       that scaffolding reads as separate from the reply, not crammed into it. */
    --turn-block-gap: 0.75rem;
    /* Tight gap between tool rows inside a single action group, so a back-to-back
       run still reads as one cohesive sequence. */
    --tool-row-gap: 0.375rem;
    /* Paragraph spacing — vertical gap between prose paragraphs, both inside a
       markdown block and between consecutive prose parts. Single knob; tweak
       freely. */
    --paragraph-gap: 0.45rem;
    --sticky-human-top: 0.23rem;
    --file-tree-row-height: 1.375rem;

    --composer-width: 48.75rem;
    --composer-control-size: 1.5rem;
    --composer-control-primary-size: 1.625rem;
    --composer-control-gap: 0.25rem;
    --composer-row-gap: 0.25rem;
    --composer-ring-strength: 1;
    --composer-surface-pad-x: 0.5rem;
    --composer-surface-pad-y: 0.3125rem;
    --composer-input-min-height: 1.625rem;
    --composer-input-max-height: 9.375rem;
    --composer-input-inline-min-width: 8rem;
    --composer-fallback-height: 2.75rem;
    --composer-measured-height: calc(0.5rem + var(--composer-shell-pad-block-end) + var(--composer-fallback-height));
    --composer-surface-measured-height: var(--composer-fallback-height);
    --thread-viewport-height: max(
      0rem,
      calc(100% - var(--composer-measured-height) + var(--composer-surface-measured-height))
    );
    --vsq: min(0.5vh, 0.5vw);
    --image-preview-max-width: 34rem;
    --image-preview-height: clamp(16.25rem, calc(var(--vsq) * 100), 26.25rem);

    --sidebar-width: 14.8125rem;
    --chat-min-width: 28rem;
    --titlebar-control-size: 1.25rem;
    --titlebar-control-height: 1.375rem;
    --sidebar-content-inline-padding: 1rem;

    --sidebar: var(--dt-sidebar-bg);
    --sidebar-foreground: var(--dt-foreground);
    --sidebar-primary: var(--dt-primary);
    --sidebar-primary-foreground: var(--dt-primary-foreground);
    --sidebar-accent: var(--ui-control-active-background);
    --sidebar-accent-foreground: var(--dt-accent-foreground);
    --sidebar-border: var(--dt-sidebar-border);
    --sidebar-ring: var(--dt-ring);
    --sidebar-edge-border: color-mix(in srgb, var(--ui-base) 7.5%, transparent);
    --chrome-action-hover: var(--ui-control-hover-background);

    --midground: var(--dt-midground);
    --background: var(--dt-background);
    --foreground: var(--dt-foreground);

    --warm-glow: color-mix(in srgb, var(--ui-warm) 32%, color-mix(in srgb, var(--ui-accent) 6%, transparent));
    /* `--noise-opacity-mul` is set per-mode by `applyTheme()`. */
    --noise-opacity-mul: 1;
    --backdrop-invert-mul: 1;
  }

  :root.dark {
    /* Per-mode mix knobs — overridden inline by `applyTheme()` per skin. */
    --theme-mix-chrome: 74%;
    --theme-mix-card: 38%;
    --theme-mix-elevated: 46%;
    --theme-mix-bubble: 46%;
    --theme-neutral-chrome: #0d0d0e;
    --theme-neutral-sidebar: #0a0a0b;
    --theme-neutral-card: #161618;

    /* Dark-only accent palette overrides. */
    --ui-red: #e75e78;
    --ui-green: #55a583;
    --ui-cyan: #6f9ba6;

    --sidebar-edge-border: color-mix(in srgb, var(--ui-base) 12%, transparent);
    --composer-ring-strength: 1.3;
    --backdrop-invert-mul: 0;

    --ui-inline-code-background: color-mix(in srgb, #ffffff 7%, transparent);
    --ui-inline-code-foreground: color-mix(in srgb, #ffffff 88%, transparent);
    --ui-selection-background: color-mix(in srgb, #ffd24a 38%, transparent);
  }

  * {
    box-sizing: border-box;
    border-color: var(--dt-border);
  }

  html,
  body,
  #root {
    height: 100%;
    /* App shell, not a document: the window itself never scrolls on either axis
       (panes own their own scroll). Belt to the auto-scroll axis-lock in the
       sidebar reorder DnD — nothing can drag the whole shell sideways. */
    overflow: hidden;
  }

  html {
    font-size: var(--dt-base-size, 0.875rem);
  }

  body {
    margin: 0;
    background: var(--ui-chat-surface-background);
    color: var(--dt-foreground);
    font-family: var(--dt-font-sans);
    font-size: 0.8125rem;
    line-height: var(--dt-line-height, 1.55);
    letter-spacing: var(--dt-letter-spacing, 0);
    -webkit-user-select: none;
    user-select: none;
    -webkit-font-smoothing: antialiased;
  }

  button,
  textarea {
    font: inherit;
  }

  :where(
    a,
    .underline,
    [class~='hover:underline'],
    [class~='focus:underline'],
    [class~='focus-visible:underline'],
    [class~='group-hover:underline'],
    [class~='peer-hover:underline']
  ) {
    text-decoration-color: color-mix(in srgb, currentColor 20%, transparent);
    text-underline-offset: 0.25rem;
  }

  *::selection {
    background: var(--ui-selection-background);
    color: inherit;
  }
}

.dither {
  background: repeating-conic-gradient(currentColor 0% 25%, transparent 0% 50%) 0 0 / 0.125rem 0.125rem;
}

:root:not([style*='--theme-asset-bg:']) .theme-default-filler {
  display: block;
}

:root[style*='--theme-asset-bg:'] .theme-default-filler {
  display: none;
}

/* Primitive-level pointer cursor for every interactive control (buttons,
   selects, menu items, switches, tabs, summaries). Keeps individual
   components from having to hardcode `cursor-pointer`; explicit cursor
   utilities (cursor-grab, cursor-default, disabled:cursor-*) still win since
   they live in the utilities layer. */
@layer base {
  button:not(:disabled):not([aria-disabled='true']),
  summary,
  [role='button']:not([aria-disabled='true']),
  [role='menuitem']:not([aria-disabled='true']),
  [role='menuitemradio']:not([aria-disabled='true']),
  [role='menuitemcheckbox']:not([aria-disabled='true']),
  [role='option']:not([aria-disabled='true']),
  [role='switch']:not([aria-disabled='true']),
  [role='tab']:not([aria-disabled='true']) {
    cursor: pointer;
  }
}

@layer utilities {
  [class*='rounded-full'],
  [class*=':rounded-full'] {
    border-radius: calc(var(--radius-scalar) * 9999rem);
  }
}

@keyframes arc-border {
  0% {
    background-position: 15% 15%;
  }
  100% {
    background-position: 75% 75%;
  }
}

.arc-border {
  --arc-c0: color-mix(in srgb, var(--dt-foreground) 0%, transparent);
  --arc-c1: var(--dt-midground);
  --arc-c2: var(--dt-background);
  --arc-angle: 160deg;
  --arc-width: 0.078125rem;
  --arc-inset: -0.125rem;
  --arc-duration: 2.23s;

  pointer-events: none;
  position: absolute;
  overflow: hidden;
  border-radius: inherit;
  inset: var(--arc-inset);
  padding: var(--arc-width);
  mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}

:root.dark .arc-border {
  --arc-c1: var(--dt-foreground);
}

/* Quest-style "needs you" pulse for a clarify-blocked session's dot —
   a soft amber glow that breathes so the row draws the eye without a toast. */
@keyframes quest-glow {
  0%,
  100% {
    transform: scale(1);
    box-shadow:
      0 0 0.1875rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 70%, transparent),
      0 0 0.5rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 45%, transparent);
  }
  50% {
    transform: scale(1.18);
    box-shadow:
      0 0 0.3125rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 90%, transparent),
      0 0 0.875rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 65%, transparent);
  }
}

.quest-glow {
  animation: quest-glow 1.8s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .quest-glow {
    animation: none;
    box-shadow:
      0 0 0.25rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 80%, transparent),
      0 0 0.625rem color-mix(in srgb, var(--color-amber-500, #f59e0b) 55%, transparent);
  }
}

/* Command-palette deep-link: briefly flash the targeted settings row. */
@keyframes setting-field-flash {
  0% {
    background-color: color-mix(in srgb, var(--dt-primary, #f59e0b) 22%, transparent);
  }
  100% {
    background-color: transparent;
  }
}

.setting-field-highlight {
  animation: setting-field-flash 1.6s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .setting-field-highlight {
    animation: none;
  }
}

.arc-border::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(
    var(--arc-angle),
    transparent 0%,
    var(--arc-c0) 15%,
    var(--arc-c1) 20%,
    var(--arc-c2) 25%,
    transparent 35%,
    transparent 40%,
    var(--arc-c0) 55%,
    var(--arc-c1) 60%,
    var(--arc-c2) 65%,
    transparent 75%,
    transparent 80%,
    var(--arc-c0) 95%,
    var(--arc-c1) 100%
  );
  background-size: 300% 300%;
  animation: arc-border var(--arc-duration) linear infinite;
}

/* Flip the arc's travel direction (e.g. the Nous Portal hero row). */
.arc-border.arc-reverse::before {
  animation-direction: reverse;
}

/* Nous Portal hero: slower, blue → orange arc. */
.arc-border.arc-nous,
:root.dark .arc-border.arc-nous {
  --arc-c1: #4f8cff;
  --arc-c2: #ff8c42;
  --arc-duration: 3.27s;
}

@media (prefers-reduced-motion: reduce) {
  .arc-border::before {
    animation: none;
  }
}

/* No focus rings, anywhere. Kills the native outline plus Tailwind's
   `focus-visible:ring-*` (a box-shadow driven by --tw-ring-*). Unlayered so it
   beats the utilities layer without !important on the outline. The composer /
   .desktop-input-chrome focus glow is untouched — those set `box-shadow`
   directly rather than through the ring vars. */
*:focus,
*:focus-visible {
  outline: none;
}

*:focus-visible {
  --tw-ring-shadow: 0 0 #0000 !important;
  --tw-ring-offset-shadow: 0 0 #0000 !important;
}

button {
  -webkit-app-region: no-drag;
}

/* Button variant styling lives entirely in the cva in components/ui/button.tsx
   (the single source of truth). Don't re-add [data-slot='button'] rules here —
   attribute selectors out-specify the Tailwind utilities and silently override
   the variants. */

[data-slot='dropdown-menu-content'],
[data-slot='select-content'],
[data-slot='dialog-content'] {
  border-color: var(--ui-stroke-secondary);
  background: color-mix(in srgb, var(--ui-bg-elevated) 96%, transparent);
  box-shadow: var(--shadow-md);
  backdrop-filter: blur(0.75rem) saturate(1.08);
  -webkit-backdrop-filter: blur(0.75rem) saturate(1.08);
}

[data-slot='dropdown-menu-item']:focus,
[data-slot='dropdown-menu-checkbox-item']:focus,
[data-slot='dropdown-menu-radio-item']:focus {
  background: var(--ui-bg-tertiary);
  color: var(--ui-text-primary);
}

input,
textarea,
[contenteditable]:not([contenteditable='false']),
[data-slot='aui_user-message-root'],
[data-slot='aui_assistant-message-content'],
[data-slot='aui_system-message-root'],
[data-selectable-text='true'],
[data-selectable-text='true'] * {
  -webkit-user-select: text;
  user-select: text;
}

button,
[role='button'] {
  -webkit-user-select: none;
  user-select: none;
}

img,
picture,
video,
canvas,
svg {
  -webkit-user-select: none;
  user-select: none;
}

img,
video,
canvas {
  -webkit-user-drag: none;
}

/* Shared input chrome — mirrors composer hover/focus FX. Unlayered to beat Tailwind utilities. */
.desktop-input-chrome {
  --ring-pct: 18%;
  --ring-fall: var(--dt-input);
  background: color-mix(in srgb, var(--dt-card) 68%, transparent);
  border-color: color-mix(
    in srgb,
    var(--dt-composer-ring) calc(var(--ring-pct) * var(--composer-ring-strength)),
    var(--ring-fall)
  );
  box-shadow: none;
  transition:
    background-color 200ms ease-out,
    border-color 200ms ease-out;
}

.desktop-input-chrome:hover {
  --ring-pct: 30%;
  background: color-mix(in srgb, var(--dt-card) 86%, transparent);
}

.desktop-input-chrome:focus {
  --ring-pct: 45%;
  --ring-fall: transparent;
  background: var(--dt-card);
  box-shadow: none;
  outline: none;
}

.desktop-input-chrome[aria-invalid='true'] {
  border-color: var(--dt-destructive);
}

@layer components {
  .scrollbar-dt,
  .scrollbar-dt * {
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--dt-midground) 18%, transparent) transparent;
  }

  .scrollbar-dt::-webkit-scrollbar,
  .scrollbar-dt *::-webkit-scrollbar {
    width: 0.5rem;
    height: 0.5rem;
  }

  .scrollbar-dt::-webkit-scrollbar-track,
  .scrollbar-dt::-webkit-scrollbar-corner,
  .scrollbar-dt *::-webkit-scrollbar-track,
  .scrollbar-dt *::-webkit-scrollbar-corner {
    background: transparent;
  }

  .scrollbar-dt::-webkit-scrollbar-thumb,
  .scrollbar-dt *::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--dt-midground) 18%, transparent);
    border-radius: 9999rem;
    border: 0.125rem solid transparent;
    background-clip: padding-box;
  }

  .scrollbar-dt::-webkit-scrollbar-thumb:hover,
  .scrollbar-dt *::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--dt-midground) 40%, transparent);
    background-clip: padding-box;
  }

  .scrollbar-dt::-webkit-scrollbar-button,
  .scrollbar-dt *::-webkit-scrollbar-button {
    display: none;
  }

  /* Variant for portaled overlays (Radix DropdownMenu, Popover, etc.) that
     render under document.body, outside the `.scrollbar-dt` scope on
     #root. Same visual treatment, applied directly to the overlay
     container so its (and only its) internal scrollbar is themed. */
  .dt-portal-scrollbar {
    scrollbar-width: thin;
    scrollbar-color: color-mix(in srgb, var(--dt-midground) 28%, transparent) transparent;
  }

  .dt-portal-scrollbar::-webkit-scrollbar {
    width: 0.375rem;
    height: 0.375rem;
  }

  .dt-portal-scrollbar::-webkit-scrollbar-track,
  .dt-portal-scrollbar::-webkit-scrollbar-corner {
    background: transparent;
  }

  .dt-portal-scrollbar::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--dt-midground) 28%, transparent);
    border-radius: 9999rem;
    border: 0.0625rem solid transparent;
    background-clip: padding-box;
  }

  .dt-portal-scrollbar::-webkit-scrollbar-thumb:hover {
    background: color-mix(in srgb, var(--dt-midground) 50%, transparent);
    background-clip: padding-box;
  }

  .dt-portal-scrollbar::-webkit-scrollbar-button {
    display: none;
  }
}

/* Bottom clearance lives on [data-slot='aui_composer-clearance'] —
   virtualized items unmount, so :nth-last-child can't fire reliably. */

[data-slot='aui_assistant-message-content'] {
  padding-left: var(--message-text-indent);
  font-size: var(--conversation-text-font-size);
  line-height: 1.5;
}

[data-slot='aui_assistant-message-root'] {
  width: 100%;
}

[data-slot='aui_assistant-message-content'] .aui-md,
[data-slot='aui_assistant-message-content'] .aui-md :where(p, li, blockquote, table, pre) {
  font-size: inherit;
}

/* Tailwind Typography sets `.prose :where(p) { margin: 1.25em }` (~16px). That
   selector ties our `my-*` utility on specificity and wins on source order, so
   paragraph spacing must be reclaimed here at higher specificity. One tight
   top-margin (bottom zeroed to avoid doubling), first child reset to flush. */
[data-slot='aui_assistant-message-content'] .aui-md :where(p) {
  margin-block: var(--paragraph-gap) 0;
}

/* First rendered element of a prose block is flush — the block-level gap above
   (tool / paragraph) already provides the separation. Reach one level deep too:
   Streamdown wraps blocks in a `div.space-y-*`, so the real first line is the
   first child's first child. */
[data-slot='aui_assistant-message-content'] .aui-md > :first-child,
[data-slot='aui_assistant-message-content'] .aui-md > :first-child > :first-child {
  margin-top: 0;
}

/* Prose, tools, todos, and thinking all share one left edge (the message
   content's --message-text-indent). No extra prose indent — a single gutter
   reads cleaner than a ragged tool-vs-reply column. */

/* RTL/bidi chat text (#44150): each block resolves its own base direction from
   its first strong char (UAX#9 plaintext). text-align:start makes that resolved
   direction drive alignment too — load-bearing, since the user bubble pins
   text-left. direction is never set, so chrome/layout/list-indent stay LTR (the
   issue asks not to flip the whole UI). Covers assistant prose, user lines, and
   both composers (main + edit share composer-rich-input). */
[data-slot='aui_assistant-message-content'] .aui-md :where(p, h1, h2, h3, h4, h5, h6, li, blockquote),
[data-slot='aui_user-inline-text'],
[data-slot='composer-rich-input'] {
  unicode-bidi: plaintext;
  text-align: start;
}

/* Inline code/KaTeX don't vote on direction and keep their own order: isolate
   makes bidi treat each as one neutral, so a block that *starts* with `./run.sh`
   then Arabic still resolves RTL, and the command's neutrals (dots/slashes)
   aren't reordered by the surrounding RTL run. */
[data-slot='aui_assistant-message-content'] .aui-md :where(:not(pre) > code),
[data-slot='aui_user-inline-code'],
[data-slot='aui_assistant-message-content'] .aui-md .katex {
  direction: ltr;
  unicode-bidi: isolate;
}

/* Fenced code stays LTR even inside an RTL list item/blockquote — never mirrors. */
[data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'],
[data-slot='aui_user-fence'] {
  direction: ltr;
  text-align: left;
}

[data-slot='aui_user-message-root'] {
  top: var(--sticky-human-top);
}

[data-slot='aui_user-message-root'],
[data-slot='aui_edit-composer-root'] {
  --human-msg-line-height: 1.3;
  font-size: var(--conversation-text-font-size);
}

[data-slot='aui_user-inline-text'] {
  line-height: var(--human-msg-line-height);
}

[data-slot='aui_edit-composer-root'] [data-slot='composer-rich-input'] {
  line-height: var(--human-msg-line-height);
}

/* Sticky human bubbles clamp to ~2 lines with a soft bottom fade so a long
   prompt doesn't dominate the viewport. The clamp lifts only in the edit
   composer; expanding on read-only :focus-within ran on mousedown (before the
   swap) and fought stick-to-bottom when parked at the bottom. */
.sticky-human-clamp {
  cursor: pointer;
  max-height: calc(4 * var(--human-msg-line-height) * var(--conversation-text-font-size) + 0.15rem);
  overflow: hidden;
}

.sticky-human-clamp[data-clamped='true'] {
  -webkit-mask-image: linear-gradient(to bottom, #000 55%, transparent);
  mask-image: linear-gradient(to bottom, #000 55%, transparent);
}

/* Stick-to-bottom owns scrollTop while following. Once escaped, native anchoring
   is safe and keeps sticky human edits from shoving the viewport; data-editing
   enables that path before React swaps in the inline editor. */
[data-slot='aui_thread-viewport'] {
  overflow-anchor: none;
}

[data-slot='aui_thread-viewport'][data-following='false'],
[data-slot='aui_thread-viewport'][data-editing='true'] {
  overflow-anchor: auto;
}

[data-slot='aui_thread-content'] {
  max-width: var(--composer-width);
  padding-inline: 1.5rem;
}

[data-slot='aui_intro'] {
  align-items: center;
  justify-content: center;
  padding-bottom: var(--composer-measured-height);
  text-align: center;
}

[data-slot='aui_intro'] > div {
  max-width: min(var(--composer-width), 82vw);
}

[data-slot='aui_intro'] p:last-child {
  max-width: 34rem;
  margin-inline: auto;
  color: var(--ui-text-tertiary);
  font-size: 0.875rem;
  line-height: 1.45;
}

.fit-text {
  --fit-captured-length: initial;
  --fit-support-sentinel: var(--fit-captured-length, 9999px);

  display: flex;
  container-type: inline-size;
}

.fit-text > [aria-hidden] {
  visibility: hidden;
}

.fit-text > :not([aria-hidden]) {
  flex-grow: 1;
  container-type: inline-size;

  --fit-captured-length: 100cqi;
  --fit-available-space: var(--fit-captured-length);
}

.fit-text > :not([aria-hidden]) > * {
  --fit-support-sentinel: inherit;
  --fit-captured-length: 100cqi;
  --fit-ratio: tan(atan2(var(--fit-available-space), var(--fit-available-space) - var(--fit-captured-length)));

  display: block;
  inline-size: var(--fit-available-space);
  font-size: clamp(
    var(--fit-min, 1em),
    1em * var(--fit-ratio),
    var(--fit-max, infinity * 1px) - var(--fit-support-sentinel)
  );
}

@container (inline-size > 0) {
  .fit-text > :not([aria-hidden]) > * {
    white-space: nowrap;
  }
}

@property --fit-captured-length {
  syntax: '<length>';
  initial-value: 0px;
  inherits: true;
}

[data-slot='composer-root'] {
  /* +10px width compensates the 5px side padding so the visible surface keeps
     its exact width/position — the inline padding is just transparent grab space
     for the peel-out drag, matching the floating composer's 5px platform. */
  width: calc(min(var(--composer-width), calc(100% - 2rem)) + 10px);
  padding-inline: 5px;
  padding-bottom: var(--composer-shell-pad-block-end);
}

/* Popped-out (floating) composer: compact width + an even 5px transparent grab
   platform. The higher-specificity selector resets the base rule's padding-bottom
   so the inset is equal on all four sides (not 5px sides / shell-pad bottom). */
[data-slot='composer-root'][data-popped-out] {
  width: var(--composer-popout-width, 24rem);
  max-width: calc(100vw - 1.5rem);
  padding: 5px;
}

/* Dock glow intensity scale — dimmer in light mode (the primary glow reads
   much stronger over a light backdrop), full strength in dark mode. */
:root {
  --dock-glow-scale: 0.55;
}

.dark {
  --dock-glow-scale: 1;
}

/* Drag-region hatch — a diagonal ///// pattern (Photoshop-style) that fades into
   the transparent grab margin on hover (and stays while dragging) to signal the
   composer is draggable. Inherits the root radius so it clips to the corners. */
[data-slot='composer-drag-region'] {
  /* Hatch frame radius (tuned by hand). */
  border-radius: 0.4rem;
  opacity: 0;
  transition: opacity 150ms ease;
  background-image: repeating-linear-gradient(
    -45deg,
    color-mix(in srgb, var(--ui-text-tertiary) 38%, transparent) 0,
    color-mix(in srgb, var(--ui-text-tertiary) 38%, transparent) 1px,
    transparent 1px,
    transparent 3.5px
  );
}

[data-slot='composer-drag-region']:hover,
[data-slot='composer-drag-region'][data-dragging] {
  opacity: 0.33;
}

[data-slot='composer-root'] > .pointer-events-none {
  background: linear-gradient(
    to bottom,
    transparent,
    color-mix(in srgb, var(--ui-chat-surface-background) 88%, transparent)
  ) !important;
}

[data-slot='composer-surface'] {
  border-color: var(--ui-stroke-secondary) !important;
}

/* On focus we don't change the fill — just shift the border ~15% toward the
   foreground, which darkens it in light mode and lightens it in dark mode. */
[data-slot='composer-surface']:focus-within {
  border-color: color-mix(in srgb, var(--ui-stroke-secondary) 85%, var(--dt-foreground)) !important;
}

[data-slot='composer-fade'] {
  min-height: 2.375rem;
}

[data-slot='composer-rich-input'] {
  color: var(--ui-text-primary);
  font-size: 0.8125rem;
}

[data-slot='composer-rich-input']:empty::before {
  color: var(--ui-text-tertiary) !important;
}

/* ── Composer fill — ONE var painted by the surface AND anything docked to it
   (slash·@ popover, `?` help). State ladder sets the var; consumers just paint
   `background: var(--composer-fill)`, so every state matches by construction.
   The :has() rule is last on purpose: while a completion drawer is open it
   beats focus/scroll and forces an OPAQUE fill (both mix endpoints solid) —
   translucent glass can never match across the two layers because they sample
   different backdrops. */
:root {
  /* Fallback for drawers outside the main composer (e.g. edit-message). */
  --composer-fill: color-mix(in srgb, var(--dt-card) 90%, var(--dt-background));
}

[data-slot='composer-root'] {
  --composer-fill: color-mix(in srgb, var(--dt-card) 72%, transparent);
}

[data-slot='composer-root'][data-thread-scrolled-up] {
  --composer-fill: color-mix(in srgb, var(--dt-card) 48%, transparent);
}

/* Tool/thinking blocks now live at message-text alignment (no leading
   chevron column to escape into), so their headers and bodies share a
   common left edge with the model's text. */
[data-slot='aui_assistant-message-content'] > [data-slot='tool-block'],
[data-slot='aui_assistant-message-content'] > [data-slot='aui_thinking-disclosure'] {
  width: 100%;
  max-width: 100%;
}

[data-slot='aui_assistant-message-content'] .aui-md [data-streamdown='code-block'] code {
  max-width: none;
  font-family: inherit;
  font-size: inherit;
  padding: 0;
  border-radius: 0;
  background: transparent;
  color: inherit;
  overflow-x: visible;
  overflow-wrap: inherit;
  vertical-align: baseline;
  word-break: inherit;
  white-space: inherit;
}

/* Streamdown's adapter wraps code fences in a `data-streamdown="code-block"`
   container with its own card chrome. We render our own <CodeCard>, so this
   strips the upstream chrome down to a layout-only passthrough. */
[data-slot='aui_assistant-message-content'] .aui-md [data-streamdown='code-block'] {
  contain: none;
  overflow: visible;
  margin-block: var(--paragraph-gap) 0 !important;
  padding: 0 !important;
  gap: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  color: inherit;
}

[data-slot='aui_assistant-message-content'] .aui-md [data-streamdown='code-block']:has(.aui-prose-fence) {
  margin-block: 0 !important;
}

[data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'] {
  /* Streamdown nests blocks, so the container's child-combinator rhythm can't
     reach the card. Carry the paragraph gap on the card itself (top-owned);
     collapses cleanly with the wrapper's margin when one is present, and the
     first-child reset still flushes a leading code block. */
  margin-block: var(--paragraph-gap) 0;
  position: relative;
  transition:
    border-color 180ms ease-out,
    box-shadow 180ms ease-out,
    background-color 180ms ease-out;
}

[data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'][data-streaming='true'] {
  animation:
    code-card-stream-enter 180ms cubic-bezier(0.16, 1, 0.3, 1) both,
    code-card-stream-glow 1.8s ease-in-out 180ms infinite alternate;
  border-color: color-mix(in srgb, var(--dt-ring) 24%, var(--ui-stroke-tertiary));
  box-shadow:
    0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 10%, transparent),
    0 0.625rem 1.75rem color-mix(in srgb, var(--dt-ring) 8%, transparent);
}

[data-slot='aui_assistant-message-content']
  .aui-md
  [data-slot='code-card'][data-streaming='true']
  [data-slot='code-card-body'] {
  -webkit-mask-image: linear-gradient(to bottom, black 0%, black calc(100% - 1.5rem), rgb(0 0 0 / 64%) 100%);
  mask-image: linear-gradient(to bottom, black 0%, black calc(100% - 1.5rem), rgb(0 0 0 / 64%) 100%);
}

[data-slot='aui_assistant-message-content'] .aui-md :not(pre) > code {
  background: var(--ui-inline-code-background);
  color: var(--ui-inline-code-foreground);
}

[data-slot='aui_assistant-message-content'] .aui-md :where(.aui-shiki, .aui-shiki > pre) {
  margin: 0 !important;
}

[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table {
  border-spacing: 0;
}

[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table > table,
[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table thead,
[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table tbody,
[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table tr,
[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table th,
[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table td {
  margin: 0 !important;
  margin-block-start: 0 !important;
  margin-block-end: 0 !important;
}

[data-slot='aui_assistant-message-content'] .aui-md .aui-md-table thead {
  border-bottom-color: var(--dt-border) !important;
}

/* Tool / thinking blocks are scaffolding around the model's reply, so we
   keep them transparent and fade them slightly. The reading column (prose)
   stays at full strength; scaffolding lifts back to full opacity on
   hover/focus so it stays legible when the user actually wants to read it. */
[data-slot='tool-block'],
[data-slot='aui_thinking-disclosure'] {
  background: transparent !important;
}

/* Fade scaffolding so the prose reading column stays primary. Two targets:
   a thinking disclosure fades as one block, and each *individual* tool row
   (`[data-tool-row]`) fades on its own. We deliberately do NOT fade the tool
   group wrapper (`[data-tool-group]`): opacity on a parent opens a stacking
   context, so a child row can never be more opaque than the group — that made
   it impossible to keep one row lit (an open diff) while its siblings faded.
   With the fade per-row, each row hovers/focuses independently. */
[data-slot='aui_assistant-message-content'] > [data-slot='aui_thinking-disclosure'],
[data-slot='aui_assistant-message-content'] [data-slot='tool-block'][data-tool-row] {
  opacity: 0.67;
  transition: opacity 120ms ease-out;
}

/* Lift on hover or *keyboard* focus only. `:focus-within` also matches the
   focus a mouse click leaves on the disclosure toggle, which kept a row lit
   after you clicked to collapse it; `:has(:focus-visible)` excludes that. */
[data-slot='aui_assistant-message-content'] > [data-slot='aui_thinking-disclosure']:is(:hover, :has(:focus-visible)),
[data-slot='aui_assistant-message-content'] [data-slot='tool-block'][data-tool-row]:is(:hover, :has(:focus-visible)) {
  opacity: 1;
}

/* Syntax-highlighted inline diff (Shiki): strip the theme's own surface +
   default margins so context lines stay transparent and each changed line owns
   its tint. `display: grid` on the code puts one `.line` per row and drops the
   whitespace-only `\n` nodes between them — without it, full-width block lines
   double up with the literal newlines (phantom blank rows). */
[data-slot='file-diff-panel'] .shiki,
[data-slot='file-diff-panel'] .shiki code {
  margin: 0;
  background: transparent !important;
}

[data-slot='file-diff-panel'] .shiki code {
  display: grid;
}

/* The github-dark token palette reads candy-bright at our small code size.
   `github-dark-dimmed` only dims the *background* (which we strip), so soften
   the token *foregrounds* directly — a small saturation + brightness pullback,
   hues preserved — for both code blocks and inline diffs. Dark mode only. */
.dark .shiki {
  filter: saturate(0.82) brightness(0.92);
}

/* File edits (write_file / edit_file / patch) are the deliverable, not
   scaffolding — the diff is what the user reviews, like a PR. An *expanded*
   edit stays at full strength; collapsed it fades like any other row. The
   `data-file-edit` marker sits on the same row element and is only present
   while the row is open. */
[data-slot='aui_assistant-message-content'] [data-slot='tool-block'][data-tool-row][data-file-edit] {
  opacity: 1;
}

/* Conversation block rhythm. assistant-ui renders each range as a direct child
   of the message content with no per-part wrapper, so adjacency rules cover
   every pairing — first block needs no reset, nested tool rows are untouched.
   Two tiers: scaffolding (tool / thinking) gets a roomy block gap so it reads
   as separate from the reply; consecutive prose collapses to a tight paragraph
   rhythm so split-out text parts don't look like a big gap. */
/* Scaffolding adjacent to anything → roomy block gap. */
[data-slot='aui_assistant-message-content']
  > :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'])
  + :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure'], .aui-md),
[data-slot='aui_assistant-message-content']
  > .aui-md
  + :is([data-slot='tool-block'], [data-slot='aui_thinking-disclosure']) {
  margin-top: var(--turn-block-gap);
}

/* Prose ↔ prose → tight paragraph rhythm, matching in-block paragraph spacing. */
[data-slot='aui_assistant-message-content'] > .aui-md + .aui-md {
  margin-top: var(--paragraph-gap);
}

/* Message action bars — flat icon hits with default dim; only the hovered/focused control is full-strength. */
[data-slot='aui_msg-actions'] button {
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  padding: 0;
  gap: 0;
  height: auto;
  width: auto;
  min-height: 0;
  min-width: 0;
  flex-shrink: 0;
  cursor: pointer;
  color: var(--color-muted-foreground);
  opacity: 0.5;
}

[data-slot='aui_msg-actions'] button:disabled {
  cursor: default;
}

[data-slot='aui_msg-actions'] button:hover {
  background: transparent;
  color: var(--color-foreground);
  opacity: 1;
}

[data-slot='aui_msg-actions'] button:active {
  background: transparent;
}

[data-slot='aui_msg-actions'] button:focus-visible {
  opacity: 1;
}

[data-slot='aui_msg-actions'] button svg {
  width: 0.875rem;
  height: 0.875rem;
}

/* Live thinking preview window. Pairs with the ResizeObserver in
   ThinkingDisclosure that pins scrollTop to the bottom — older lines fade
   into the top mask while the latest tokens settle in below. */
.thinking-preview {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 28%, black 100%);
  mask-image: linear-gradient(to bottom, transparent 0%, black 28%, black 100%);
}

@keyframes code-card-stream-enter {
  from {
    opacity: 0.74;
    transform: translateY(0.375rem);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Floating "jump to bottom" control (see scroll-to-bottom-button.tsx).
   Directional scale: it contracts toward 1 as it arrives (from 1.1) and keeps
   contracting to 0.9 as it leaves — always shrinking in the direction of
   travel, so the motion reads as a soft settle / recede rather than a pop. The
   X half-offset stays baked into every transform so `left-1/2` centering holds
   through the animation. */
.thread-jump-button {
  opacity: 0;
  transform: translateX(-50%) translateY(0.3rem) scale(0.9);
}

.thread-jump-button[data-state='in'] {
  animation: thread-jump-in 200ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
}

.thread-jump-button[data-state='out'] {
  animation: thread-jump-out 180ms ease-in forwards;
}

@keyframes thread-jump-in {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(0.3rem) scale(1.1);
  }

  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1);
  }
}

@keyframes thread-jump-out {
  from {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1);
  }

  to {
    opacity: 0;
    transform: translateX(-50%) translateY(0.3rem) scale(0.9);
  }
}

@media (prefers-reduced-motion: reduce) {
  .thread-jump-button[data-state='in'],
  .thread-jump-button[data-state='out'] {
    animation: none;
    transition: opacity 120ms linear;
  }

  .thread-jump-button[data-state='in'] {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(1);
  }
}

@keyframes code-card-stream-glow {
  from {
    border-color: color-mix(in srgb, var(--dt-ring) 18%, var(--ui-stroke-tertiary));
    box-shadow:
      0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 6%, transparent),
      0 0.5rem 1.5rem color-mix(in srgb, var(--dt-ring) 5%, transparent);
  }

  to {
    border-color: color-mix(in srgb, var(--dt-ring) 32%, var(--ui-stroke-tertiary));
    box-shadow:
      0 0 0 0.0625rem color-mix(in srgb, var(--dt-ring) 12%, transparent),
      0 0.75rem 2rem color-mix(in srgb, var(--dt-ring) 10%, transparent);
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-slot='aui_assistant-message-content'] .aui-md [data-slot='code-card'][data-streaming='true'] {
    animation: none;
  }
}

/* -------------------------------------------------------------------------- */
/* Pet egg hatch (Cmd-K → Pets → Generate)                                    */
/* The incubation wobble + reveal flash/pop give the draft→pet step a         */
/* Pokémon-style "egg is hatching" beat instead of a bare spinner.            */
/* -------------------------------------------------------------------------- */

.pet-egg {
  position: relative;
  width: 5.5rem;
  height: 7rem;
  border-radius: 50% 50% 50% 50% / 62% 62% 38% 38%;
  background:
    radial-gradient(120% 90% at 32% 26%, color-mix(in srgb, var(--ui-accent) 14%, #fff) 0%, #f4ecd8 46%, #e4d3ad 100%);
  box-shadow:
    inset -0.45rem -0.6rem 1.1rem color-mix(in srgb, #000 16%, transparent),
    inset 0.35rem 0.4rem 0.7rem color-mix(in srgb, #fff 70%, transparent),
    0 0.4rem 0.9rem color-mix(in srgb, #000 22%, transparent);
  transform-origin: 50% 88%;
  animation: pet-egg-wobble 2.4s ease-in-out infinite;
}

/* Compact egg (empty-state hero). Children are %-based so they track the size;
   only the rem box-shadow needs scaling down to stay crisp. */
.pet-egg--sm {
  width: 3.25rem;
  height: 4.1rem;
  box-shadow:
    inset -0.28rem -0.38rem 0.7rem color-mix(in srgb, #000 16%, transparent),
    inset 0.22rem 0.26rem 0.45rem color-mix(in srgb, #fff 70%, transparent),
    0 0.25rem 0.55rem color-mix(in srgb, #000 22%, transparent);
}

.pet-egg__shine {
  position: absolute;
  top: 14%;
  left: 22%;
  width: 28%;
  height: 22%;
  border-radius: 50%;
  background: color-mix(in srgb, #fff 85%, transparent);
  filter: blur(2px);
  opacity: 0.85;
}

.pet-egg__spot {
  position: absolute;
  border-radius: 50%;
  background: color-mix(in srgb, var(--ui-accent) 70%, #b89b63);
  opacity: 0.55;
}

.pet-egg__glow {
  position: absolute;
  inset: -35%;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--ui-accent) 55%, transparent) 0%, transparent 62%);
  animation: pet-egg-glow 2.4s ease-in-out infinite;
  pointer-events: none;
}

.pet-egg-shadow {
  width: 4.5rem;
  height: 0.8rem;
  border-radius: 50%;
  /* Lighter on light backgrounds (~20% less ink); dark mode keeps it grounded. */
  background: radial-gradient(circle, color-mix(in srgb, #000 var(--pet-egg-shadow-ink, 26%), transparent) 0%, transparent 72%);
  animation: pet-egg-shadow 2.4s ease-in-out infinite;
}

.dark .pet-egg-shadow {
  --pet-egg-shadow-ink: 32%;
}

/* Contact shadow sized for the compact incubator egg (roughly its footprint). */
.pet-egg-shadow--sm {
  width: 3rem;
  height: 0.6rem;
}

/* Contact shadow under the revealed pet — mirrors the floating mascot's in-app
   shadow: an ellipse at the feet, ~55% of the sprite width, sitting behind it. */
.pet-contact-shadow {
  position: absolute;
  bottom: -0.15rem;
  left: 50%;
  width: 55%;
  aspect-ratio: 100 / 28;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, color-mix(in srgb, #000 42%, transparent) 0%, transparent 70%);
  pointer-events: none;
  z-index: 0;
}

/* Hatch wiggle for the pixel egg (rocks around its base). */
.pet-wobble {
  transform-origin: 50% 85%;
  animation: pet-egg-wobble 2.4s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .pet-wobble {
    animation: none;
  }
}

@keyframes pet-egg-wobble {
  0%,
  62%,
  100% {
    transform: rotate(0deg);
  }
  8% {
    transform: rotate(-7deg);
  }
  16% {
    transform: rotate(6deg);
  }
  24% {
    transform: rotate(-5deg);
  }
  32% {
    transform: rotate(4deg);
  }
  40% {
    transform: rotate(0deg);
  }
  /* the "almost out" burst */
  70% {
    transform: rotate(-12deg);
  }
  76% {
    transform: rotate(12deg);
  }
  82% {
    transform: rotate(-9deg);
  }
  88% {
    transform: rotate(7deg);
  }
  94% {
    transform: rotate(-3deg);
  }
}

@keyframes pet-egg-glow {
  0%,
  100% {
    opacity: 0.35;
    transform: scale(0.92);
  }
  70% {
    opacity: 0.4;
  }
  84% {
    opacity: 0.85;
    transform: scale(1.08);
  }
}

@keyframes pet-egg-shadow {
  0%,
  62%,
  100% {
    transform: scaleX(1);
    opacity: 0.6;
  }
  76% {
    transform: scaleX(0.8);
    opacity: 0.45;
  }
}

.pet-reveal {
  animation: pet-reveal-pop 620ms cubic-bezier(0.22, 1.4, 0.4, 1) both;
}

@keyframes pet-reveal-pop {
  0% {
    opacity: 0;
    transform: scale(0.35) translateY(0.4rem);
  }
  60% {
    opacity: 1;
    transform: scale(1.12) translateY(0);
  }
  100% {
    transform: scale(1) translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .pet-egg,
  .pet-egg__glow,
  .pet-egg-shadow,
  .pet-reveal {
    animation: none;
  }
  .pet-reveal {
    opacity: 1;
    transform: none;
  }
}

/* Pet generation progress bar — determinate (hatch rows: done/total) or         */
/* indeterminate (drafts, which return together so a % would just snap).         */
.pet-progress {
  position: relative;
  height: 0.25rem;
  width: 100%;
  overflow: hidden;
  border-radius: 9999px;
  background: color-mix(in srgb, var(--ui-accent) 15%, transparent);
}

.pet-progress__fill {
  position: absolute;
  inset: 0 auto 0 0;
  height: 100%;
  border-radius: 9999px;
  background: var(--ui-accent);
  transition: width 320ms ease;
}

.pet-progress__indeterminate {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 40%;
  border-radius: 9999px;
  background: var(--ui-accent);
  animation: pet-progress-slide 1.15s ease-in-out infinite;
}

@keyframes pet-progress-slide {
  0% {
    left: -42%;
  }
  100% {
    left: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .pet-progress__indeterminate {
    animation: none;
    left: 0;
    width: 100%;
    opacity: 0.4;
  }
}
