{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "foundation",
  "type": "registry:style",
  "title": "Iris UI foundation",
  "description": "Iris UI's tokens (colour, surface, ink, line, radius, shadow, spacing, type) in light and dark, the Tailwind v4 theme that maps them to utilities, motion variables, keyboard focus rules, keyframes and the Inter, Geist and JetBrains Mono fonts. Requires Tailwind v4: import components/iris/styles/foundation.css after tailwindcss. strict.css (optional, imported before foundation.css) removes Tailwind's default palette, shadows and radii.",
  "categories": [
    "foundation"
  ],
  "dependencies": [
    "@fontsource-variable/geist",
    "@fontsource-variable/inter",
    "@fontsource-variable/jetbrains-mono",
    "tailwindcss"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "src/styles/foundation.css",
      "content": "/* Iris UI foundation: import once from your global stylesheet, after `@import \"tailwindcss\";`.\n * Fonts come from @fontsource-variable; tokens.css is generated from design-system/tokens.json (pnpm tokens). */\n@import \"@fontsource-variable/inter\";\n@import \"@fontsource-variable/inter/wght-italic.css\";\n@import \"@fontsource-variable/geist\";\n@import \"@fontsource-variable/jetbrains-mono\";\n@import \"./tokens.css\";\n@import \"./extras.css\";\n@import \"./theme.css\";\n",
      "type": "registry:file",
      "target": "@components/iris/styles/foundation.css"
    },
    {
      "path": "src/styles/tokens.css",
      "content": "/* Iris UI — generated from tokens.json */\n:root, [data-theme=\"light\"] {\n  --page: oklch(0.985 0.001 286.376);\n  --canvas: oklch(0.961 0.002 247.84);\n  --surface: oklch(1 0 0);\n  --inset: oklch(0.979 0.002 247.839);\n  --hover: oklch(0.97 0.002 247.839);\n  --hover-2: oklch(0.933 0.003 247.86);\n  --field: oklch(0.961 0.001 286.375);\n  --ink: oklch(0.247 0.006 258.361);\n  --ink-2: oklch(0.506 0.01 264.477);\n  --ink-3: oklch(0.695 0.009 264.505);\n  --line: oklch(0.946 0.003 264.542);\n  --line-strong: oklch(0.912 0.005 258.326);\n  --line-soft: oklch(0.966 0.002 264.542);\n  --stripe: oklch(0.405 0 0 / 0.075);\n  --stripe-bg: oklch(0.97 0 0);\n  --accent: oklch(0.626 0.205 254.947);\n  --accent-ink: oklch(0.556 0.187 255.617);\n  --accent-tint: oklch(0.96 0.019 252.878);\n  --on-accent: #ffffff;\n  --green: oklch(0.603 0.155 150.883);\n  --green-tint: oklch(0.958 0.017 159.118);\n  --orange: oklch(0.689 0.179 49.902);\n  --orange-tint: oklch(0.964 0.021 67.581);\n  --red: oklch(0.621 0.192 23.042);\n  --red-tint: oklch(0.956 0.017 17.462);\n  --tooltip-bg: oklch(0.272 0.008 264.435);\n  --tooltip-fg: oklch(0.976 0.002 247.839);\n  --tooltip-muted: oklch(0.731 0.008 260.731);\n  --tooltip-border: oklch(0.356 0.007 264.474);\n  --control-on: var(--ink);\n  --control-glyph: var(--surface);\n  --control-track: var(--line-strong);\n  --control-track-hover: oklch(86% 0 0);\n  --control-thumb: oklch(100% 0 0);\n  --control-thumb-on: oklch(100% 0 0);\n  --control-fill: var(--control-on);\n  --series-1: #1f7dcf;\n  --series-2: #7128a5;\n  --series-3: #e58f00;\n  --series-4: #009e84;\n  --gradient-from: oklch(90% .045 300);\n  --gradient-to: oklch(92% .045 65);\n  --shadow-xs: 0 0 4px 0 rgba(0, 0, 0, 0.04);\n  --shadow-sm: 0 18px 47px 0 rgba(0, 0, 0, 0.03), 0 7.5px 19px 0 rgba(0, 0, 0, 0.02), 0 4px 10.5px 0 rgba(0, 0, 0, 0.02), 0 2.3px 5.8px 0 rgba(0, 0, 0, 0.01), 0 1.2px 3.1px 0 rgba(0, 0, 0, 0.01), 0 0.5px 1.3px 0 rgba(0, 0, 0, 0.01);\n  --shadow-md: 0 17.54px 23.39px 0 rgba(0, 0, 0, 0.04), 0 9.4px 12.5px 0 rgba(0, 0, 0, 0.03), 0 5.25px 7px 0 rgba(0, 0, 0, 0.02), 0 2.79px 3.72px -2px rgba(0, 0, 0, 0.01), 0 1.16px 1.5px 0 rgba(0, 0, 0, 0.01);\n  --shadow-lg: 0 25px 50px 0 rgba(0, 0, 0, 0.05), 0 12px 24px 0 rgba(0, 0, 0, 0.04), 0 6px 12px 0 rgba(0, 0, 0, 0.03), 0 3px 6px 0 rgba(0, 0, 0, 0.02), 0 1.5px 3px 0 rgba(0, 0, 0, 0.02);\n  --shadow-hairline: 0 0 0 1px oklch(0.946 0.003 264.542);\n  --shadow-btn: 0 0 0 1px oklch(0.912 0.005 258.326), 0 0 4px 0 rgba(0, 0, 0, 0.04);\n  --shadow-card: 0 0 0 1px oklch(0.946 0.003 264.542), 0 18px 47px 0 rgba(0, 0, 0, 0.03), 0 7.5px 19px 0 rgba(0, 0, 0, 0.02), 0 4px 10.5px 0 rgba(0, 0, 0, 0.02), 0 2.3px 5.8px 0 rgba(0, 0, 0, 0.01), 0 1.2px 3.1px 0 rgba(0, 0, 0, 0.01), 0 0.5px 1.3px 0 rgba(0, 0, 0, 0.01);\n  --shadow-raised: 0 0 0 1px oklch(0.946 0.003 264.542), 0 17.54px 23.39px 0 rgba(0, 0, 0, 0.04), 0 9.4px 12.5px 0 rgba(0, 0, 0, 0.03), 0 5.25px 7px 0 rgba(0, 0, 0, 0.02), 0 2.79px 3.72px -2px rgba(0, 0, 0, 0.01), 0 1.16px 1.5px 0 rgba(0, 0, 0, 0.01);\n  --shadow-overlay: 0 0 0 1px oklch(0.946 0.003 264.542), 0 25px 50px 0 rgba(0, 0, 0, 0.05), 0 12px 24px 0 rgba(0, 0, 0, 0.04), 0 6px 12px 0 rgba(0, 0, 0, 0.03), 0 3px 6px 0 rgba(0, 0, 0, 0.02), 0 1.5px 3px 0 rgba(0, 0, 0, 0.02);\n  --shadow-inset-field: inset 0 1px 2px oklch(0 0 0 / 0.12);\n  --shadow-resting: 0 0 4px 0 rgba(0, 0, 0, 0.04);\n  --shadow-floating: 0 25px 50px 0 rgba(0, 0, 0, 0.05), 0 12px 24px 0 rgba(0, 0, 0, 0.04), 0 6px 12px 0 rgba(0, 0, 0, 0.03), 0 3px 6px 0 rgba(0, 0, 0, 0.02), 0 1.5px 3px 0 rgba(0, 0, 0, 0.02);\n  --control-thumb-shadow: 0 0 0 .5px oklch(0% 0 0 / .07), 0 1px 2px oklch(0% 0 0 / .14), 0 2px 6px oklch(0% 0 0 / .06);\n}\n[data-theme=\"dark\"] {\n  --page: oklch(0.209 0.004 264.477);\n  --canvas: oklch(0.231 0.004 264.487);\n  --surface: oklch(0.26 0.006 271.191);\n  --inset: oklch(0.243 0.004 264.492);\n  --hover: oklch(0.289 0.006 271.22);\n  --hover-2: oklch(0.318 0.007 274.747);\n  --field: oklch(0.293 0.006 271.223);\n  --ink: oklch(0.964 0.002 247.839);\n  --ink-2: oklch(0.731 0.008 260.731);\n  --ink-3: oklch(0.541 0.01 264.484);\n  --line: oklch(0.308 0.006 258.354);\n  --line-strong: oklch(0.356 0.007 264.474);\n  --line-soft: oklch(0.278 0.006 258.354);\n  --stripe: oklch(1 0 0 / 0.055);\n  --stripe-bg: oklch(0.226 0.004 264.485);\n  --accent: oklch(0.68 0.173 253.301);\n  --accent-ink: oklch(0.788 0.113 248.33);\n  --accent-tint: oklch(0.68 0.173 253.301 / 0.16);\n  --on-accent: var(--page);\n  --green: oklch(0.705 0.154 153.814);\n  --green-tint: oklch(0.705 0.154 153.814 / 0.14);\n  --orange: oklch(0.746 0.156 55.642);\n  --orange-tint: oklch(0.746 0.156 55.642 / 0.14);\n  --red: oklch(0.666 0.18 21.433);\n  --red-tint: oklch(0.666 0.18 21.433 / 0.14);\n  --tooltip-bg: oklch(0.182 0.004 264.459);\n  --tooltip-fg: oklch(0.964 0.002 247.839);\n  --tooltip-muted: oklch(0.731 0.008 260.731);\n  --tooltip-border: oklch(0.308 0.006 258.354);\n  --control-on: var(--ink);\n  --control-glyph: var(--page);\n  --control-track: var(--line-strong);\n  --control-track-hover: oklch(37% 0 0);\n  --control-thumb: oklch(97% 0 0);\n  --control-thumb-on: var(--page);\n  --control-fill: oklch(62% 0 0);\n  --series-1: #55adff;\n  --series-2: #9c37be;\n  --series-3: #e66e00;\n  --series-4: #00a861;\n  --gradient-from: oklch(38% .05 300);\n  --gradient-to: oklch(40% .045 60);\n  --shadow-hairline: 0 0 0 1px oklch(0.308 0.006 258.354);\n  --shadow-btn: 0 0 0 1px oklch(1 0 0 / 0.1), 0 1px 2px oklch(0 0 0 / 0.3);\n  --shadow-card: 0 0 0 1px oklch(1 0 0 / 0.11), 0 1px 2px oklch(0 0 0 / 0.2), 0 2px 6px oklch(0 0 0 / 0.2);\n  --shadow-raised: 0 0 0 1px oklch(1 0 0 / 0.13), 0 2px 10px oklch(0 0 0 / 0.22);\n  --shadow-overlay: 0 0 0 1px oklch(1 0 0 / 0.15), 0 8px 28px oklch(0 0 0 / 0.34);\n  --shadow-inset-field: inset 0 1px 2px oklch(0 0 0 / 0.4);\n  --shadow-resting: 0 1px 2px oklch(0 0 0 / 0.3);\n  --shadow-floating: 0 8px 28px oklch(0 0 0 / 0.34);\n  --control-thumb-shadow: 0 0 0 .5px oklch(0% 0 0 / .3), 0 1px 2px oklch(0% 0 0 / .35), 0 2px 6px oklch(0% 0 0 / .2);\n}\n:root {\n  --space-1: .25rem;\n  --space-2: .5rem;\n  --space-3: .75rem;\n  --space-4: 1rem;\n  --space-5: 1.25rem;\n  --space-6: 1.5rem;\n  --space-8: 2rem;\n  --space-10: 2.5rem;\n  --space-12: 3rem;\n  --space-16: 4rem;\n  --space-20: 5rem;\n  --space-24: 6rem;\n  --radius-chip: 6px;\n  --radius-control: 8px;\n  --radius-button: 9999px;\n  --radius-card: 10px;\n  --radius-window: 14px;\n  --radius-panel: 10px;\n  --radius-surface: 14px;\n  --radius-pill: 9999px;\n  --text-xs: .75rem;\n  --text-sm: .875rem;\n  --text-base: 1rem;\n  --text-lg: 1.125rem;\n  --text-xl: 1.375rem;\n  --text-2xl: 1.75rem;\n  --text-3xl: 2.25rem;\n  --text-4xl: 3.25rem;\n  --text-5xl: 4.5rem;\n  --leading-display: 1.1;\n  --leading-body: 1.4;\n  --tracking-display: -.03em;\n  --tracking-body: -.01em;\n  --control-height-sm: 2rem;\n  --control-height-md: 2.25rem;\n  --control-height-lg: 2.5rem;\n  --font-body: \"Inter Variable\", Inter, ui-sans-serif, system-ui, sans-serif;\n  --font-display: \"Geist Variable\", Geist, \"Inter Variable\", ui-sans-serif, system-ui, sans-serif;\n  --font-code: \"JetBrains Mono Variable\", \"JetBrains Mono\", ui-monospace, \"SF Mono\", monospace;\n}\n.display-hero { font-family: var(--font-display); font-size: 72px; line-height: 1.1; font-weight: 500; letter-spacing: -0.03em; }\n.display-1 { font-family: var(--font-display); font-size: 52px; line-height: 1.1; font-weight: 500; letter-spacing: -0.03em; }\n.display-2 { font-family: var(--font-display); font-size: 36px; line-height: 1.1; font-weight: 500; letter-spacing: -0.03em; }\n.display-3 { font-family: var(--font-display); font-size: 28px; line-height: 1.1; font-weight: 500; letter-spacing: -0.03em; }\n.display-4 { font-family: var(--font-display); font-size: 22px; line-height: 1.1; font-weight: 500; letter-spacing: -0.03em; }\n.title { font-family: var(--font-body); font-size: 21px; line-height: 1.375; font-weight: 600; letter-spacing: -0.02em; }\n.heading { font-family: var(--font-body); font-size: 17px; line-height: 1.4; font-weight: 600; letter-spacing: -0.01em; }\n.body-lg { font-family: var(--font-body); font-size: 16px; line-height: 1.4; font-weight: 400; letter-spacing: -0.01em; }\n.body { font-family: var(--font-body); font-size: 14px; line-height: 1.5; font-weight: 400; letter-spacing: -0.01em; }\n.label { font-family: var(--font-body); font-size: 13px; line-height: 1.4; font-weight: 500; letter-spacing: -0.01em; }\n.label-sm { font-family: var(--font-body); font-size: 12.5px; line-height: 1.4; font-weight: 500; letter-spacing: -0.01em; }\n.small { font-family: var(--font-body); font-size: 12px; line-height: 1.5; font-weight: 400; letter-spacing: -0.01em; }\n.caption { font-family: var(--font-body); font-size: 11.5px; line-height: 1.4; font-weight: 500; letter-spacing: -0.005em; }\n.micro { font-family: var(--font-body); font-size: 10.5px; line-height: 1.3; font-weight: 500; letter-spacing: 0; }\n.code { font-family: var(--font-code); font-size: 12.5px; line-height: 20px; font-weight: 400; letter-spacing: 0; }\n.code-sm { font-family: var(--font-code); font-size: 12px; line-height: 18px; font-weight: 400; letter-spacing: 0; }\n",
      "type": "registry:file",
      "target": "@components/iris/styles/tokens.css"
    },
    {
      "path": "src/styles/extras.css",
      "content": "/* ── Iris UI foundation extras ─────────────────────────────\n * What tokens.json cannot hold: motion, color-mix() and gradient values, and the\n * keyboard-focus rules. Colours, shadows, radii, spacing and type live in tokens.json. */\n:root {\n  color-scheme: light;\n}\n[data-theme=\"dark\"] {\n  color-scheme: dark;\n}\n:root {\n  /* motion: easings and durations (the JS presets live in src/lib/motion-tokens.ts) */\n  --ease-enter: cubic-bezier(0.16, 1, 0.3, 1);\n  --ease-standard: cubic-bezier(0.22, 1, 0.36, 1);\n  --ease-exit: cubic-bezier(0.7, 0, 0.84, 0);\n  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);\n  --ease-spring: linear(\n    0,\n    0.0213,\n    0.0739,\n    0.1443,\n    0.2235,\n    0.305,\n    0.3849,\n    0.4606,\n    0.5305,\n    0.594,\n    0.6508,\n    0.7011,\n    0.7452,\n    0.7836,\n    0.8168,\n    0.8454,\n    0.8699,\n    0.8907,\n    0.9084,\n    0.9234,\n    0.9361,\n    0.9467,\n    0.9557,\n    0.9632,\n    0.9694,\n    0.9747,\n    0.979,\n    0.9826,\n    0.9857,\n    0.9882,\n    0.9902,\n    0.992,\n    0.9934,\n    0.9946,\n    0.9955,\n    0.9963,\n    1\n  );\n  --duration-instant: 120ms;\n  --duration-fast: 160ms;\n  --duration-standard: 240ms;\n  --duration-considered: 480ms;\n  --duration-spring: 580ms;\n  /* strong easing curves for links and reveals */\n  --ease-out-strong: cubic-bezier(0.23, 1, 0.32, 1);\n  --ease-in-out-strong: cubic-bezier(0.77, 0, 0.175, 1);\n  --ease-link: cubic-bezier(0.16, 1, 0.3, 1);\n  /* derived colours */\n  --grid-line: color-mix(in srgb, var(--line) 78%, transparent);\n  --control-on-subtle: color-mix(in oklab, var(--control-on) 10%, transparent);\n  --focus-ring: transparent;\n  --focus-outline: var(--accent);\n  --gradient: linear-gradient(100deg, var(--gradient-from), var(--gradient-to));\n  --gradient-foreground: var(--ink);\n  --gradient-soft: linear-gradient(135deg, oklch(97.5% 0.016 300), oklch(98% 0.016 65));\n  --gradient-line: linear-gradient(100deg, oklch(83% 0.06 300), oklch(86% 0.06 65));\n  --gradient-ink: linear-gradient(100deg, oklch(47% 0.1 300), oklch(50% 0.09 55));\n}\n[data-theme=\"dark\"] {\n  --gradient-soft: linear-gradient(135deg, oklch(23.5% 0.016 300), oklch(24% 0.014 65));\n  --gradient-line: linear-gradient(100deg, oklch(48% 0.06 300), oklch(52% 0.055 65));\n  --gradient-ink: linear-gradient(100deg, oklch(82% 0.07 300), oklch(86% 0.065 70));\n}\n/* Focus: pointer focus draws no ring; keyboard focus (:focus-visible) draws a 2px solid `accent` outline, offset 2px\n   (3.6:1 on surface in light, 5.4:1 in dark). Text fields, menu items/options and tabindex=-1 targets show focus their own way. */\n:focus:not(:focus-visible),\n:is(\n  input:not(\n    [type=\"button\"],\n    [type=\"checkbox\"],\n    [type=\"color\"],\n    [type=\"file\"],\n    [type=\"image\"],\n    [type=\"radio\"],\n    [type=\"range\"],\n    [type=\"reset\"],\n    [type=\"submit\"]\n  ),\n  textarea,\n  [contenteditable]:not([contenteditable=\"false\"]),\n  [role=\"menuitem\"],\n  [role=\"menuitemcheckbox\"],\n  [role=\"menuitemradio\"],\n  [role=\"option\"],\n  [tabindex=\"-1\"]\n):focus {\n  outline: none !important;\n}\n:focus-visible:not(\n  input:not(\n    [type=\"button\"],\n    [type=\"checkbox\"],\n    [type=\"color\"],\n    [type=\"file\"],\n    [type=\"image\"],\n    [type=\"radio\"],\n    [type=\"range\"],\n    [type=\"reset\"],\n    [type=\"submit\"]\n  ),\n  textarea,\n  [contenteditable]:not([contenteditable=\"false\"]),\n  [role=\"menuitem\"],\n  [role=\"menuitemcheckbox\"],\n  [role=\"menuitemradio\"],\n  [role=\"option\"],\n  [tabindex=\"-1\"]\n) {\n  outline: var(--focus-outline-width, 2px) solid var(--focus-outline) !important;\n  outline-offset: var(--focus-outline-offset, 2px) !important;\n}\n\n/* Placeholder art: the flat demo pictures (data: SVGs whose root has class \"iris-placeholder\") are drawn in light\n   neutrals. An <img> cannot read the theme, so in dark they are inverted with their hues kept, which turns them into\n   dark neutrals with the same blue tints. Real photos carry no marker and are never touched. */\n[data-theme=\"dark\"] img[src*=\"iris-placeholder\"] {\n  filter: invert(0.88) hue-rotate(180deg);\n}\n",
      "type": "registry:file",
      "target": "@components/iris/styles/extras.css"
    },
    {
      "path": "src/styles/theme.css",
      "content": "/* Iris UI Tailwind theme: maps the tokens in tokens.css onto Tailwind v4's namespaces, so every component is styled\n * with utilities such as bg-surface, text-ink-2, border-line, rounded-control, shadow-card, ease-standard and\n * duration-fast. Values (and their dark variants) live in tokens.css; nothing here hard-codes a colour. */\n\n@custom-variant dark (&:where([data-theme=\"dark\"], [data-theme=\"dark\"] *));\n\n@theme inline {\n  /* colour */\n  --color-white: #fff;\n  --color-black: #000;\n  --color-page: var(--page);\n  --color-canvas: var(--canvas);\n  --color-surface: var(--surface);\n  --color-inset: var(--inset);\n  --color-hover: var(--hover);\n  --color-hover-2: var(--hover-2);\n  --color-field: var(--field);\n  --color-ink: var(--ink);\n  --color-ink-2: var(--ink-2);\n  --color-ink-3: var(--ink-3);\n  --color-line: var(--line);\n  --color-line-strong: var(--line-strong);\n  --color-line-soft: var(--line-soft);\n  --color-accent: var(--accent);\n  --color-accent-ink: var(--accent-ink);\n  --color-accent-tint: var(--accent-tint);\n  --color-on-accent: var(--on-accent);\n  --color-green: var(--green);\n  --color-green-tint: var(--green-tint);\n  --color-orange: var(--orange);\n  --color-orange-tint: var(--orange-tint);\n  --color-red: var(--red);\n  --color-red-tint: var(--red-tint);\n  --color-tooltip-bg: var(--tooltip-bg);\n  --color-tooltip-fg: var(--tooltip-fg);\n  --color-tooltip-muted: var(--tooltip-muted);\n  --color-tooltip-border: var(--tooltip-border);\n  --color-control-on: var(--control-on);\n  --color-control-glyph: var(--control-glyph);\n  --color-control-track: var(--control-track);\n  --color-control-track-hover: var(--control-track-hover);\n  --color-control-thumb: var(--control-thumb);\n  --color-control-thumb-on: var(--control-thumb-on);\n  --color-control-fill: var(--control-fill);\n  --color-series-1: var(--series-1);\n  --color-series-2: var(--series-2);\n  --color-series-3: var(--series-3);\n  --color-series-4: var(--series-4);\n  --color-stripe: var(--stripe);\n  --color-stripe-bg: var(--stripe-bg);\n\n  /* shadow: rings are baked into the stacks */\n  --shadow-hairline: var(--shadow-hairline);\n  --shadow-btn: var(--shadow-btn);\n  --shadow-inset-field: var(--shadow-inset-field);\n  --shadow-card: var(--shadow-card);\n  --shadow-raised: var(--shadow-raised);\n  --shadow-overlay: var(--shadow-overlay);\n  --shadow-resting: var(--shadow-resting);\n  --shadow-floating: var(--shadow-floating);\n  --shadow-thumb: var(--control-thumb-shadow);\n\n  /* radius: chip 6 · control 8 · card/panel 10 · window/surface 14 · button (pill) · full */\n  --radius-chip: var(--radius-chip);\n  --radius-control: var(--radius-control);\n  --radius-button: var(--radius-button);\n  --radius-card: var(--radius-card);\n  --radius-panel: var(--radius-panel);\n  --radius-window: var(--radius-window);\n  --radius-surface: var(--radius-surface);\n  --radius-full: 9999px;\n\n  /* type */\n  --font-sans: var(--font-body);\n  --font-body: var(--font-body);\n  --font-display: var(--font-display);\n  --font-mono: var(--font-code);\n  --font-code: var(--font-code);\n  --text-xs: var(--text-xs);\n  --text-sm: var(--text-sm);\n  --text-base: var(--text-base);\n  --text-lg: var(--text-lg);\n  --text-xl: var(--text-xl);\n  --text-2xl: var(--text-2xl);\n  --text-3xl: var(--text-3xl);\n  --text-4xl: var(--text-4xl);\n  --text-5xl: var(--text-5xl);\n  --leading-body: var(--leading-body);\n  --leading-display: var(--leading-display);\n  --tracking-body: var(--tracking-body);\n  --tracking-display: var(--tracking-display);\n\n  /* control heights: h-control-sm 32 · h-control-md 36 · h-control-lg 40 */\n  --spacing-control-sm: var(--control-height-sm);\n  --spacing-control-md: var(--control-height-md);\n  --spacing-control-lg: var(--control-height-lg);\n\n  /* easing (durations are utilities below) */\n  --ease-enter: var(--ease-enter);\n  --ease-standard: var(--ease-standard);\n  --ease-exit: var(--ease-exit);\n  --ease-spring: var(--ease-spring);\n  --ease-out-strong: var(--ease-out-strong);\n  --ease-in-out-strong: var(--ease-in-out-strong);\n  --ease-link: var(--ease-link);\n}\n\n/* durations: instant 120 · fast 160 · standard 240 · considered 480 · spring 580 */\n@utility duration-instant {\n  transition-duration: var(--duration-instant);\n}\n@utility duration-fast {\n  transition-duration: var(--duration-fast);\n}\n@utility duration-standard {\n  transition-duration: var(--duration-standard);\n}\n@utility duration-considered {\n  transition-duration: var(--duration-considered);\n}\n@utility duration-spring {\n  transition-duration: var(--duration-spring);\n}\n\n/* component keyframes, one section per component */\n@import \"./animations.css\";\n\n/* ── base ─────────────────────────────────────────────── */\n\nhtml {\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n  text-rendering: optimizeLegibility;\n}\n\n.iris-stripes {\n  background-color: var(--stripe-bg);\n  background-image: repeating-linear-gradient(\n    -45deg,\n    transparent 0,\n    transparent 7px,\n    var(--stripe) 7px,\n    var(--stripe) 8px\n  );\n  /* Pin the stripe pattern to the viewport so it stays put on scroll. */\n  background-attachment: fixed;\n}\n\nbody {\n  background-color: var(--page);\n  color: var(--ink);\n  font-family: var(--font-body);\n  font-feature-settings: \"cv11\", \"ss01\";\n  font-size: 14px;\n  letter-spacing: -0.01em;\n  line-height: 1.5;\n}\n\n::selection {\n  background: var(--accent-tint);\n  color: var(--ink);\n}\n\n/* ── interface hygiene (interfaces.dev cheat sheet) ────── */\n\n/* headings balance; descriptions avoid orphans (skip long-form — we have none) */\nh1,\nh2,\nh3,\nh4 {\n  text-wrap: balance;\n}\n\np {\n  text-wrap: pretty;\n}\n\n/* underlines clear descenders */\na {\n  text-underline-position: from-font;\n  text-decoration-skip-ink: auto;\n}\n\n/* theme switches swap every token at once — freeze transitions so the flip\n * is one clean repaint instead of hundreds of mismatched color fades */\n.theme-switching *,\n.theme-switching *::before,\n.theme-switching *::after {\n  transition: none !important;\n}\n\n/* Tailwind v4 resets buttons to cursor:default — anything\n * clickable must invite the click */\nbutton:not(:disabled),\n[role=\"button\"]:not([aria-disabled=\"true\"]),\nlabel:has(input),\na {\n  cursor: pointer;\n}\n\n/* Focus rings: see extras.css (keyboard-only, in the accent). */\n\ninput:focus-visible,\ntextarea:focus-visible,\nselect:focus-visible,\n[contenteditable]:focus-visible {\n  outline: none;\n}\n\n/* reduced motion: every animation and transition collapses to its end state */\n@media (prefers-reduced-motion: reduce) {\n  *,\n  *::before,\n  *::after {\n    animation-duration: 0.01ms !important;\n    animation-iteration-count: 1 !important;\n    transition-duration: 0.01ms !important;\n  }\n}\n",
      "type": "registry:file",
      "target": "@components/iris/styles/theme.css"
    },
    {
      "path": "src/styles/animations.css",
      "content": "/* Component keyframes. Each component that needs CSS keyframes owns one section, named after its registry item, holding\n * its @keyframes and the matching --animate-* entries (used as animate-<name>). Prefer motion/react for anything\n * driven by state; keep CSS keyframes for loops and pure decoration. Every animation needs a reduced-motion path. */\n\n/* ── button-group ── */\n/* No-op: Radix unmounts the menu when this ends, so it times the exit while the transition does the visual work. */\n@keyframes button-group-menu-exit {\n  to {\n    --menu-exit: 1;\n  }\n}\n@theme {\n  --animate-button-group-menu-exit: button-group-menu-exit 130ms linear both;\n}\n\n/* ── context-menu ── */\n/* Rows drop in 2px one after another; --i on each row staggers them, capped after the fifth. Inline, so --i resolves on the row. */\n@keyframes context-menu-item-in {\n  from {\n    opacity: 0;\n    transform: translateY(-2px);\n  }\n}\n@theme inline {\n  --animate-context-menu-item-in: context-menu-item-in var(--duration-standard) var(--ease-enter)\n    calc(min(var(--i, 0), 4) * 35ms) both;\n}\n\n/* ── dropdown-menu ── */\n/* No-op: Radix unmounts the menu when this ends, so it times the exit while the transition does the visual work. */\n@keyframes dropdown-menu-exit {\n  to {\n    --menu-exit: 1;\n  }\n}\n@theme {\n  --animate-dropdown-menu-exit: dropdown-menu-exit 130ms linear both;\n}\n\n/* ── expanding-button-group ── */\n/* A busy action's icon breathes until the work settles; reduced motion holds it dimmed instead. */\n@keyframes expanding-button-group-busy {\n  50% {\n    opacity: 0.45;\n  }\n}\n@theme {\n  --animate-expanding-button-group-busy: expanding-button-group-busy 1.1s var(--ease-in-out) infinite;\n}\n\n/* ── countdown ── */\n/* The finished mark's ring: it swells and fades from the dot, then rests before the next beat. */\n@keyframes countdown-pulse {\n  from {\n    opacity: 0.5;\n    transform: scale(1);\n  }\n  70%,\n  to {\n    opacity: 0;\n    transform: scale(2.6);\n  }\n}\n@theme {\n  --animate-countdown-pulse: countdown-pulse 2s var(--ease-standard) infinite;\n}\n\n/* ── line-chart ── */\n/* While loading, the series (or a skeleton band where the lines will be) breathes; reduced motion holds it still. */\n@keyframes line-chart-breathe {\n  from {\n    opacity: 0.22;\n  }\n  to {\n    opacity: 0.45;\n  }\n}\n@theme {\n  --animate-line-chart-breathe: line-chart-breathe 1.4s var(--ease-in-out) infinite alternate;\n}\n\n/* ── agent-screen ── */\n/* The recording dot in the viewer's title bar breathes while the timer runs. */\n@keyframes agent-screen-pulse {\n  0%,\n  100% {\n    opacity: 0.35;\n    transform: scale(0.8);\n  }\n  50% {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n@theme {\n  --animate-agent-screen-pulse: agent-screen-pulse 1.1s ease-in-out infinite;\n}\n\n/* ── loading-state ── */\n/* One grid cell brightens to a plateau and dims again; each cell sets its own duration and delay inline, so the\n * loader's wavefront comes from the stagger. Reduced motion stops it on the dim frame. */\n@keyframes loading-state-pixel-on {\n  0%,\n  100% {\n    opacity: 0.15;\n  }\n  18%,\n  42% {\n    opacity: 1;\n  }\n  62% {\n    opacity: 0.15;\n  }\n}\n@theme {\n  --animate-loading-state-pixel-on: loading-state-pixel-on 650ms ease-in-out infinite;\n}\n\n/* ── text-reveal ── */\n/* Three tracks per word: the rise settles longest, the fade finishes first, and the blur clears between them. Backwards fill holds the\n * hidden start through each word's --reveal-delay, then lets go, so resting words keep no transform or filter layer. Reduced motion only fades. */\n@keyframes text-reveal-rise {\n  from {\n    transform: translateY(0.62em);\n  }\n}\n@keyframes text-reveal-fade {\n  from {\n    opacity: 0;\n  }\n}\n@keyframes text-reveal-focus {\n  from {\n    filter: blur(var(--reveal-blur, 4px));\n  }\n}\n@theme {\n  --animate-text-reveal-word:\n    text-reveal-rise 0.76s var(--ease-enter) var(--reveal-delay, 0s) backwards,\n    text-reveal-fade 0.44s var(--ease-standard) var(--reveal-delay, 0s) backwards,\n    text-reveal-focus 0.58s var(--ease-enter) var(--reveal-delay, 0s) backwards;\n  --animate-text-reveal-still: text-reveal-fade var(--duration-fast) var(--ease-standard) backwards;\n}\n\n/* ── floating-button-group ── */\n/* No-op: Radix unmounts the side tooltip when this ends, so it times the exit while the transition does the visual work. */\n@keyframes floating-button-group-tip-exit {\n  to {\n    --side-tip-exit: 1;\n  }\n}\n@theme {\n  --animate-floating-button-group-tip-exit: floating-button-group-tip-exit 110ms linear both;\n}\n\n/* ── notification-center ── */\n/* The panel grows out of the bell: it starts a few pixels toward the trigger (--panel-x/--panel-y, set per side) and leaves faster than it arrives.\n * Rows settle in with a short cascade keyed on their --index; `inline` keeps that var() resolving on each row. */\n@keyframes notification-center-panel-open {\n  from {\n    opacity: 0;\n    transform: translate(var(--panel-x), var(--panel-y)) scale(0.97);\n  }\n}\n@keyframes notification-center-panel-close {\n  to {\n    opacity: 0;\n    transform: translate(calc(var(--panel-x) / 2), calc(var(--panel-y) / 2)) scale(0.98);\n  }\n}\n@keyframes notification-center-item-in {\n  from {\n    opacity: 0;\n    transform: translateY(4px);\n  }\n}\n@theme inline {\n  --animate-notification-center-panel-open: notification-center-panel-open var(--duration-standard) var(--ease-enter)\n    both;\n  --animate-notification-center-panel-close: notification-center-panel-close var(--duration-instant)\n    var(--ease-standard) both;\n  --animate-notification-center-item-in: notification-center-item-in var(--duration-standard) var(--ease-enter)\n    calc(var(--index, 0) * 35ms) both;\n}\n\n/* ── in-view-title ── */\n/* The fallback for a server rendered title whose scripts are late: it settles every part to rest after 2.4s. */\n@keyframes in-view-title-settle {\n  to {\n    opacity: 1;\n    transform: none;\n    filter: none;\n    --wipe: 0%;\n    mask-image: none;\n  }\n}\n@theme {\n  --animate-in-view-title-settle: in-view-title-settle 0.4s var(--ease-enter) 2.4s forwards;\n}\n\n/* ── onboarding-checklist ── */\n/* The pending action's spinner; reduced motion holds it still. */\n@keyframes onboarding-checklist-spin {\n  to {\n    transform: rotate(360deg);\n  }\n}\n@theme {\n  --animate-onboarding-checklist-spin: onboarding-checklist-spin 0.7s linear infinite;\n}\n\n/* ── skeleton ── */\n/* A calm, finite pulse: each block dims a beat after the one above it (--index), then rests after about 20 seconds. */\n@keyframes skeleton-pulse {\n  0%,\n  100% {\n    opacity: 1;\n  }\n  50% {\n    opacity: 0.52;\n  }\n}\n@theme inline {\n  --animate-skeleton-pulse: skeleton-pulse 1.8s var(--ease-in-out) calc(var(--index, 0) * 90ms) 11 both;\n}\n\n/* ── split-button ── */\n/* No-op: Radix unmounts the menu when this ends, so it times the exit while the transition does the visual work. */\n@keyframes split-button-menu-exit {\n  to {\n    --menu-exit: 1;\n  }\n}\n@theme {\n  --animate-split-button-menu-exit: split-button-menu-exit 130ms linear both;\n}\n\n/* ── avatar ── */\n/* Initials that stand in for a photo that failed to load fade in; reduced motion shows them at once. */\n@keyframes avatar-fallback-in {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n@theme {\n  --animate-avatar-fallback-in: avatar-fallback-in var(--duration-standard) var(--ease-enter) both;\n}\n\n/* ── select ── */\n/* The menu grows from the trigger edge: it starts a few pixels toward the trigger (--menu-x/--menu-y, set per side) and\n * leaves faster than it arrives. The check of the chosen option pops in from a soft blur. Reduced motion only fades. */\n@keyframes select-in {\n  from {\n    opacity: 0;\n    transform: translate(var(--menu-x), var(--menu-y)) scale(0.97);\n  }\n}\n@keyframes select-out {\n  to {\n    opacity: 0;\n    transform: translate(calc(var(--menu-x) / 2), calc(var(--menu-y) / 2)) scale(0.98);\n  }\n}\n@keyframes select-indicator-in {\n  from {\n    opacity: 0;\n    transform: scale(0.6);\n    filter: blur(2px);\n  }\n}\n@keyframes select-fade-in {\n  from {\n    opacity: 0;\n  }\n}\n@keyframes select-fade-out {\n  to {\n    opacity: 0;\n  }\n}\n@theme {\n  --animate-select-in: select-in var(--duration-standard) var(--ease-enter) both;\n  --animate-select-out: select-out var(--duration-instant) var(--ease-standard) both;\n  --animate-select-indicator-in: select-indicator-in var(--duration-standard) var(--ease-enter) 40ms both;\n  --animate-select-fade-in: select-fade-in var(--duration-instant) var(--ease-standard) both;\n  --animate-select-fade-out: select-fade-out var(--duration-instant) var(--ease-standard) both;\n}\n\n/* ── popover ── */\n/* No-op: Radix unmounts the panel when this ends, so it times the exit while the transition does the visual work. */\n@keyframes popover-exit {\n  to {\n    --popover-exit: 1;\n  }\n}\n@theme {\n  --animate-popover-exit: popover-exit var(--duration-fast) linear both;\n}\n\n/* ── tooltip ── */\n/* No-op: Radix unmounts the bubble when this ends, so it times the exit while the transition does the visual work. */\n@keyframes tooltip-exit {\n  to {\n    --tooltip-exit: 1;\n  }\n}\n@theme {\n  --animate-tooltip-exit: tooltip-exit var(--duration-instant) linear both;\n}\n\n/* ── dialog ── */\n/* Used only when DialogContent sits under a bare Radix root (Motion animates the layers otherwise): the overlay fades while\n * the dialog fades in and rises 8px on a spring; closing is shorter. Reduced motion only fades, instantly. */\n@keyframes dialog-overlay-in {\n  from {\n    opacity: 0;\n  }\n}\n@keyframes dialog-overlay-out {\n  to {\n    opacity: 0;\n  }\n}\n@keyframes dialog-content-fade-in {\n  from {\n    opacity: 0;\n  }\n}\n@keyframes dialog-content-rise-in {\n  from {\n    transform: translateY(8px) scale(0.96);\n  }\n}\n@keyframes dialog-content-out {\n  to {\n    opacity: 0;\n    transform: translateY(4px) scale(0.98);\n  }\n}\n@keyframes dialog-content-fade-out {\n  to {\n    opacity: 0;\n  }\n}\n@theme {\n  --animate-dialog-overlay-in: dialog-overlay-in var(--duration-standard) var(--ease-enter) both;\n  --animate-dialog-overlay-out: dialog-overlay-out var(--duration-fast) var(--ease-standard) both;\n  --animate-dialog-content-in:\n    dialog-content-fade-in var(--duration-fast) var(--ease-enter) both,\n    dialog-content-rise-in var(--duration-spring) var(--ease-spring) both;\n  --animate-dialog-content-out: dialog-content-out var(--duration-fast) var(--ease-standard) both;\n  --animate-dialog-fade-in: dialog-overlay-in var(--duration-instant) var(--ease-standard) both;\n  --animate-dialog-overlay-fade-out: dialog-overlay-out var(--duration-instant) var(--ease-standard) both;\n  --animate-dialog-content-fade-out: dialog-content-fade-out var(--duration-instant) var(--ease-standard) both;\n}\n\n/* ── drawer ── */\n/* Used only when DrawerContent sits under a bare Radix root (Motion springs the panel otherwise). The panel slides from\n * --drawer-from (set per side) on a critically damped curve that never overshoots its edge; on the way out the late fade\n * lets the floating shadow leave with the panel instead of popping away at unmount. Reduced motion only fades. */\n@keyframes drawer-overlay-in {\n  from {\n    opacity: 0;\n  }\n}\n@keyframes drawer-overlay-out {\n  to {\n    opacity: 0;\n  }\n}\n@keyframes drawer-in {\n  from {\n    transform: var(--drawer-from);\n  }\n}\n@keyframes drawer-out {\n  65% {\n    opacity: 1;\n  }\n  to {\n    opacity: 0;\n    transform: var(--drawer-from);\n  }\n}\n@keyframes drawer-fade-in {\n  from {\n    opacity: 0;\n  }\n}\n@keyframes drawer-fade-out {\n  to {\n    opacity: 0;\n  }\n}\n@theme {\n  --animate-drawer-overlay-in: drawer-overlay-in var(--duration-standard) var(--ease-enter) both;\n  --animate-drawer-overlay-out: drawer-overlay-out var(--duration-fast) var(--ease-standard) both;\n  --animate-drawer-in: drawer-in var(--duration-considered) cubic-bezier(0.32, 0.72, 0, 1) both;\n  --animate-drawer-out: drawer-out var(--duration-standard) var(--ease-standard) both;\n  --animate-drawer-overlay-fade-in: drawer-overlay-in var(--duration-instant) linear both;\n  --animate-drawer-overlay-fade-out: drawer-overlay-out 100ms linear both;\n  --animate-drawer-fade-in: drawer-fade-in var(--duration-instant) linear both;\n  --animate-drawer-fade-out: drawer-fade-out 100ms linear both;\n}\n\n/* ── toast-stack ── */\n/* The loading spinner turns only while something is loading; the icon swap is its stop. */\n@keyframes toast-stack-spin {\n  to {\n    rotate: 360deg;\n  }\n}\n@theme {\n  --animate-toast-stack-spin: toast-stack-spin 0.8s linear infinite;\n}\n\n/* ── swipe-actions ── */\n/* The row menu fades in while it rises from its trigger, its items follow one after another (staggered by --i), and it leaves\n   faster than it arrives. Reduced motion keeps only the fades. Inline, so --i resolves on each item. */\n@keyframes swipe-actions-menu-fade-in {\n  from {\n    opacity: 0;\n  }\n}\n@keyframes swipe-actions-menu-rise-in {\n  from {\n    transform: translate(var(--menu-x), var(--menu-y)) scale(0.97);\n  }\n}\n@keyframes swipe-actions-menu-out {\n  to {\n    opacity: 0;\n    transform: translate(calc(var(--menu-x) * 0.5), calc(var(--menu-y) * 0.5)) scale(0.985);\n  }\n}\n@keyframes swipe-actions-menu-item-in {\n  from {\n    opacity: 0;\n    transform: translate(calc(var(--menu-x) * 0.4), calc(var(--menu-y) * 0.4));\n  }\n}\n@keyframes swipe-actions-menu-fade-out {\n  to {\n    opacity: 0;\n  }\n}\n@theme inline {\n  --animate-swipe-actions-menu-in:\n    swipe-actions-menu-fade-in var(--duration-fast) var(--ease-enter) both,\n    swipe-actions-menu-rise-in var(--duration-spring) var(--ease-spring) both;\n  --animate-swipe-actions-menu-out: swipe-actions-menu-out var(--duration-instant) var(--ease-standard) both;\n  --animate-swipe-actions-menu-item-in: swipe-actions-menu-item-in var(--duration-standard) var(--ease-enter)\n    calc(min(var(--i, 0), 4) * 35ms) both;\n  --animate-swipe-actions-menu-fade-in: swipe-actions-menu-fade-in var(--duration-instant) linear both;\n  --animate-swipe-actions-menu-fade-out: swipe-actions-menu-fade-out var(--duration-instant) linear both;\n}\n\n/* ── ridgeline ── */\n/* A new value-axis tick fades in where it lands; reduced motion shows it at once. */\n@keyframes ridgeline-tick-in {\n  from {\n    opacity: 0;\n  }\n}\n@theme {\n  --animate-ridgeline-tick-in: ridgeline-tick-in var(--duration-standard) var(--ease-standard);\n}\n\n/* ── logo-marquee ── */\n/* The track holds two copies of the list, so moving it by half its width loops without a seam. Reduced motion stops it. */\n@keyframes logo-marquee-travel {\n  to {\n    transform: translateX(-50%);\n  }\n}\n@theme {\n  --animate-logo-marquee-travel: logo-marquee-travel 39s linear infinite;\n}\n\n/* ── user-menu ── */\n/* The sign-out spinner; reduced motion slows it rather than stopping it, so progress still reads. */\n@keyframes user-menu-spin {\n  to {\n    transform: rotate(360deg);\n  }\n}\n@theme {\n  --animate-user-menu-spin: user-menu-spin 0.8s linear infinite;\n}\n\n/* ── password-field ── */\n/* Switching between dots and characters resolves in place; two names with the same frames let a toggle restart it. */\n@keyframes password-field-resolve-shown {\n  from {\n    opacity: 0.35;\n    filter: blur(2px);\n  }\n}\n@keyframes password-field-resolve-hidden {\n  from {\n    opacity: 0.35;\n    filter: blur(2px);\n  }\n}\n@theme {\n  --animate-password-field-resolve-shown: password-field-resolve-shown var(--duration-standard) var(--ease-enter);\n  --animate-password-field-resolve-hidden: password-field-resolve-hidden var(--duration-standard) var(--ease-enter);\n}\n\n/* ── password-strength ── */\n/* Dots and characters resolve into each other; two names with the same frames let a toggle restart it. */\n@keyframes password-strength-resolve-shown {\n  from {\n    opacity: 0.35;\n    filter: blur(2px);\n  }\n}\n@keyframes password-strength-resolve-hidden {\n  from {\n    opacity: 0.35;\n    filter: blur(2px);\n  }\n}\n@theme {\n  --animate-password-strength-resolve-shown: password-strength-resolve-shown var(--duration-standard) var(--ease-enter);\n  --animate-password-strength-resolve-hidden: password-strength-resolve-hidden var(--duration-standard)\n    var(--ease-enter);\n}\n\n/* ── timeline ── */\n/* The scrolling feed's bottom feather (mask height) transitions as more updates wait below; a custom property only\n * animates once it is registered with a type. */\n@property --timeline-feather {\n  syntax: \"<length>\";\n  inherits: false;\n  initial-value: 0px;\n}\n\n/* ── empty-state ── */\n/* The icon settles in once when the state first appears; reduced motion shows it at rest. */\n@keyframes empty-state-icon {\n  from {\n    opacity: 0;\n    transform: scale(0.92);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n@theme {\n  --animate-empty-state-icon: empty-state-icon var(--duration-considered) var(--ease-enter) both;\n}\n\n/* ── file-dropzone ── */\n/* A file over the target makes it breathe, slowly, while it waits for the drop. Reduced motion holds it still. */\n@keyframes file-dropzone-breathe {\n  0%,\n  100% {\n    transform: scale(1);\n  }\n  50% {\n    transform: scale(1.012);\n  }\n}\n@theme {\n  --animate-file-dropzone-breathe: file-dropzone-breathe 2.2s var(--ease-in-out) infinite;\n}\n\n/* ── inline-edit ── */\n/* The saving spinner; reduced motion holds it still as a ring with a gap. */\n@keyframes inline-edit-spin {\n  to {\n    transform: rotate(360deg);\n  }\n}\n@theme {\n  --animate-inline-edit-spin: inline-edit-spin 0.7s linear infinite;\n}\n\n/* ── shortcut-recorder ── */\n/* The recording light breathes while the recorder listens; reduced motion keeps it steady. */\n@keyframes shortcut-recorder-breathe {\n  50% {\n    opacity: 0.35;\n  }\n}\n@theme {\n  --animate-shortcut-recorder-breathe: shortcut-recorder-breathe 1.4s var(--ease-in-out) infinite;\n}\n\n/* ── shared ── */\n/* Generic keyframes still referenced by name from other items' inline styles and arbitrary animate-[…] values\n * (agent-screen, approval-card, chat-panel, context-cards, diff-table, fine-tune-card, flowchart, loading-state,\n * action-button, button, confirm-morph, hero-relay). New code should use an item section instead. */\n@keyframes fade-in {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n@keyframes fade-up {\n  from {\n    opacity: 0;\n    transform: translateY(8px);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n@keyframes pop-in {\n  from {\n    opacity: 0;\n    transform: scale(0.95);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n@keyframes spin {\n  to {\n    transform: rotate(360deg);\n  }\n}\n@keyframes shimmer-text {\n  from {\n    background-position: 150% center;\n  }\n  to {\n    background-position: -50% center;\n  }\n}\n\n/* ── prompt-bar ── */\n/* Menus and attachment chips pop in from 95 %; the dictation bars bounce while listening, each offset by an inline delay. */\n@keyframes prompt-bar-pop-in {\n  from {\n    opacity: 0;\n    transform: scale(0.95);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n@keyframes prompt-bar-eq-bounce {\n  0%,\n  100% {\n    transform: scaleY(0.35);\n  }\n  50% {\n    transform: scaleY(1);\n  }\n}\n@theme {\n  --animate-prompt-bar-menu-in: prompt-bar-pop-in 180ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-prompt-bar-chip-in: prompt-bar-pop-in 200ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-prompt-bar-eq: prompt-bar-eq-bounce 900ms ease-in-out infinite;\n}\n\n/* ── recommendation-card ── */\n/* The recommendation text fades in each time a different option is promoted. */\n@keyframes recommendation-card-fade-in {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n@theme {\n  --animate-recommendation-card-body-in: recommendation-card-fade-in 180ms ease-out both;\n}\n\n/* ── records-table ── */\n/* Calculating cells pulse; popovers and pickers pop in from 95 %; the advanced settings rise 8px into place. */\n@keyframes records-table-pulse {\n  0%,\n  100% {\n    opacity: 0.35;\n    transform: scale(0.8);\n  }\n  50% {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n@keyframes records-table-pop-in {\n  from {\n    opacity: 0;\n    transform: scale(0.95);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n@keyframes records-table-fade-up {\n  from {\n    opacity: 0;\n    transform: translateY(8px);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n@theme {\n  --animate-records-table-pulse: records-table-pulse 1.1s ease-in-out infinite;\n  --animate-records-table-picker-in: records-table-pop-in 140ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-records-table-popover-in: records-table-pop-in 160ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-records-table-settings-in: records-table-fade-up 160ms cubic-bezier(0.23, 1, 0.32, 1) both;\n}\n\n/* ── search-list ── */\n/* The clear button, results and empty state fade in as the query changes. */\n@keyframes search-list-fade-in {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n@theme {\n  --animate-search-list-clear-in: search-list-fade-in 150ms ease-out both;\n  --animate-search-list-row-in: search-list-fade-in 200ms ease-out both;\n  --animate-search-list-empty-in: search-list-fade-in 250ms ease-out both;\n}\n\n/* ── selection-actions ── */\n/* The bar pops in under the selection; the busy spinner turns while an edit runs. */\n@keyframes selection-actions-pop-in {\n  from {\n    opacity: 0;\n    transform: scale(0.95);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n@keyframes selection-actions-spin {\n  to {\n    transform: rotate(360deg);\n  }\n}\n@theme {\n  --animate-selection-actions-bar-in: selection-actions-pop-in 220ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-selection-actions-spin: selection-actions-spin 700ms linear infinite;\n}\n\n/* ── sidebar-nav ── */\n/* The workspace menu pops in below its trigger. */\n@keyframes sidebar-nav-pop-in {\n  from {\n    opacity: 0;\n    transform: scale(0.95);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n@theme {\n  --animate-sidebar-nav-menu-in: sidebar-nav-pop-in 180ms cubic-bezier(0.23, 1, 0.32, 1) both;\n}\n\n/* ── streaming-text ── */\n/* Citation chips pop in, the streaming caret fades in, and follow-ups rise in one after another (inline delay). */\n@keyframes streaming-text-pop-in {\n  from {\n    opacity: 0;\n    transform: scale(0.95);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n@keyframes streaming-text-fade-in {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n@keyframes streaming-text-fade-up {\n  from {\n    opacity: 0;\n    transform: translateY(8px);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n@theme {\n  --animate-streaming-text-cite-in: streaming-text-pop-in 250ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-streaming-text-caret-in: streaming-text-fade-in 150ms ease-out both;\n  --animate-streaming-text-follow-up-in: streaming-text-fade-up 350ms cubic-bezier(0.23, 1, 0.32, 1) both;\n}\n\n/* ── task-rows ── */\n/* Rows and detail lines rise in staggered (inline delay); badges pop, pills fade, the active ring and retry glyph turn. */\n@keyframes task-rows-fade-up {\n  from {\n    opacity: 0;\n    transform: translateY(8px);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n@keyframes task-rows-fade-in {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n@keyframes task-rows-pop-in {\n  from {\n    opacity: 0;\n    transform: scale(0.95);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n@keyframes task-rows-spin {\n  to {\n    transform: rotate(360deg);\n  }\n}\n@theme {\n  --animate-task-rows-row-in: task-rows-fade-up 450ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-task-rows-detail-in: task-rows-fade-up 300ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-task-rows-pill-in: task-rows-fade-in 200ms ease-out both;\n  --animate-task-rows-badge-in: task-rows-pop-in 300ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-task-rows-ring: task-rows-spin 1.1s linear infinite;\n  --animate-task-rows-retry: task-rows-spin 1.2s linear infinite;\n}\n\n/* ── thinking-state ── */\n/* The working label shimmers; the settled label and \"more\" note fade in; trace rows rise in staggered (inline delay). */\n@keyframes thinking-state-shimmer {\n  from {\n    background-position: 150% center;\n  }\n  to {\n    background-position: -50% center;\n  }\n}\n@keyframes thinking-state-fade-in {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n@keyframes thinking-state-fade-up {\n  from {\n    opacity: 0;\n    transform: translateY(8px);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n@keyframes thinking-state-spin {\n  to {\n    transform: rotate(360deg);\n  }\n}\n@theme {\n  --animate-thinking-state-shimmer: thinking-state-shimmer 1.4s linear infinite;\n  --animate-thinking-state-done-in: thinking-state-fade-in 350ms ease-out both;\n  --animate-thinking-state-more-in: thinking-state-fade-in 300ms ease-out both;\n  --animate-thinking-state-query-in: thinking-state-fade-up 300ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-thinking-state-row-in: thinking-state-fade-up 320ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-thinking-state-spin: thinking-state-spin 700ms linear infinite;\n}\n\n/* ── tool-chips ── */\n/* Tool rows rise in; file chips pop in staggered (inline delay) and the \"more\" link follows; the diff preview pops in. */\n@keyframes tool-chips-fade-up {\n  from {\n    opacity: 0;\n    transform: translateY(8px);\n  }\n  to {\n    opacity: 1;\n    transform: translateY(0);\n  }\n}\n@keyframes tool-chips-fade-in {\n  from {\n    opacity: 0;\n  }\n  to {\n    opacity: 1;\n  }\n}\n@keyframes tool-chips-pop-in {\n  from {\n    opacity: 0;\n    transform: scale(0.95);\n  }\n  to {\n    opacity: 1;\n    transform: scale(1);\n  }\n}\n@theme {\n  --animate-tool-chips-row-in: tool-chips-fade-up 300ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-tool-chips-chip-in: tool-chips-pop-in 250ms cubic-bezier(0.23, 1, 0.32, 1) both;\n  --animate-tool-chips-more-in: tool-chips-fade-in 300ms ease-out both;\n  --animate-tool-chips-preview-in: tool-chips-pop-in 160ms cubic-bezier(0.23, 1, 0.32, 1) both;\n}\n\n/* ── shimmer ── */\n/* A highlight band sweeps across the label, right to left, on a loop. */\n@keyframes shimmer-sweep {\n  from {\n    background-position: 150% center;\n  }\n  to {\n    background-position: -50% center;\n  }\n}\n@theme {\n  --animate-shimmer-sweep: shimmer-sweep 1.8s linear infinite;\n}\n\n/* ── stream-text ── */\n/* The caret blinks once the text settles; it holds solid while streaming, and reduced motion keeps it solid. */\n@keyframes stream-text-caret-blink {\n  0%,\n  100% {\n    opacity: 1;\n  }\n  50% {\n    opacity: 0;\n  }\n}\n@theme {\n  --animate-stream-text-caret-blink: stream-text-caret-blink 1s step-end infinite;\n}\n\n/* ── chat-thread ── */\n/* The typing indicator's dots lift and brighten one after another (each dot sets its own delay); reduced motion holds them still. */\n@keyframes chat-thread-breathe {\n  0%,\n  60%,\n  100% {\n    opacity: 0.35;\n    transform: translateY(0);\n  }\n  30% {\n    opacity: 1;\n    transform: translateY(-3px);\n  }\n}\n@theme {\n  --animate-chat-thread-breathe: chat-thread-breathe 1.2s var(--ease-in-out) infinite;\n}\n\n/* ── sortable-data-table ── */\n/* On a phone, the fade off the pinned select-all cell follows the header strip's scroll (animation-timeline: scroll()). */\n@keyframes sortable-data-table-strip-fade {\n  to {\n    opacity: 1;\n  }\n}\n@theme {\n  --animate-sortable-data-table-strip-fade: sortable-data-table-strip-fade linear both;\n}\n\n/* ── page-header ── */\n/* A new issue or update arrives lit and settles to the page, so it is easy to find without a lasting marker. */\n@keyframes page-header-arrived {\n  0%,\n  35% {\n    opacity: 1;\n  }\n  100% {\n    opacity: 0;\n  }\n}\n/* The overflow menu closes with transitions; this no-op animation keeps it mounted until they finish. */\n@keyframes page-header-menu-exit {\n  to {\n    --menu-exit: 1;\n  }\n}\n@theme {\n  --animate-page-header-arrived: page-header-arrived 1.8s var(--ease-standard) both;\n  --animate-page-header-menu-exit: page-header-menu-exit var(--duration-instant) linear both;\n}\n",
      "type": "registry:file",
      "target": "@components/iris/styles/animations.css"
    },
    {
      "path": "src/styles/strict.css",
      "content": "/* Removes Tailwind's default colour palette, shadows and radii, so only Iris UI's token utilities exist. Import it right\n * after tailwindcss and before foundation.css. The site and the bundle use it; a consumer app that also uses Tailwind's\n * palette or shadcn's theme leaves it out. */\n@theme {\n  --color-*: initial;\n  --shadow-*: initial;\n  --radius-*: initial;\n}\n",
      "type": "registry:file",
      "target": "@components/iris/styles/strict.css"
    }
  ],
  "docs": "Docs and live preview: https://irisui.dev/components/foundation",
  "meta": {
    "kind": "foundation",
    "docs": "https://irisui.dev/components/foundation"
  }
}
