{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "andromeda-tokens",
  "type": "registry:lib",
  "title": "Andromeda tokens",
  "description": "Foundation files for the Andromeda design system — tokens, shared utilities, and the system mark. Required by every Andromeda component and template.",
  "author": "aicanvas <https://aicanvas.me>",
  "dependencies": [
    "@fontsource-variable/jetbrains-mono",
    "clsx",
    "tailwind-merge"
  ],
  "files": [
    {
      "path": "components/aicanvas/andromeda/AndromedaIcon.tsx",
      "content": "// @ts-nocheck — design-systems/ is not type-checked (see design-systems/CLAUDE.md). Strip this after a proper typing pass.\n// ============================================================\n// ANDROMEDA · brand icon\n// Two-path mark: gray triangle + turquoise blade. Source SVG is\n// 28x24 (7:6 aspect). The exported component takes a `size` prop\n// that is interpreted as the WIDTH; height is derived so the icon\n// never deforms regardless of where it's dropped in.\n// ============================================================\n\nexport function AndromedaIcon({ size = 24, mono = false, style = undefined, ...props }) {\n  const width = size;\n  const height = (size * 24) / 28;\n\n  // `mono` collapses the two-tone brand mark into a flat silhouette in\n  // `currentColor`, so the icon reads like every other Phosphor icon\n  // when dropped into nav rows that inherit text color from a parent.\n  // andromeda-allow: brand mark. The logo's own two tones, deliberately NOT\n  // system colours — they must not shift when a consumer rethemes the accent.\n  const fillBack = mono ? 'currentColor' : '#C1C1C1';\n  const fillFront = mono ? 'currentColor' : '#2DD4BF'; // andromeda-allow: brand mark\n\n  return (\n    <svg\n      width={width}\n      height={height}\n      viewBox=\"0 0 28 24\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      style={{ display: 'block', ...style }}\n      aria-label=\"Andromeda\"\n      role=\"img\"\n      {...props}\n    >\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M0 24L13.1483 0L14.9111 7.19476C14.4502 8.0149 14.0026 8.81944 13.5507 9.63168L9.86787 16.2221C10.7337 15.869 11.6049 15.5292 12.4707 15.1762L12.4717 15.1758C13.8326 14.633 12.4717 15.1758 16.531 13.5278L0 24Z\"\n        fill={fillBack}\n      />\n      <path\n        fillRule=\"evenodd\"\n        clipRule=\"evenodd\"\n        d=\"M14.7637 0L19.9727 20.3637C28 24 19.9727 20.3637 27.9998 24C26.8086 21.7712 25.5259 19.5191 24.3008 17.3031L17.7544 5.4295C17.5204 5.00473 14.8816 0.132369 14.7637 0Z\"\n        fill={fillFront}\n      />\n    </svg>\n  );\n}\n",
      "type": "registry:lib",
      "target": "components/aicanvas/andromeda/AndromedaIcon.tsx"
    },
    {
      "path": "components/aicanvas/andromeda/components/lib/utils.ts",
      "content": "// @ts-nocheck — design-systems/ is not type-checked (see design-systems/CLAUDE.md). Strip this after a proper typing pass.\n// ============================================================\n// SHARED UTILITIES\n// shadcn/ui-style helpers used by all Andromeda components.\n// ============================================================\n\nimport { clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\nimport { tokens } from '../../tokens';\n\n/**\n * cn — class name merger.\n * Combines clsx (conditional class joining) with tailwind-merge\n * (conflict resolution for Tailwind utilities).\n *\n * @param {...(string | undefined | null | false | Record<string, boolean>)} inputs\n * @returns {string}\n */\nexport function cn(...inputs) {\n  return twMerge(clsx(inputs));\n}\n\n/**\n * easingArray — parse a tokens.motion.easing cubic-bezier() string into the\n * 4-number array framer-motion needs. Framer cannot read CSS vars, so JS\n * animations MUST cross the var boundary — but they should derive from the\n * token string here, never hand-copy the numbers (copies drift silently).\n *\n * @param {string} cssBezier e.g. tokens.motion.easing.out\n * @returns {[number, number, number, number]}\n */\nexport function easingArray(cssBezier) {\n  const m = String(cssBezier).match(/[\\d.]+/g);\n  return m && m.length === 4 ? m.map(Number) : [0.4, 0, 0.2, 1];\n}\n\n/**\n * andromedaVars — emits Andromeda tokens as CSS custom properties.\n *\n * Tailwind v4 cannot reach JS-defined token values directly. By\n * spreading this object onto a component's root `style` prop we\n * cascade every token down to that subtree, where cva variants\n * can reference them via `[color:var(--andromeda-…)]` arbitrary\n * classes — including in `hover:` / `focus-visible:` state\n * variants. Every value below traces back to `tokens.ts` exactly.\n *\n * @returns {Record<string, string>}\n */\nexport function andromedaVars() {\n  const t = tokens;\n  return {\n    // Text\n    '--andromeda-text-primary':   t.color.text.primary,\n    '--andromeda-text-secondary': t.color.text.secondary,\n    '--andromeda-text-muted':     t.color.text.muted,\n    '--andromeda-text-faint':     t.color.text.faint,\n    // Surfaces — solid + one alpha (scrim/backdrop)\n    '--andromeda-surface-base':    t.color.surface.base,\n    '--andromeda-surface-raised':  t.color.surface.raised,\n    '--andromeda-surface-overlay': t.color.surface.overlay,\n    '--andromeda-surface-hover':   t.color.surface.hover,\n    '--andromeda-surface-active':  t.color.surface.active,\n    '--andromeda-surface-alpha':   t.color.surface.alpha,\n    // Borders — solid + one alpha (glassy edge)\n    '--andromeda-border-subtle': t.color.border.subtle,\n    '--andromeda-border-base':   t.color.border.base,\n    '--andromeda-border-bright': t.color.border.bright,\n    '--andromeda-border-strong': t.color.border.strong,\n    '--andromeda-border-alpha':  t.color.border.alpha,\n    // Accent (turquoise) — 5 stops + 1 alpha + on-fill foreground\n    '--andromeda-accent-100':   t.color.accent[100],\n    '--andromeda-accent-200':   t.color.accent[200],\n    '--andromeda-accent-300':   t.color.accent[300],\n    '--andromeda-accent-400':   t.color.accent[400],\n    '--andromeda-accent-500':   t.color.accent[500],\n    '--andromeda-accent-alpha': t.color.accent.alpha,\n    '--andromeda-accent-on':    t.color.accent.on,\n    // Red — 5 stops + 1 alpha + on-fill foreground\n    '--andromeda-red-100':   t.color.red[100],\n    '--andromeda-red-200':   t.color.red[200],\n    '--andromeda-red-300':   t.color.red[300],\n    '--andromeda-red-400':   t.color.red[400],\n    '--andromeda-red-500':   t.color.red[500],\n    '--andromeda-red-alpha': t.color.red.alpha,\n    '--andromeda-red-on':    t.color.red.on,\n    // Orange — 5 stops + 1 alpha + on-fill foreground\n    '--andromeda-orange-100':   t.color.orange[100],\n    '--andromeda-orange-200':   t.color.orange[200],\n    '--andromeda-orange-300':   t.color.orange[300],\n    '--andromeda-orange-400':   t.color.orange[400],\n    '--andromeda-orange-500':   t.color.orange[500],\n    '--andromeda-orange-alpha': t.color.orange.alpha,\n    '--andromeda-orange-on':    t.color.orange.on,\n    // Gradients\n    '--andromeda-gradient-accent-fade':  t.color.gradient.accentFade,\n    '--andromeda-gradient-accent-sweep': t.color.gradient.accentSweep,\n    '--andromeda-gradient-surface-soft': t.color.gradient.surfaceSoft,\n    // Typography\n    '--andromeda-font-sans': t.typography.fontSans,\n    '--andromeda-font-mono': t.typography.fontMono,\n    '--andromeda-text-xs':   t.typography.size.xs,\n    '--andromeda-text-sm':   t.typography.size.sm,\n    '--andromeda-text-md':   t.typography.size.md,\n    '--andromeda-text-lg':   t.typography.size.lg,\n    '--andromeda-text-xl':   t.typography.size.xl,\n    '--andromeda-text-2xl':  t.typography.size['2xl'],\n    '--andromeda-text-3xl':  t.typography.size['3xl'],\n    '--andromeda-text-4xl':  t.typography.size['4xl'],\n    '--andromeda-text-5xl':  t.typography.size['5xl'],\n    '--andromeda-weight-thin':     String(t.typography.weight.thin),\n    '--andromeda-weight-regular':  String(t.typography.weight.regular),\n    '--andromeda-weight-medium':   String(t.typography.weight.medium),\n    '--andromeda-weight-semibold': String(t.typography.weight.semibold),\n    '--andromeda-weight-bold':     String(t.typography.weight.bold),\n    '--andromeda-leading-none':    String(t.typography.lineHeight.none),\n    '--andromeda-leading-tight':   String(t.typography.lineHeight.tight),\n    '--andromeda-leading-snug':    String(t.typography.lineHeight.snug),\n    '--andromeda-leading-normal':  String(t.typography.lineHeight.normal),\n    '--andromeda-leading-relaxed': String(t.typography.lineHeight.relaxed),\n    '--andromeda-tracking-tight':  t.typography.tracking.tight,\n    '--andromeda-tracking-normal': t.typography.tracking.normal,\n    '--andromeda-tracking-wide':   t.typography.tracking.wide,\n    '--andromeda-tracking-wider':  t.typography.tracking.wider,\n    '--andromeda-tracking-widest': t.typography.tracking.widest,\n    // Spacing\n    '--andromeda-1':  t.spacing[1],\n    '--andromeda-2':  t.spacing[2],\n    '--andromeda-3':  t.spacing[3],\n    '--andromeda-4':  t.spacing[4],\n    '--andromeda-5':  t.spacing[5],\n    '--andromeda-6':  t.spacing[6],\n    '--andromeda-8':  t.spacing[8],\n    '--andromeda-10': t.spacing[10],\n    '--andromeda-12': t.spacing[12],\n    // Radius\n    '--andromeda-radius-none':  t.radius.none,\n    '--andromeda-radius-sm':    t.radius.sm,\n    '--andromeda-radius-md':    t.radius.md,\n    // Raw default, NOT t.radius.frame — that string embeds var(--andromeda-\n    // radius-frame,…) and would self-reference. Keep in sync with tokens.ts.\n    '--andromeda-radius-frame': '0px',\n    // Border + marker stroke widths (1px hairline identity, theme-tunable)\n    '--andromeda-border-width': t.border.width,\n    '--andromeda-marker-width': `${t.marker.borderWidth}px`,\n    // Opacity — disabled-control constant (unitless; used via opacity-[var(--andromeda-opacity-disabled)])\n    '--andromeda-opacity-disabled': String(t.opacity.disabled),\n    // Icon glyph scale (px units for CSS boxes; Phosphor size props use the numbers)\n    '--andromeda-icon-xs': `${t.iconSize.xs}px`,\n    '--andromeda-icon-sm': `${t.iconSize.sm}px`,\n    '--andromeda-icon-md': `${t.iconSize.md}px`,\n    '--andromeda-icon-lg': `${t.iconSize.lg}px`,\n    '--andromeda-icon-xl': `${t.iconSize.xl}px`,\n    // Effects — glass blur + accent glow radius\n    '--andromeda-blur-sm': t.effect.blurSm,\n    '--andromeda-blur-lg': t.effect.blurLg,\n    '--andromeda-glow':    t.effect.glow,\n    // Drop-shadow — primitives (theme-tunable) + composed size tiers\n    '--andromeda-shadow-color': t.effect.shadowColor,\n    '--andromeda-shadow-x':     t.effect.shadowX,\n    '--andromeda-shadow-y':     t.effect.shadowY,\n    '--andromeda-shadow-blur':  t.effect.shadowBlur,\n    '--andromeda-shadow-sm':    t.effect.shadowSm,\n    '--andromeda-shadow-md':    t.effect.shadowMd,\n    '--andromeda-shadow-lg':    t.effect.shadowLg,\n    // Chart constants (CSS sinks only; recharts numeric sinks stay RAW)\n    '--andromeda-chart-fill-opacity':       String(t.chart.fillOpacity),\n    '--andromeda-chart-fill-opacity-faint': String(t.chart.fillOpacityFaint),\n    '--andromeda-swatch':                   t.chart.swatch,\n    // Breakpoints — exposed for clamp()/calc() expressions that want the\n    // same thresholds (e.g. fluid type). NOTE: a CSS @media condition\n    // CANNOT read var(), so reflow media queries use the `mq` helper\n    // (components/lib/responsive.ts), which interpolates the literal token.\n    '--andromeda-bp-sm': t.breakpoints.sm,\n    '--andromeda-bp-md': t.breakpoints.md,\n    '--andromeda-bp-lg': t.breakpoints.lg,\n    // Motion — every duration, easing, and stagger from tokens.motion.\n    // Components and templates reference these as `var(--andromeda-duration-*)`\n    // and `var(--andromeda-easing-*)` instead of hardcoding ms / cubic-bezier.\n    '--andromeda-duration-fast':       t.motion.duration.fast,\n    '--andromeda-duration-normal':     t.motion.duration.normal,\n    '--andromeda-duration-slow':       t.motion.duration.slow,\n    '--andromeda-duration-cascade':    t.motion.duration.cascade,\n    '--andromeda-duration-row':        t.motion.duration.row,\n    '--andromeda-duration-countup':    t.motion.duration.countup,\n    '--andromeda-easing-standard':     t.motion.easing.standard,\n    '--andromeda-easing-out':          t.motion.easing.out,\n    '--andromeda-easing-in':           t.motion.easing.in,\n    '--andromeda-easing-sharp':        t.motion.easing.sharp,\n    '--andromeda-stagger-cascade':     t.motion.stagger.cascade,\n    '--andromeda-stagger-row':         t.motion.stagger.row,\n    '--andromeda-stagger-progressbar': t.motion.stagger.progressBar,\n  };\n}\n",
      "type": "registry:lib",
      "target": "components/aicanvas/andromeda/components/lib/utils.ts"
    },
    {
      "path": "components/aicanvas/andromeda/tokens.ts",
      "content": "import '@fontsource-variable/jetbrains-mono';\n// @ts-nocheck — design-systems/ is not type-checked (see design-systems/CLAUDE.md). Strip this after a proper typing pass.\n//\n// Andromeda v1: free and open source (MIT). These components and tokens\n// are free to use, forever. This public repo is frozen at v1; new\n// Andromeda components are developed privately and are not published\n// here (they stay free to use via the platform).\n//\n// Andromeda v2 is premium: the full design brain (deep rules + build\n// workflow), the template library, and one-command bulk install.\n// https://aicanvas.me/andromeda\n//\n// ============================================================\n// ANDROMEDA DESIGN TOKENS\n// Sci-fi / blueprint aesthetic. Solid surfaces by default — every\n// hue palette (accent, red, orange) ships as a 5-stop scale (100\n// lightest → 500 darkest). One alpha token is allowed per family\n// (color, border, surface) for cases that genuinely need layering.\n// ============================================================\n\nexport const tokens = {\n  color: {\n    // Text — solid greys. No alpha. Tuned for WCAG AA on surface.base:\n    // primary 17.7:1, secondary 8.3:1, muted 6.9:1, faint 3.5:1 (AA-large).\n    text: {\n      primary:   '#F5F5F5',\n      secondary: '#A3A3A3',\n      muted:     '#9A9A9A',\n      faint:     '#6E6E6E',\n    },\n    // Surfaces — solid colors. `base` is the page void; nothing\n    // else is transparent. `alpha` is the one allowed alpha\n    // surface (modal scrim / drawer backdrop).\n    surface: {\n      base:    '#0E0E0F',\n      raised:  '#141415',\n      overlay: '#19191A',\n      hover:   '#1C1C1D',\n      active:  '#232325',\n      alpha:   'rgba(0, 0, 0, 0.65)',\n    },\n    // Borders — solid greys + one alpha border for glassy edges.\n    border: {\n      subtle: '#212122',\n      base:   '#3E3E3F',\n      bright: '#5B5B5C',\n      strong: '#939393',\n      alpha:  'rgba(255, 255, 255, 0.18)',\n    },\n    // Accent — turquoise. 5 stops + 1 alpha (translucent overlay\n    // derived from the 300 base, 0.25). The 100 stop pairs with\n    // the 500 stop for body text (≥6:1 ratio).\n    accent: {\n      100:   '#BAF8EC',\n      200:   '#56F0D6',\n      300:   '#0FCFB2',\n      400:   '#109380',\n      500:   '#126059',\n      alpha: 'rgba(15, 207, 178, 0.25)',\n      // Text/icon ON an accent-filled surface. The one guaranteed-contrast\n      // pairing token — every accent fill takes its foreground from here so\n      // a theme retuning the family keeps labels legible. Defaults to the\n      // 100 stop (documented ≥6:1 on the 500 stop).\n      on:    '#BAF8EC',\n    },\n    // Red — 5 stops + 1 alpha. Use 100 for body text on 500 (≥7:1).\n    red: {\n      100:   '#FFCFCF',\n      200:   '#FF8B8B',\n      300:   '#FF3939',\n      400:   '#B82424',\n      500:   '#5A1818',\n      alpha: 'rgba(255, 57, 57, 0.25)',\n      on:    '#FFCFCF',\n    },\n    // Orange — 5 stops + 1 alpha. Use 100 for body text on 500 (≥8:1).\n    orange: {\n      100:   '#FFE5B5',\n      200:   '#FFC466',\n      300:   '#FFA000',\n      400:   '#B57009',\n      500:   '#4D3712',\n      alpha: 'rgba(255, 160, 0, 0.25)',\n      on:    '#FFE5B5',\n    },\n    // Gradients fade to solid colors (no transparent stops).\n    gradient: {\n      accentFade:  'linear-gradient(180deg, #0A2422 0%, #0E0E0F 100%)',\n      // Soft accent spotlight — a barely-visible accent tint blooms from\n      // the top-left corner and fades smoothly back to surface.raised.\n      // Used by Card variant=\"glow\" to draw the eye without painting a\n      // colored card.\n      accentSweep: 'radial-gradient(ellipse 80% 70% at 0% 0%, #1B2C29 0%, #172321 25%, #141415 65%)',\n      surfaceSoft: 'linear-gradient(180deg, #181819 0%, #111111 100%)',\n    },\n  },\n  typography: {\n    // JetBrains Mono is the only font in the Andromeda design system.\n    // In the AI Canvas app, --font-jetbrains-mono is provided by next/font (see\n    // app/design-systems/andromeda/layout.tsx). Installed projects don't have it,\n    // so the var carries an INNER fallback ('JetBrains Mono Variable'). Without an\n    // inner fallback, an undefined var invalidates the WHOLE declaration (invalid\n    // at computed-value time) and the named fallbacks below never apply — the font\n    // collapses to the page's inherited font. The registry self-loads\n    // 'JetBrains Mono Variable' via @fontsource-variable so the fallback resolves.\n    // Both fontSans and fontMono resolve to the same family — the sans/mono\n    // distinction is kept only so existing component references work unchanged.\n    fontSans: \"var(--font-jetbrains-mono, 'JetBrains Mono Variable'), 'JetBrains Mono', 'IBM Plex Mono', Menlo, Monaco, Consolas, monospace\",\n    fontMono: \"var(--font-jetbrains-mono, 'JetBrains Mono Variable'), 'JetBrains Mono', 'IBM Plex Mono', Menlo, Monaco, Consolas, monospace\",\n    size: {\n      xs:   '10px',\n      sm:   '12px',\n      md:   '14px',\n      lg:   '15px',\n      xl:   '18px',\n      '2xl':'22px',\n      '3xl':'28px',\n      '4xl':'36px',\n      '5xl':'48px',\n    },\n    weight: {\n      thin:     200,\n      regular:  400,\n      medium:   500,\n      semibold: 600,\n      bold:     700,\n    },\n    lineHeight: {\n      none:    1,\n      tight:   1.1,\n      snug:    1.25,\n      normal:  1.5,\n      relaxed: 1.6,\n    },\n    tracking: {\n      // Wide letter-spacing on monospace labels\n      tight:  '0',\n      normal: '0.02em',\n      wide:   '0.08em',\n      wider:  '0.14em',\n      widest: '0.22em',\n    },\n  },\n  spacing: {\n    1: '4px',\n    2: '8px',\n    3: '12px',\n    4: '16px',\n    5: '20px',\n    6: '24px',\n    8: '32px',\n    10:'40px',\n    12:'48px',\n  },\n  radius: {\n    // Sharp by default — square corners are part of the look\n    none: '0',\n    sm:   '2px',\n    md:   '3px',\n    // The one radius every framed surface consumes (cards, buttons, inputs,\n    // menus, tiles). 0 = the square identity. Same var-with-fallback pattern\n    // as border.thin below, so INLINE styles consuming tokens.radius.frame\n    // are theme-tunable too; andromedaVars() emits the raw 0px default for\n    // --andromeda-radius-frame (it must not self-reference this string).\n    // `none` stays a true constant zero for explicit square declarations.\n    frame: 'var(--andromeda-radius-frame, 0px)',\n  },\n  opacity: {\n    // Disabled controls. One system-wide constant so every primitive and\n    // input dims identically. Exposed as --andromeda-opacity-disabled.\n    disabled: 0.4,\n  },\n  // Icon glyph sizes (numbers — Phosphor `size` props and SVG boxes need\n  // numerics). One authoritative scale instead of per-component px.\n  iconSize: {\n    xs: 12,\n    sm: 16,\n    md: 18,\n    lg: 20,\n    xl: 22,\n  },\n  // Effects — frosted-glass blur radii and the accent hover/focus glow\n  // radius. Exposed as --andromeda-blur-sm/-lg and --andromeda-glow.\n  effect: {\n    blurSm: '2px',\n    blurLg: '8px',\n    glow:   '8px',\n    // Drop-shadow system. Four PRIMITIVES a theme can tune (color, x, y,\n    // blur), then three SIZE TIERS composed from them. The tiers scale the\n    // offset + blur so a large panel casts a deeper shadow than a small chip\n    // — one control set retunes every tier at once. Components pick the tier\n    // that matches their footprint (chips → sm, menus/popovers → md, drawers\n    // / big panels → lg). Default is a soft near-black elevation, close to\n    // the ad-hoc shadows components used before.\n    shadowColor: 'rgba(0, 0, 0, 0.45)',\n    shadowX:     '0px',\n    shadowY:     '10px',\n    shadowBlur:  '24px',\n    // Tier strings reference the primitive vars (with the token defaults as\n    // fallbacks) so tuning any primitive reflows all three tiers live.\n    shadowSm: 'var(--andromeda-shadow-x, 0px) calc(var(--andromeda-shadow-y, 10px) * 0.4) calc(var(--andromeda-shadow-blur, 24px) * 0.4) var(--andromeda-shadow-color, rgba(0, 0, 0, 0.45))',\n    shadowMd: 'var(--andromeda-shadow-x, 0px) calc(var(--andromeda-shadow-y, 10px) * 0.8) calc(var(--andromeda-shadow-blur, 24px) * 0.9) var(--andromeda-shadow-color, rgba(0, 0, 0, 0.45))',\n    shadowLg: 'var(--andromeda-shadow-x, 0px) var(--andromeda-shadow-y, 10px) var(--andromeda-shadow-blur, 24px) var(--andromeda-shadow-color, rgba(0, 0, 0, 0.45))',\n  },\n  // Chart constants shared by TrendChart / MetricChart / RadarChart / Gauge.\n  // lineWidth/dash are recharts sinks (numbers/strings, var-incapable — keep\n  // RAW); fillOpacity + swatch are CSS sinks, exposed as vars.\n  chart: {\n    fillOpacity:      0.12,\n    fillOpacityFaint: 0.06,\n    lineWidth:        1.5,\n    dash:             '2 4',\n    swatch:           '8px',\n  },\n  border: {\n    // System hairline width. 1px IS the identity; the var indirection (same\n    // pattern as fontSans above) lets a theme widen every border at once.\n    // The inner fallback keeps installed projects correct without any var.\n    width: '1px',\n    thin: 'var(--andromeda-border-width, 1px) solid',\n  },\n  marker: {\n    // Corner marker geometry — L-shaped brackets that hug each corner.\n    size:        12,    // px square the bracket lives inside\n    offset:      0,     // px inset from the corner (0 = flush)\n    borderWidth: 1,     // px stroke thickness of the L; rendered through\n                        // --andromeda-marker-width so themes can thicken it\n  },\n  layout: {\n    sidebarWidth: '224px',\n    headerHeight: '60px',\n  },\n  // Breakpoints — max-width thresholds. Andromeda is DESKTOP-FIRST: the\n  // default (unqualified) styles are the desktop layout and these step\n  // DOWN from there. `md` (768px) is the primary stack threshold — at/below\n  // it, dense bento grids collapse to a single column and the sidebar\n  // becomes a Drawer. `sm` is for phone-only fine-tuning (display-type\n  // step-down, tighter insets); `lg` is the tablet ceiling where the full\n  // desktop grid is still guaranteed to fit. Media queries can't read a\n  // CSS var(), so the `mq` helper (components/lib/responsive.ts)\n  // interpolates these literals — tokens.ts stays the single source.\n  // See the Andromeda responsive rules for the mechanism + faithful-stack rules.\n  breakpoints: {\n    sm: '640px',\n    md: '768px',\n    lg: '1024px',\n  },\n  // Motion — durations, easings, and stagger presets that encode the\n  // Andromeda tempo. Movement signals data movement or interaction\n  // acknowledgement; never decoration. See the Andromeda motion rules for the\n  // philosophy and approved/forbidden patterns.\n  motion: {\n    duration: {\n      // Click acknowledgement (active flash, focus ring, button press).\n      // Brief enough that the user reads it as feedback, not animation.\n      fast:    '80ms',\n      // Default state transitions: hover, popover caret rotation, anything\n      // where the user changed their mind and wants to see the new state.\n      normal:  '140ms',\n      // Stateful trigger reveals (drawer slide, menu open). The motion\n      // IS the visual answer to the click — slow enough to track, fast\n      // enough not to feel laggy.\n      slow:    '200ms',\n      // Cascade entrances (ProgressBar segment fill, dashboard section\n      // slide-in). Each element's own motion duration; stagger between\n      // siblings is `motion.stagger.cascade`. 500ms is the calm read —\n      // each element clearly arrives, the cascade doesn't feel hurried.\n      cascade: '500ms',\n      // Row reveals inside a table or log when its container scrolls\n      // into view. Tighter than the section cascade because rows are\n      // smaller visual elements; a 500ms reveal per row drags.\n      row:     '350ms',\n      // StatTile count-up. Long enough that the eye reads the value as\n      // animating in, short enough that the final number is what the\n      // user remembers.\n      countup: '1800ms',\n    },\n    easing: {\n      // Material standard — accelerate then decelerate. Default for\n      // anything that doesn't have a more specific reason.\n      standard: 'cubic-bezier(0.4, 0, 0.2, 1)',\n      // Ease-out — fast start, soft landing. Use for entrances (cascade,\n      // hover-in) where the motion settles into a final state.\n      out:      'cubic-bezier(0, 0, 0.2, 1)',\n      // Ease-in — slow start, fast end. Use for exits (drawer close,\n      // hover-out) where the motion is leaving the field.\n      in:       'cubic-bezier(0.4, 0, 1, 1)',\n      // Ease-in-out — symmetrical. Use for state-flip transitions where\n      // start and end deserve the same weight.\n      sharp:    'cubic-bezier(0.4, 0, 0.6, 1)',\n    },\n    stagger: {\n      // Cascade between siblings on entrance (top-to-bottom dashboard\n      // load, list reveal). 60ms reads as a deliberate sequence, not\n      // a cascade so fast it feels like a single event.\n      cascade:     '60ms',\n      // Row stagger inside a table or log. Tighter than section cascade\n      // — long tables would otherwise feel like they take forever to\n      // reveal. 40ms is fast enough to keep the user moving, slow\n      // enough that the eye registers the cascade.\n      row:         '40ms',\n      // ProgressBar segment fill cascade. Tighter than entrance because\n      // segments are visually adjacent — looser would read as choppy.\n      progressBar: '120ms',\n    },\n  },\n};\n",
      "type": "registry:lib",
      "target": "components/aicanvas/andromeda/tokens.ts"
    }
  ]
}
