{"version":3,"file":"colors-OYs1yUs1.cjs","names":[],"sources":["../src/tokens/colors.ts"],"sourcesContent":["/**\n * Color tokens.\n *\n * Source of truth: AiStrike Complete Design System (Figma)\n * https://www.figma.com/design/LJdrBxmaROpXg0hLW3GKe6/AiStrike-Complete-Design-System?node-id=23-476\n *\n * All hex values below were extracted directly from the Figma \"Colours\" frame.\n * This is a dark-first security design system.\n */\n\n/**\n * Text colors — a monotonic ramp.\n *\n * The tiers descend in lightness in the order they are declared, so picking a\n * tier is picking an emphasis level. This was not previously true: `tertiary`\n * used to be brighter than `secondary`, and `muted` brighter than `subtle`,\n * which is why call sites reached past them for an ad-hoc grey.\n *\n * Contrast against `background.widget` (#262626), the rung most body text sits\n * on, is pinned in `textRamp.contrast.test.ts`:\n *\n * | tier      | ratio | usable for                                  |\n * |-----------|-------|---------------------------------------------|\n * | primary   | 12.93 | body and headings                           |\n * | secondary |  9.14 | body                                        |\n * | tertiary  |  6.00 | body                                        |\n * | subtle    |  4.74 | body, at the AA floor — see the caveat below |\n * | muted     |  3.63 | large or bold text only                     |\n * | disabled  |  2.33 | disabled affordances, exempt by design       |\n *\n * `subtle` clears 4.5:1 on `page`, `primary` and `widget` only. On `surface`\n * and above it drops to 4.25 and below, so the surface scope switches\n * `--ds-text-quiet` from `subtle` to `tertiary` at that point. Do not hand-pick\n * `subtle` for text on an overlay.\n *\n * ## What used to be here\n *\n * Six entries were removed once the ramp became monotonic and the severity\n * scale grew a text variant, because each was a second name for a decision made\n * elsewhere — and a name is where drift starts:\n *\n * - `tableLabel` and `inactiveTab` were both `#909090`, the same value as\n *   `subtle`. The spec folds `inactiveTab` into `subtle` explicitly. Anything\n *   quiet should read `var(--ds-text-quiet)`, which also swaps tier where\n *   `subtle` stops being legible — a fixed `#909090` cannot.\n * - `highlight` was `#00C4AC`, which is `brand.main`.\n * - `critical`, `high` and `medium` were severity *fills* being offered as ink.\n *   They are unusable that way: `#BB010B` on `widget` is 2.49:1. Severity as\n *   text is `severityTextColors`, which is the same hues lightened until each\n *   clears 4.5:1 on every rung.\n * - `chartText1..3` restated three series colours. Series identity belongs to\n *   `chartTokens[mode].series`, which is validated as a categorical palette.\n */\nexport const textColors = {\n  primary: '#EDEDED',\n  secondary: '#C9C9C9',\n  /** One step below `secondary`. Now genuinely dimmer than it, which it was not. */\n  tertiary: '#A3A3A3',\n  /**\n   * Supporting text sitting directly under a title — a row's description line,\n   * a card's subtitle. Sits at the 4.5:1 floor on `widget`, so it is the last\n   * tier usable for body text, and only up to that rung.\n   */\n  subtle: '#909090',\n  /**\n   * Incidental metadata: timestamps, counts, authors, \"last seen\" columns.\n   * Below the AA floor for normal text at 3.63:1 — large or bold only.\n   */\n  muted: '#7C7C7C',\n  /**\n   * Text *on* a tooltip. Tooltips are dark (`background.raised`), so this is a\n   * light ink. It was a near-black, which only made sense on a light tooltip.\n   */\n  tooltip: '#EDEDED',\n  disabled: '#5E5E5E',\n  /**\n   * Link text. Nine percent lighter than the spec's `#6699FF`, which cleared\n   * 4.5:1 on every rung except `overlay` (4.10:1). A link inside a dialog is\n   * common enough that certifying the token below the top rung was not worth\n   * the footgun; this holds from `page` (6.99:1) to `overlay` (4.53:1).\n   */\n  link: '#74A2FF',\n} as const;\n\n/**\n * Surface / background colors — the six-rung ladder.\n *\n * The first six entries are an ordered scale, not a set of names. Each rung is\n * 2–3 L\\* above the one below it, which is enough to read as a step without\n * turning a dense page into stripes. Containment goes *up*: a card on `primary`\n * is `widget`, a popover over that card is `surface`. Recession goes *down*: an\n * input inside a `widget` is `primary`, one rung below its host.\n *\n * ```\n * page     #191919   the app shell, and recessed bands (table headers)\n * primary  #1F1F1F   page body, and fields hosted on widget\n * widget   #262626   cards, panels, dashboard tiles\n * surface  #2E2E2E   popovers, menus, drawers, dialogs\n * raised   #333333   tooltips, snackbars, floating elements over an overlay\n * overlay  #3A3A3A   the ceiling — a second dialog, a menu inside a drawer\n * ```\n *\n * `page` is no longer pure black. That is deliberate and the ladder depends on\n * it: a field on the app shell has to recess *below* its host, and nothing sits\n * below `#000000`.\n *\n * Three levels of containment is the supported maximum. `Surface` clamps a\n * fourth and warns in development — see `src/tokens/surfaceScopes.ts`.\n */\nexport const backgroundColors = {\n  /** Rung 0. App shell, and bands that recess below the body. */\n  page: '#191919',\n  /** Rung 1. Primary content background, and fields hosted on `widget`. */\n  primary: '#1F1F1F',\n  /** Rung 2. Widget / card background. Where most body text lives. */\n  widget: '#262626',\n  /** Rung 3. Pop-up / filter / side panel / AI chat. */\n  surface: '#2E2E2E',\n  /** Rung 4. Tooltips, snackbars, and anything floating above an overlay. */\n  raised: '#333333',\n  /** Rung 5, the ceiling. A dialog over a dialog, a menu inside a drawer. */\n  overlay: '#3A3A3A',\n  /** Rule between table rows. Subtler than `border` so the outline still reads. */\n  tableDivider: '#262626',\n  /** Subtle success-tinted surface. */\n  darkGreen: '#182724',\n  /**\n   * Default border / divider.\n   *\n   * Rung-agnostic, and therefore only correct on the lower rungs: it is 1.13:1\n   * on `widget` and near-invisible on `surface`. Prefer `borderByRung` or\n   * `var(--ds-border)` anywhere the rung is known. Kept because `palette.divider`\n   * points at it and every MUI `Divider` reads that.\n   */\n  border: '#2F2F2F',\n  /** A divider that should read as a hint rather than a rule. */\n  borderSubtle: '#272727',\n  /**\n   * Card border / outline. Kept for explicit opt-in, but a card on `primary` or\n   * above should not carry one — the rung step already separates it.\n   */\n  cardBorder: '#414141',\n} as const;\n\n/**\n * Border colour per rung, at hairline-divider weight (~1.35:1 against its host).\n *\n * A border cannot be one value on a ladder this tight. The rungs are 2–3 L\\*\n * apart, so a fixed `border` that reads on `page` is invisible two rungs up:\n * `#2F2F2F` on `widget` is 1.13:1, and on `surface` it is almost the background\n * itself. The flat tokens are kept for existing consumers, but anything that\n * knows its rung should use this — or `var(--ds-border)`, which resolves it.\n *\n * 1.35:1 is calibrated against what already ships rather than invented: the old\n * `border` ran 1.11–1.32:1 depending on surface, and MUI's own dark divider\n * (`rgba(255,255,255,0.12)` over `#121212`) is 1.38:1.\n */\nexport const borderByRung = {\n  page: '#313131',\n  primary: '#363636',\n  widget: '#3B3B3B',\n  surface: '#424242',\n  raised: '#474747',\n  overlay: '#4E4E4E',\n} as const;\n\n/**\n * Border colour per rung at outline weight (~1.7:1), for a deliberate edge\n * rather than a divider — an outlined chip, a focusable container, a selected\n * card.\n *\n * The `page` entry is `#414141`, which is exactly the historical `cardBorder`.\n * That is a coincidence worth keeping: it means this ramp is the same weight the\n * system already used for outlines, generalised across the ladder.\n */\nexport const outlineByRung = {\n  page: '#414141',\n  primary: '#454545',\n  widget: '#4A4A4A',\n  surface: '#515151',\n  raised: '#565656',\n  overlay: '#5C5C5C',\n} as const;\n\n/**\n * The ordered ladder, lowest rung first.\n *\n * Exported as data so the monotonicity guarantee can be tested and the\n * Storybook docs page can render the scale without restating the values.\n */\nexport const SURFACE_LADDER = ['page', 'primary', 'widget', 'surface', 'raised', 'overlay'] as const;\n\nexport type SurfaceRung = (typeof SURFACE_LADDER)[number];\n\n/**\n * Row-separator colour per rung (~1.12:1 against its host).\n *\n * Lighter than `borderByRung` on purpose: container outlines and header\n * underlines stay on the heavier border, while the rules between table rows\n * are rhythm, not structure. Keyed by the surface the separator sits on so a\n * table derives its row rule from the host without picking a flat grey.\n *\n * Source: Table Separators spec (dark values). Light counterparts live on the\n * light surface scope — light has a different surface ladder today.\n */\nexport const separatorByRung = {\n  page: '#212121',\n  primary: '#282828',\n  widget: '#2F2F2F',\n  surface: '#383838',\n  raised: '#3D3D3D',\n  overlay: '#454545',\n} as const satisfies Record<SurfaceRung, string>;\n\n/**\n * Table header fill per rung (~1.08:1 against its host).\n *\n * Moves *away* from the elevation direction — darker in light, lighter in dark —\n * so the header reads as recessed relative to its rows. A flat `tableHeader`\n * only worked on the rung it was drawn against; inside a card (widget) it read\n * as a trench, and on a dialog it read as a bar.\n *\n * Source: Table Separators spec. `primary` reuses `widget` rather than minting\n * a second hex. Light counterparts live on the light surface scope.\n */\nexport const tableHeaderByRung = {\n  page: '#202020',\n  /** Same hex as `widget` — reuse rather than add a value. */\n  primary: '#262626',\n  widget: '#2C2C2C',\n  surface: '#343434',\n  raised: '#383838',\n  overlay: '#3F3F3F',\n} as const satisfies Record<SurfaceRung, string>;\n\n/** Three levels of containment. A fourth is clamped and warned about. */\nexport const MAX_SURFACE_DEPTH = 3;\n\n/**\n * Scrim opacities over black, by what the scrim is covering for.\n *\n * A dialog demands more separation than a menu because it takes over the\n * page. These are opacities, not colors, because the scrim always sits on\n * black regardless of rung.\n */\nexport const scrim = {\n  /** A menu or popover. Barely there — it exists to catch the outside click. */\n  menu: 0.32,\n  /** A drawer or dismissible overlay. */\n  drawer: 0.5,\n  /** A modal dialog, which owns the page while it is open. */\n  dialog: 0.6,\n  /**\n   * A busy veil over content that is already open — the loading state inside a\n   * popover or menu, not a scrim between layers. Named rather than inlined so\n   * the two places that draw one cannot drift apart.\n   */\n  loading: 0.4,\n} as const;\n\n/**\n * Ink for text sitting on a *saturated* fill — a brand or severity colour —\n * rather than on a rung.\n *\n * Fixed rather than derived from the ladder, because the fill it sits on does\n * not move with the ladder either. Named by the fill it goes on, not by the\n * theme mode: a light fill wants dark ink in either theme.\n */\nexport const fillInk = {\n  /** On a light saturated fill: brand teal, warning amber. */\n  onLight: '#191919',\n  /** On a dark saturated fill: critical red. */\n  onDark: '#FFFFFF',\n} as const;\n\n/**\n * Interaction state opacities, applied over the host rung rather than as fixed\n * colors, so a hover on `page` and a hover on `overlay` both read as one step.\n */\nexport const stateAlpha = {\n  hover: 0.06,\n  selected: 0.12,\n  pressed: 0.16,\n  focus: 0.12,\n  disabled: 0.38,\n} as const;\n\n/**\n * Shared chrome for outlined TextField, Select, Search, Autocomplete, and\n * the secondary Button. Kept separate from `backgroundColors.border` so\n * restyling these controls does not move every divider in the system.\n * Hover and focus use the same outline — not `text.primary` (white) and\n * not the brand teal.\n */\nexport const inputColors = {\n  /**\n   * Field / secondary-button fill (dark).\n   *\n   * This is the fallback for a field with no surface context. A field inside a\n   * scoped surface recesses one rung below its host instead, via\n   * `var(--ds-field)` — that is what makes an input read as inset rather than\n   * as a differently-coloured box. The one exception is a field directly on\n   * `page`: there is no rung below it, so it goes transparent with a hairline.\n   *\n   * `page` rather than `primary`, because the unscoped case is a field on the\n   * document body, and `palette.background.default` is `primary`. Setting this\n   * to `primary` made the field exactly match the body and vanish, leaving only\n   * its outline. This is also within a point of the historical `#1A1A1A`, so\n   * the fallback path barely moves.\n   *\n   * Light mode uses `lightInputColors` — never fall back to this hex in light,\n   * or fields render as black bars on a grey page.\n   */\n  background: '#191919',\n  /** Outline at rest. */\n  border: '#2F2F2F',\n  /** Outline on hover. One step up, so the control acknowledges the pointer. */\n  borderHover: '#3A3A3A',\n  /**\n   * Outline on focus.\n   *\n   * Deliberately equal to `border`: focus is currently *not* indicated on\n   * fields in dark. Both specs proposed a ring — neutral `#E8E8E8` in Tokens\n   * §03, brand `#00C4AC` in Component System §05 — and neither was adopted for\n   * dark. The token exists, and components reference it, so turning focus\n   * indication on later is a change to this one value rather than a change to\n   * every input component.\n   *\n   * Light mode's `lightInputColors.focusRing` is distinct (`#1A1A1A`), so focus\n   * is visible there. Note the accessibility cost on dark while it stays here:\n   * a keyboard user gets no visible focus indication on a field (WCAG 2.4.7).\n   */\n  focusRing: '#2F2F2F',\n  /** Outline for a field in the error state. */\n  errorBorder: '#EB2D36',\n} as const;\n\n/**\n * Light-theme input chrome — Tokens Option A Light §03.\n *\n * Same roles as `inputColors`, inverted. `background` is the unscoped /\n * primary-host fallback (one step onto `page`). Per-host fills live on the\n * light surface scope as `--ds-field`.\n */\nexport const lightInputColors = {\n  background: '#E9E9E9',\n  border: '#D4D4D4',\n  /** −8 L* on the line only; the fill never moves on hover. */\n  borderHover: '#ADADAD',\n  /** Neutral focus ring — distinct from `border`, so focus is visible in light. */\n  focusRing: '#1A1A1A',\n  /** Severity high, darkened to clear 3:1 against white. */\n  errorBorder: '#C41B23',\n} as const;\n\n/**\n * Light surface ladder — Tokens Option A Light §01.\n *\n * Elevation still means lighter. Four tonal steps fit above `#E9E9E9`; `raised`\n * and `overlay` share white and separate by shadow + border weight instead.\n */\nexport const lightBackgroundColors = {\n  page: '#E9E9E9',\n  primary: '#F1F1F1',\n  widget: '#F8F8F8',\n  surface: '#FCFCFC',\n  raised: '#FFFFFF',\n  overlay: '#FFFFFF',\n  /** Below the ladder — table rules and section edges that must read on white. */\n  tableDivider: '#E2E2E2',\n  borderSubtle: '#E2E2E2',\n  border: '#D4D4D4',\n  cardBorder: '#BDBDBD',\n  tintGreen: '#E8F2EF',\n} as const;\n\n/**\n * Light text ramp — Tokens Option A Light §02.\n *\n * Contrast-checked against `widget` (#F8F8F8). `subtle` holds 4.5:1 on every\n * light rung, so `--ds-text-quiet` does not need to swap tier the way it does\n * in dark.\n */\nexport const lightTextColors = {\n  primary: '#1A1A1A',\n  secondary: '#3D3D3D',\n  tertiary: '#5C5C5C',\n  subtle: '#6E6E6E',\n  muted: '#8A8A8A',\n  disabled: '#ABABAB',\n  link: '#0B5FCC',\n  highlight: '#00786B',\n  /** Ink on the inverted (dark) light-theme tooltip. */\n  tooltip: '#F1F1F1',\n} as const;\n\n/**\n * Brand tint per rung, for selected rows and brand-emphasised panels.\n *\n * A resolved fill, not brand-at-16%-alpha. An alpha tint drifts with whatever\n * it happens to sit on, which on a six-rung ladder means a selected row looks\n * like a different colour in a card than in a dialog. Keyed by host rung so the\n * tint lands the same distance above its background everywhere.\n */\nexport const brandTintByRung = {\n  page: '#152F2C',\n  primary: '#1B3532',\n  widget: '#223C39',\n  surface: '#2A4441',\n  raised: '#2F4946',\n  overlay: '#334A47',\n} as const satisfies Record<SurfaceRung, string>;\n\n/**\n * Background usage guidance.\n *\n * Maps each surface token to the role it plays in the product, so humans (via\n * Storybook) and LLMs (via the published package) can pick the correct\n * background instead of guessing or hardcoding hex. Keyed by `backgroundColors`\n * so the guidance can never drift from the tokens.\n *\n * Source: AiStrike \"Background Colors\" reference.\n */\nexport const backgroundUsage = {\n  page: {\n    hex: backgroundColors.page,\n    label: 'Page (rung 0)',\n    useFor:\n      'The app shell, and bands that should recess below the body such as a table header. No longer pure black, so that a field on the shell has a rung to recess into.',\n    examples: ['App shell background', 'Table header band', 'Area behind primary surfaces'],\n  },\n  primary: {\n    hex: backgroundColors.primary,\n    label: 'Primary (rung 1)',\n    useFor:\n      'Primary content background for a page or section, the recessed fill for a field hosted on a widget, and the unscoped table body / user chat bubble.',\n    examples: ['Page body', 'Main content area', 'Input inside a card', 'User chatbox'],\n  },\n  widget: {\n    hex: backgroundColors.widget,\n    label: 'Widget (rung 2)',\n    useFor:\n      'Widget / card surfaces sitting on the primary background. The rung most body text sits on, and what the text ramp is measured against.',\n    examples: ['Cards', 'Dashboard widgets', 'Panels'],\n  },\n  surface: {\n    hex: backgroundColors.surface,\n    label: 'Surface (rung 3) — Pop-up / Filter / Side Panel / AI chat',\n    useFor:\n      'Elevated overlays and side panels that sit above content. From this rung up, quiet text must use `tertiary` rather than `subtle`.',\n    examples: ['Dialogs and pop-ups', 'Filter panels', 'Side panels', 'AI chat surface'],\n  },\n  raised: {\n    hex: backgroundColors.raised,\n    label: 'Raised (rung 4)',\n    useFor:\n      'Elements floating above an overlay, and portalled elements that cannot inherit a rung from the DOM.',\n    examples: ['Tooltips', 'Snackbars', 'A menu opened from a popover'],\n  },\n  overlay: {\n    hex: backgroundColors.overlay,\n    label: 'Overlay (rung 5, the ceiling)',\n    useFor:\n      'The top of the ladder. Reaching it means three levels of containment; a fourth is clamped here rather than continuing to lighten.',\n    examples: ['A dialog opened from a dialog', 'A menu inside a drawer'],\n  },\n  tableDivider: {\n    hex: backgroundColors.tableDivider,\n    label: 'Table Divider',\n    useFor: 'The rule between table rows. Subtler than `border` so the outline still reads.',\n    examples: ['Row separator'],\n  },\n  darkGreen: {\n    hex: backgroundColors.darkGreen,\n    label: 'Dark Green',\n    useFor: 'Subtle success-tinted surface for positive emphasis.',\n    examples: ['Success-tinted panels', 'Attack-path success emphasis'],\n  },\n} as const;\n\nexport type BackgroundToken = keyof typeof backgroundUsage;\n\n/**\n * Brand / primary accent. One accent, deliberately.\n *\n * There is no `brand.link` here. Link blue is *not* brand — the two are\n * separate on purpose, because a teal link inside teal-accented UI is\n * unfindable. Filing it under `brand` was a category error with a real\n * consequence: `palette.secondary` read it, so every MUI component rendered\n * with `color=\"secondary\"` painted link ink as a background fill. Links read\n * `textColors.link`, which is the only place that colour lives.\n */\nexport const brand = {\n  main: '#00C4AC',\n} as const;\n\n/** Success / Failure / Info / Warning semantic colors. */\nexport const statusColors = {\n  success: '#199F0F',\n  failure: '#EB2D36',\n  warning: '#E99C16',\n  info: '#1266CC',\n  general: '#00C4AC',\n} as const;\n\n/** The ordered severity magnitude scale. `info` and `untriaged` are separate states, not rungs. */\nexport const SEVERITY_ORDER = ['critical', 'high', 'medium', 'low'] as const;\n\nexport type SeverityKey = (typeof SEVERITY_ORDER)[number] | 'info' | 'untriaged';\n\n/**\n * Severity colors used across the security product.\n *\n * Severity is a reserved *status* scale, not a categorical series palette, and\n * it is validated as one. The categorical checks cannot be satisfied at any\n * assignment — critical/high share a hue, as do medium/low — and the one-hue\n * ordinal checks fail too, because red through yellow spans ~90 degrees. Red,\n * amber and yellow are an industry domain convention for severity; recolouring\n * them to satisfy a validator would break recognition for no accessibility gain.\n *\n * What is enforced instead (see `colors.severity.test.ts`): every step clears a\n * contrast floor against its surface, and lightness increases monotonically\n * across the ordered scale with adjacent dL >= 0.06 so it reads as ordered.\n *\n * Movement from the historical values is deliberately minimal:\n * - dark: only `critical` moves, 2.74:1 -> 3.04:1.\n * - light: only `medium`, `low` and `untriaged` move, to clear 2:1 on white\n *   while preserving the ordering gaps.\n *\n * For series identity use `chartTokens[mode].series` instead — never these.\n */\nexport const severityColorsByMode = {\n  dark: {\n    critical: '#c80009',\n    high: '#EB2D36',\n    medium: '#E99C16',\n    low: '#D0C800',\n    info: '#1266CC',\n    /** Not-yet-triaged / unknown severity. */\n    untriaged: '#C0C0C0',\n  },\n  light: {\n    critical: '#BB010B',\n    high: '#EB2D36',\n    medium: '#db9000',\n    low: '#c2bb01',\n    info: '#1266CC',\n    /** Not-yet-triaged / unknown severity. */\n    untriaged: '#b7b7b7',\n  },\n} as const satisfies Record<'dark' | 'light', Record<SeverityKey, string>>;\n\n/** Dark-mode severity colors. Retained flat for existing consumers. */\nexport const severityColors = severityColorsByMode.dark;\n\n/**\n * Severity as *text* or as an icon glyph, rather than as a fill.\n *\n * The fills above are tuned to carry white or dark ink on top of them. Used as\n * ink themselves they are far too dark — `critical` on `widget` is 2.49:1. These\n * are the same hues lightened until each clears 4.5:1 on `overlay`, the highest\n * rung, so one value works on every rung rather than needing a per-rung table.\n *\n * These deliberately do **not** preserve the lightness ordering that the fills\n * do: forcing two saturated reds to the same contrast ratio necessarily puts\n * them at the same lightness, so `critical` and `high` land 0.002 apart. That is\n * acceptable here and only here, because this token is used where a word\n * (\"Critical\") or a distinct glyph carries the rank. Never use these as\n * unlabelled indicator fills — see `severityIndicatorCeiling`.\n */\nexport const severityTextColors = {\n  critical: '#E68A8E',\n  high: '#F38287',\n  medium: '#E99C16',\n  low: '#D0C800',\n  info: '#76A6E1',\n  untriaged: '#C0C0C0',\n} as const satisfies Record<SeverityKey, string>;\n\n/**\n * The highest rung at which each severity *fill* may be used as an unlabelled\n * indicator — a bare dot, a bar, a chart segment with no text.\n *\n * Two different accessibility rules apply to a severity colour depending on\n * whether it is labelled, and conflating them is what made the ladder look like\n * it broke the palette:\n *\n * - A **labelled** chip is governed by WCAG 1.4.3: the label against the fill.\n *   Every severity clears that, so a labelled chip works on every rung.\n * - An **unlabelled** indicator is governed by WCAG 1.4.11: the fill against its\n *   background, at 3:1. Contrast falls as the ladder lightens, so this one has a\n *   ceiling.\n *\n * `null` means there is no rung where the fill clears 3:1, so the indicator must\n * carry a label or a shape difference. `critical` cannot be fixed by lightening:\n * the amount needed closes its lightness gap to `high` below the 0.06 the\n * ordering test requires, and recolouring the scale to satisfy a validator would\n * break the domain recognition the palette exists for. The correct fix for an\n * unlabelled critical dot is to label it.\n *\n * Pinned in `colors.severity.test.ts`, which recomputes this from the tokens —\n * so if a fill moves, the test fails until this table is updated.\n */\nexport const severityIndicatorCeiling = {\n  critical: null,\n  high: 'surface',\n  medium: 'overlay',\n  low: 'overlay',\n  info: 'page',\n  untriaged: 'overlay',\n} as const satisfies Record<SeverityKey, SurfaceRung | null>;\n\n/**\n * Three whole scales were removed here, not just individual entries. Each one\n * was a parallel palette for a job another scale already owned, and every one of\n * them had drifted:\n *\n * - **`priorityColors`** — a six-key sibling of severity, for \"triage/priority\n *   badges where the emphasis ramp differs slightly\". Three of its values\n *   existed nowhere else (`high #F0352A`, `medium #FE8C00`, and `info #32DEB5`,\n *   a teal-green that is neither the brand nor the info hue). Nothing consumed\n *   it. Priority renders as severity; there is one ordered scale, validated as\n *   one, in `severityColorsByMode`.\n * - **`chartColors`** — already deprecated in place, with its own docstring\n *   saying it \"must not be used to colour multiple series\" because its entries\n *   are severity synonyms. A scale that cannot be used for the thing it is named\n *   after is not a scale. Series identity is `chartTokens[mode].series`.\n * - **`inventoryColors`** — seven categorical hues with no consumers and no\n *   contrast validation, overlapping the chart palette's job. Its one value that\n *   does appear on screen, `#3D7FFF`, is declared independently in\n *   `attackPath.ts` for the resource node, so nothing changes visually.\n *\n * Icon colors.\n *\n * These are *derived* rather than restated. Every entry below used to be its own\n * hex, which meant eleven of the fourteen were a second copy of a value owned by\n * `statusColors`, `brand` or `neutral` — free to drift from the original with\n * nothing to catch it. The keys are unchanged, because `Icon`'s `tone` prop is\n * `keyof typeof iconColors` and that is public API.\n *\n * Note that per the spec an icon should normally take the *text* tier it sits in\n * rather than a colour from here, and reach for a tone only when the icon itself\n * carries status. `alert` and `vulnerability` are the two genuinely independent\n * values left; both are domain hues with no owner elsewhere.\n */\nexport const iconColors = {\n  success: statusColors.success,\n  failure: statusColors.failure,\n  warning: statusColors.warning,\n  info: statusColors.info,\n  general: brand.main,\n  tabIcon: '#888888',\n  actionActive: '#FFFFFF',\n  inactiveToggle: '#D3D3D3',\n  activeTabIcon: brand.main,\n  alert: '#EF073A',\n  vulnerability: '#EA5515',\n  attackPathDefault: '#FFFFFF',\n  attackPathSuccess: statusColors.success,\n  attackPathFailure: statusColors.failure,\n} as const;\n\n/**\n * Neutral grey scale, used to generate MUI palette steps and hover/active\n * overlays.\n *\n * Deliberately frozen at its historical values and **not** aligned to the\n * surface ladder. Several entries are the ladder's own former values — `900`\n * was `widget`, `800` was `primary`, `700` was `surface` — so reading a surface\n * colour out of here now gets a rung that no longer exists. Remapping it was\n * considered and rejected: these feed MUI's internal grey steps, where a shift\n * shows up in places the ladder has no opinion about.\n *\n * For any surface, use `backgroundColors` / the ladder. For a step in a\n * generated scale, this is still the right source.\n *\n * Every entry is a true grey (R = G = B). `600` was `#2B2B33`, which is not —\n * it carries an 8-point blue lift, reading as blue-violet at hue 240. That\n * mattered because MUI resolves a dark `Avatar`'s default background to\n * `grey[600]`, so every initials avatar in the system was tinted blue by a\n * value in a scale named \"neutral\". It is now `#2B2B2B`: the same step, with\n * the hue removed. Pinned by `colors.neutral.test.ts`.\n */\nexport const neutral = {\n  0: '#000000',\n  900: '#141414',\n  850: '#171717',\n  800: '#191919',\n  700: '#242424',\n  600: '#2B2B2B',\n  500: '#363636',\n  400: '#5E5E5E',\n  300: '#888888',\n  200: '#AEAEAE',\n  100: '#D3D3D3',\n  50: '#FDFDFD',\n  white: '#FFFFFF',\n} as const;\n\nexport const colors = {\n  text: textColors,\n  background: backgroundColors,\n  backgroundUsage,\n  input: inputColors,\n  lightText: lightTextColors,\n  lightBackground: lightBackgroundColors,\n  lightInput: lightInputColors,\n  status: statusColors,\n  severity: severityColors,\n  severityText: severityTextColors,\n  icon: iconColors,\n  neutral,\n  brand,\n  brandTintByRung,\n  scrim,\n  stateAlpha,\n} as const;\n\nexport type Colors = typeof colors;\nexport type SeverityLevel = keyof typeof severityColors;\nexport type StatusLevel = keyof typeof statusColors;\n"],"mappings":"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"}